二叉树相关操作(遍历、路径、最近公共父节点、重构)

来源:互联网 发布:大学专科本科网络教育 编辑:程序博客网 时间:2024/06/04 19:32

本文总结了二叉树的相关操作,并在最后附上所有操作的实现。还有不足之处,以后会及时更新~

 

相关操作包括:

1、插入:InsertBTree

2、遍历

1)前序遍历(递归):PreOrderTraverse

2)前序遍历(非递归):PreOrderTraverseNoRec

3)中序遍历(递归):InOrderTraverse

4)中序遍历(非递归):InOrderTraverseNoRec

5)后序遍历(递归):PostOrderTraverse

6)后序遍历(非递归):PostOrderTraverseNoRec

7)层序遍历:LevelOrderTraverse

3、寻找从根节点到某一节点的路径:FindNodePath

4、寻找两个节点的最近公共父节点:FindNearestParent

5、重构二叉树

1)根据前序和中序遍历结果重构:RebuildFromPreAndInOrder

2)根据后序和中序遍历结果重构:RebuildFromPostAndInOrder

 

程序如下:

 

#include <iostream>#include <stack>#include <queue>#include <vector>using namespace std;// 将节点保存的数据类型设为整型typedef int ElemType;struct BTreeNode{ElemType elem;// 当前节点元素BTreeNode *left;// 左孩子结点BTreeNode *right;// 右孩子节点};// 往二叉树中插入节点,该方法实际上最后生成的是二叉查找树void InsertBTree(BTreeNode **root, ElemType elem){// 如果树为空,则创建if (*root == NULL){*root = new BTreeNode;(*root)->elem  = elem;(*root)->left  = NULL;(*root)->right = NULL;return ;}BTreeNode *node = *root;while (node != NULL){if (elem < node->elem){if (node->left == NULL){BTreeNode *temp = new BTreeNode;temp->elem  = elem;temp->left  = NULL;temp->right = NULL;node->left  = temp;return ;} else{node = node->left;}} else{if (node->right == NULL){BTreeNode *temp = new BTreeNode;temp->elem  = elem;temp->left  = NULL;temp->right = NULL;node->right = temp;return ;} else{node = node->right;}}}}// 前序遍历(递归方式)void PreOrderTraverse(BTreeNode *root){if (root != NULL){cout<<root->elem<<" ";// 输出该节点值PreOrderTraverse(root->left);// 递归遍历左子树PreOrderTraverse(root->right);// 递归遍历右子树}}// 前序遍历(非递归方式)void PreOrderTraverseNoRec(BTreeNode *root){stack<BTreeNode *> s;while (root!=NULL || !s.empty()){if (root != NULL){cout<<root->elem<<" ";s.push(root);root = root->left;} else{root = s.top()->right;s.pop();}}}// 中序遍历(递归方式)void InOrderTraverse(BTreeNode *root){if (root != NULL){InOrderTraverse(root->left);// 递归遍历左子树cout<<root->elem<<" ";// 输出该节点值InOrderTraverse(root->right);// 递归遍历右子树}}// 中序遍历(非递归方式)void InOrderTraverseNoRec(BTreeNode *root){stack<BTreeNode *> s;while (root!=NULL || !s.empty()){if (root != NULL){s.push(root);root = root->left;} else{cout<<s.top()->elem<<" ";// 打印出当前节点值root = s.top()->right;// 将root指向当前节点的右孩子节点s.pop();// 弹出当前节点}}}// 后序遍历(递归方式)void PostOrderTraverse(BTreeNode *root){if (root != NULL){PostOrderTraverse(root->left);// 递归遍历左子树PostOrderTraverse(root->right);// 递归遍历右子树cout<<root->elem<<" ";// 输出该节点值}}// 后序遍历(非递归方式)void PostOrderTraverseNoRec(BTreeNode *root){vector<BTreeNode *> v;v.push_back(root);vector<BTreeNode *>::iterator iter = v.end()-1;// 此时iter指向根节点do {if (root != NULL){if (root->left != NULL){iter = v.insert(iter, root->left) + 1;}if (root->right != NULL){iter = v.insert(iter, root->right) + 1;}}iter--;root = *iter;} while (iter != v.begin()-1);// 输出后序遍历结果for (iter=v.begin(); iter!=v.end(); iter++){cout<<(*iter)->elem<<" ";}}// 分层遍历void LevelOrderTraverse(BTreeNode *root){queue<BTreeNode *> q;while (root != NULL){// 输出当前节点,并把当前节点的左右子节点放入队列中cout<<root->elem<<" ";if (root->left != NULL){q.push(root->left);} if (root->right != NULL){q.push(root->right);}if (!q.empty()){root = q.front();q.pop();} else{break;}}}// 根据前序遍历结果和中序遍历结果重构二叉树void RebuildFromPreAndInOrder(BTreeNode **root, ElemType preOrder[], ElemType inOrder[], int size){if (size <= 0){return ;}// 为新节点申请内存空间*root = new BTreeNode;(*root)->elem  = preOrder[0];(*root)->left  = NULL;(*root)->right = NULL;for (int num=0; num<size; num++){if (inOrder[num] == preOrder[0]){break;}}RebuildFromPreAndInOrder(&((*root)->left), preOrder+1, inOrder, num);RebuildFromPreAndInOrder(&((*root)->right), preOrder+num+1, inOrder+num+1, size-num-1);}// 根据后序遍历结果和中序遍历结果重构二叉树void RebuildFromPostAndInOrder(BTreeNode **root, ElemType postOrder[], ElemType inOrder[], int size){if (size <=0 ){return ;}// 为新节点申请内存空间*root = new BTreeNode;(*root)->elem  = postOrder[size-1];(*root)->left  = NULL;(*root)->right = NULL;for (int num=0; num<size; num++){if (inOrder[num] == postOrder[size-1]){break;}}RebuildFromPostAndInOrder(&((*root)->left), postOrder, inOrder, num);RebuildFromPostAndInOrder(&((*root)->right), postOrder+num, inOrder+num+1, size-num-1);}// 找出从根节点到某一节点的路径,保存到 vector<BTreeNode *> path 中bool FindNodePath(BTreeNode *root, ElemType elem, vector<BTreeNode *> &path){// 在这个函数中用 vector 实现 stack 的功能if (root != NULL){path.push_back(root);if (root->elem == elem){// 找到该节点path.assign(path.begin(), path.end());return true;} else{if (FindNodePath(root->left, elem, path) == true){return true;}if (FindNodePath(root->right, elem, path) == true){return true;}path.pop_back();}} return false;}void FindNearestParent(BTreeNode *root, ElemType elem1, ElemType elem2){// 保存自根节点到elem1和elem2所在节点的路径vector<BTreeNode *> path1, path2;FindNodePath(root, elem1, path1);FindNodePath(root, elem2, path2);// 从两个路径中找出最后一个相同的节点,该节点即最近公共父节点vector<BTreeNode *>::iterator iter1 = path1.begin();vector<BTreeNode *>::iterator iter2 = path2.begin();while ((*iter1)->elem == (*iter2)->elem){iter1++;iter2++;}cout<<"节点"<<elem1<<"和"<<elem2<<"的最近公共父节点是:"<<(*(iter1-1))->elem<<endl;}// 测试上述函数void main(){// 定义树的根节点BTreeNode *root = NULL;// 初始化树int tree[] = {36, 25, 57, 11, 30, 27};for (int i=0; i<sizeof(tree)/sizeof(int); i++){InsertBTree(&root, tree[i]);}/************************************************************************//* 遍历二叉树                                                           *//************************************************************************/cout<<"前序遍历(递归):\t";PreOrderTraverse(root);cout<<endl;cout<<"前序遍历(非递归):\t";PreOrderTraverseNoRec(root);cout<<endl;cout<<"中序遍历(递归):\t";InOrderTraverse(root);cout<<endl;cout<<"中序遍历(非递归):\t";InOrderTraverseNoRec(root);cout<<endl;cout<<"后序遍历(递归):\t";PostOrderTraverse(root);cout<<endl;cout<<"后序遍历(非递归):\t";PostOrderTraverseNoRec(root);cout<<endl;cout<<"层序遍历:\t";LevelOrderTraverse(root);cout<<endl;/************************************************************************//* 重构二叉树                                                           *//************************************************************************/BTreeNode *root1 = NULL;BTreeNode *root2 = NULL;ElemType preOrder[]  = {36, 25, 11, 30, 27, 57};ElemType inOrder[]   = {11, 25, 27, 30, 36, 57};ElemType postOrder[] = {11, 27, 30, 25, 57, 36};RebuildFromPreAndInOrder(&root1, preOrder, inOrder, 6);RebuildFromPostAndInOrder(&root2, postOrder, inOrder, 6);// 前序遍历,已验证重建的正确性cout<<"根据前序和中序便利结果,重构后的二叉树前序遍历结果是:";PreOrderTraverse(root1);cout<<endl;cout<<"根据后序和中序便利结果,重构后的二叉树前序遍历结果是:";PreOrderTraverse(root2);cout<<endl;/************************************************************************//* 查找某一元素是否在二叉树中,如果在打印自根节点到该节点的路径         *//************************************************************************/ElemType elem = 27;// 假设要查找的元素是27vector<BTreeNode *> path;// 保存该元素所在节点的路径if (FindNodePath(root, elem, path) == true){cout<<"元素 "<<elem<<" 所在节点的路径是:";for (vector<BTreeNode *>::iterator iter=path.begin(); iter!=path.end(); iter++){cout<<(*iter)->elem<<" ";}cout<<endl;}else{cout<<"元素 "<<elem<<" 不在该二叉树中"<<endl;}/************************************************************************//* 查找某两个节点的最近公共父节点                                       *//************************************************************************/ElemType elem1 = 57, elem2 = 27;FindNearestParent(root, elem1, elem2);}


实际使用的二叉树如下:

执行结果如下:

 

原创粉丝点击