数据结构与算法(c++)——查找二叉树与中序遍历
查找树ADT——查找二叉树
定义:对于树中的每个节点X,它的左子树中的所有项的值小于X中的项,而它的右子树中所有项的值大于X中的项。
现在给出字段和方法定义(BinarySearchTree.h)
#include <queue> class BinarySearchTree { private: struct Node { int value; Node* left; Node* right; }; Node* root; void insert(Node*, int); void traversal(Node*, std::queue<int>&); bool checkNode(Node*, int); int findRoot(Node*, int, int); public: BinarySearchTree() : root(nullptr) {}; void insert(int); std::queue<int> traversal(); int findRoot(int, int); // 查找两个节点的公共父节点 std::queue<int> morrisTraversal(); // (Morris方法)不使用递归和栈遍历二叉树 };
查找二叉树的遍历可以采用遍历和非遍历两种算法。
一、添加元素(insert)
现在假设要添加这样一组整数10,7,2,6,13,11,17,3。按照顺序形成的查找二叉树应该如下图:
算法实现:
void BinarySearchTree::insert(int val) { Node* node = new Node(); node->value = val; node->left = nullptr; node->right = nullptr; if (root == nullptr) { root = node; } else { insert(root, val); } } void BinarySearchTree::insert(Node* node, int val) { if (val < node->value) { if (node->left != nullptr) { insert(node->left, val); } else { Node* chdNode = new Node(); chdNode->value = val; chdNode->left = nullptr; chdNode->right = nullptr; node->left = chdNode; } } else { if (node->right != nullptr) { insert(node->right, val); } else { Node* chdNode = new Node(); chdNode->value = val; chdNode->left = nullptr; chdNode->right = nullptr; node->right = chdNode; } } }
二、遍历元素(递归)
查找二叉树的遍历需要采用中序法。即对于树中的每个节点来说首先处理左子树然后处理根节点再处理右子树。
算法实现:
std::queue<int> BinarySearchTree::traversal() { std::queue<int> q; if (root != nullptr) { traversal(root, q); } return q; } void BinarySearchTree::traversal(Node* node, std::queue<int>& q) { if (node->left != nullptr) { traversal(node->left, q); } q.push(node->value); if (node->right != nullptr) { traversal(node->right, q); } }
三、查找树中任意两个节点的最小父节点
查找最小父节点的逻辑是对于给出的任意两个节点分别处于根节点的左侧与右侧。若两个节点均处于根节点左侧则向左子树递归遍历,反之,则向右子树递归遍历。如11和17,它们的最小父节点是13。一种例外情况是要求查找的两个节点其中一个是另一个的父节点。如2和3,它们的最小父节点是2。
算法实现:
int BinarySearchTree::findRoot(int a, int b) { if (checkNode(root, a) && checkNode(root, b)) { return findRoot(root, a, b); } } int BinarySearchTree::findRoot(Node* node, int a, int b) { if (a<node->value && b>node->value) { return node->value; } else if (a < node->value && b < node->value) { return findRoot(node->left, a, b); } else if (a > node->value && b > node->value) { return findRoot(node->right, a, b); } else { return a == node->value ? a : b; } }
四、遍历元素(不使用递归和栈)
分析:查找二叉树的遍历必须采用中序法,由于不能使用递归和栈。就需要使用特殊算法,能够在处理完X节点的右子树后向上检索到Y节点。如图:
Morris算法的特点就是在处理X节点前,首先找到其最右侧的子树b(b->right == nullptr)。然后建立与Y节点的连接(b->right = Y)。处理完成后再删除临时连接恢复二叉树的原装(b->right = nullptr)
算法实现:
std::queue<int> BinarySearchTree::morrisTraversal() { std::queue<int> q; if (root == nullptr) { return q; } Node* cur = root; Node* prev = nullptr; while (cur != nullptr) { if (cur->left == nullptr) { q.push(cur->value); cur = cur->right; } else { prev = cur->left; while (prev->right != nullptr && prev->right != cur) { prev = prev->right; } if (prev->right == nullptr) { prev->right = cur; cur = cur->left; } else { prev->right = nullptr; q.push(cur->value); cur = cur->right; } } } return q; }