二叉树遍历和构造
二叉树的遍历
二叉树遍历其实很简单,三种遍历都是一样的,只不过顺序先后不一样罢了。
先序遍历
访问根结点,先序遍历左子树,先序遍历右子树
void PreOrder(BitTree T){ if( T != nullptr){ visit(T); PreOrder(T->lchild); PreOrder(T->rchild); } }
|
中序遍历
中序遍历左子树,访问根结点,中序遍历右子树
void InOrder(BitTree T){ if(T != nullptr){ InOrder(T->lchild); visit(T); InOrder(T->rchild); } }
|
后序遍历
后序遍历左子树,后序遍历右子树,访问根结点
void PostOrder(BitTree T){ if( T != nullptr ){ PostOrder(T->lchild); PostOrder(T->rchild); visit(T); } }
|
时间复杂度都为O(n),在递归遍历中,递归工作栈的栈深恰好为树的深度,在最坏情况下,二叉树是有n个结点且深度为 n 的单支树,遍历算法的空间复杂度为O(n)。
利用非递归方式遍历二叉树
借助栈,可以将二叉树的递归遍历转换为非递归算法。以中序遍历为例,给出中序遍历非递归算法。先扫描(并非访问)根结点的所有左结点并将它们一一进栈,然后出栈一个结点*p,访问它。然后继续扫描该结点的右孩子结点,将其进栈,在扫描该孩子结点的所有左结点并一一进栈,如此继续,直到栈空。
中序遍历的非递归算法如下:
void InOrderWithoutRecursion(BitTree T){ Stack<BitTree> S; BitTree p = T; while( p || !IsEmpty(S) ){ if( p ){ S.push(p); p = p->lchild; }else{ S.pop(p); visit(p); p = p->rchild; } } }
|
前序遍历的非递归算法:
void PreOrderWithoutRecursion(BitTree T) { if (T == nullptr) return; BTNode* p = T; stack<BitNode*> s; while (!s.empty() || p) { if (p) { visit(p); s.push(p); p = p->lchild; } else { p = s.top(); s.pop(); p = p->rchild; } } cout << endl; }
|
后序遍历的非递归算法:后序遍历的难点在于:需要判断上次访问的节点是位于左子树,还是右子树。若是位于左子树,则需跳过根节点,先进入右子树,再回头访问根节点;若是位于右子树,则直接访问根节点。直接看代码,代码中有详细的注释。
void PostOrderWithoutRecursion(BTNode* root) { if (root == NULL) return; stack<BTNode*> s; BTNode* pCur, *pLastVisit; pCur = root; pLastVisit = NULL; while (pCur) { s.push(pCur); pCur = pCur->lchild; } while (!s.empty()) { pCur = s.top(); s.pop(); if (pCur->rchild == NULL || pCur->rchild == pLastVisit) { cout << setw(4) << pCur->data; pLastVisit = pCur; }
else { s.push(pCur); pCur = pCur->rchild; while (pCur) { s.push(pCur); pCur = pCur->lchild; } } } cout << endl; }
|
层次遍历
层次遍历需要借助队列。先将二叉树根结点入队,然后初岁,访问该结点,若它有左子树,则将左子树根节点入队;若它有右子树,则将右子树根结点入队。然后出队,对出队结点访问,如此反复,直到队列为空。

void LevelOrder(BitTree T){ if( T == nullptr){ return ; } Queue<BitNode*> q; q.push(T); while(!q.empty()){ int sz = q.size(); for(int i = 0; i < sz; i++){ BitNode* cur = Q.front(); q.pop(); if(p->lchild != nullptr){ q.push(p->lchild); } if(p->rchild != nullptr){ q.push(p->rchild); } } } }
|
由遍历序列构造二叉树
由二叉树的先序和中序序列可以唯一确定一棵二叉树,同样后序和中序序列也可以唯一确定一棵二叉树,但先序和后序不能确定一棵二叉树。
先序和中序序列构造一棵二叉树
思路:我们知道先序序列的第一个值其实就是根节点的值,这样我们就可以在中序序列中找到对应的根节点,那么根节点左边的数就全为左子树的结点,根节点右边的数就全为右子树的结点。根据这个想法,再递归的进行构造,见代码。
class Solution { private: unordered_map<int, int> index; public: TreeNode* myBuildTree(const vector<int>& preorder, const vector<int>& inorder, int preorder_left, int preorder_right, int inorder_left, int inorder_right) { if (preorder_left > preorder_right) { return nullptr; } int preorder_root = preorder_left; int inorder_root = index[preorder[preorder_root]]; TreeNode* root = new TreeNode(preorder[preorder_root]); int size_left_subtree = inorder_root - inorder_left; root->left = myBuildTree(preorder, inorder, preorder_left + 1, preorder_left + size_left_subtree, inorder_left, inorder_root - 1); root->right = myBuildTree(preorder, inorder, preorder_left + size_left_subtree + 1, preorder_right, inorder_root + 1, inorder_right); return root; }
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) { int n = preorder.size(); for (int i = 0; i < n; ++i) { index[inorder[i]] = i; } return myBuildTree(preorder, inorder, 0, n - 1, 0, n - 1); } };
|
后序和中序序列构造一棵二叉树
思路:我们知道后序序列的最后一个值其实就是根节点的值,这样我们就可以在中序序列中找到对应的根节点,那么根节点左边的数就全为左子树的结点,根节点右边的数就全为右子树的结点。根据这个想法,再递归的进行构造,见代码。
class Solution { private: unordered_map<int,int> index; public: TreeNode* myBuildTree(vector<int>& postorder,vector<int>& inorder,int postorder_left,int postorder_right,int inorder_left,int inorder_right){ if(postorder_left > postorder_right){ return nullptr; } int postorder_root = postorder_right; int inorder_root = index[postorder[postorder_root]]; TreeNode* root=new TreeNode(postorder[postorder_root]); int size_left_subtree=inorder_root-inorder_left; root->left=myBuildTree(postorder,inorder,postorder_left,postorder_left+size_left_subtree-1,inorder_left,inorder_root-1); root->right=myBuildTree(postorder,inorder,postorder_left+size_left_subtree,postorder_root-1,inorder_root+1,inorder_right); return root; } TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder){ int n=postorder.size(); for(int i=0;i<n;i++){ index[inorder[i]]=i; } return myBuildTree(postorder,inorder,0,n-1,0,n-1); } };
|