二叉樹各種遍歷操作
阿新 • • 發佈:2019-02-01
目錄
本文總結關於二叉樹的各種遍歷演算法
首先定義二叉樹節點結構體
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
1 求二叉樹深度
1.1 遞迴實現
- 如果一棵樹只有一個結點,那麼它的深度為1;
- 如果根結點只有左子樹沒有右子樹,那麼樹的深度是左子樹的深度加1,加1是加上根節點這一層
- 如果既有左子樹又有右子樹,那麼樹的深度應該是左、右子樹中深度較大的值再加1
int TreeDepth(TreeNode* pRoot)
{
if(pRoot==NULL)
return 0;
int nleft = TreeDepth(pRoot->left);
int nright = TreeDepth(pRoot->right);
return (nleft>nright)?(nleft+1):(nright+1);
}
1.2 非遞迴實現(佇列)
- 每遍歷一層,depth++;
- 每一層,需使用一個變數
len
記錄該層的結點個數,也就是佇列的當前長度,然後依次在佇列中訪問該層的len
個結點(將佇列中len
個元素出佇列),並將下一層入佇列。
int TreeDepth(TreeNode* pRoot) { queue<TreeNode*> q; if(!pRoot) return 0; q.push(pRoot); int level=0; while(!q.empty()){ int len=q.size(); level++; while(len--){ TreeNode* tem=q.front(); q.pop(); if(tem->left) q.push(tem->left); if(tem->right) q.push(tem->right); } } return level; }
1.3 非遞迴實現(棧)
#include <iostream>
#include <stack>
using namespace std;
typedef struct BinTree
{
int data;
BinTree *lc;
BinTree *rc;
}BTNode,*BinTree;
int max(int a,int b)
{
return (a>b)?a:b;
}
int BinTreeDepth(BinTree T)
{
stack<BinTree> s;
BinTree p = T,r = NULL;
int depth=0;
while(p||!s.empty())
{
if(p)
{ //從根節點向左邊走
s.push(p);
int size = s.size();//獲取棧的大小
depth = max(depth,size);//替換最大值
p = p->lc;
}
else
{ //左邊走不通向右走
p = s.top();
if(p->rc&&p->rc!=r)//如果右子樹存在,且未被訪問過
{
p = p->rc;
s.push(p);
int size = s.size();//獲取棧的大小
depth = max(depth,size);//替換最大值
p = p->lc;
}else
{
p=s.top();
s.pop();
cout<<p->data<<endl;
r=p; //記錄最近訪問的節點
p=NULL; //節點訪問完之後,重置p指標,目的是為了防止再次將左孩子壓棧
}
}
}
return depth;
}
2 求二叉樹高度
跟求深度一樣,唯一的區別就是,對於根節點,深度為1,高度為0.
int Height(TreeNode *node)
{
if(node == NULL)
return -1;
else
return 1 + Max(Height(node->left),Height(node->right));
}
3 二叉樹先序遍歷
3.1 遞迴版本
void preOrderTraverse(TreeNode *root) {
if (root != NULL) {
cout<<root->val<<endl;
preOrderTraverse(root->left);
preOrderTraverse(root->right);
}
}
3.2 非遞迴版本
void PreOrder(TreeNode* pRoot)//前序遍歷,非遞迴
{
if (pRoot == NULL)
return;
stack<BiNode*> s;
TreeNode *p = pRoot;
while (p != NULL || !s.empty())
{
if (p != NULL)
{
cout << p->val << " ";
s.push_back(p);
p = p->left;
}
else
{
p = s.pop();
p = p->right;
}
}
cout << endl;
}
3.3 利用先序建立二叉樹
//前序建立一顆二叉樹
void CreateBiTree(BiTree &T)
{
char c;
cin >> c;
if ('#' == c)
T=NULL;
else
{
T = (BiNode* ) malloc(sizeof(BiNode));
T->val = c;
CreateBiTree(T->left);
CreateBiTree(T->right);
}
}
4 二叉樹中序遍歷
4.1 遞迴版本
void inOrderTraverse(TreeNode* root) {
if (root != NULL) {
inOrderTraverse(root->left);
cout<<root->val<<" ";
inOrderTraverse(root->right);
}
}
4.2 非遞迴版本
void inOrderTraverse(TreeNode* root) {
stack<TreeNode*> s;
TreeNode* pNode = root;
while (pNode != null || !stack.isEmpty()) {
if (pNode != null) {
s.push(pNode);
pNode = pNode->left;
} else { //pNode == null && !stack.isEmpty()
TreeNode node = s.pop();
cout<<node->val<<" ";
pNode = node->right;
}
}
}
5 二叉樹後序遍歷
5.1 遞迴版本
public void postOrderTraverse(TreeNode root) {
if (root != null) {
postOrderTraverse(root.left);
postOrderTraverse(root.right);
System.out.print(root.val+" ");
}
}
5.2 非遞迴版本
void PostOrder(BiTree &T)//後序遍歷(雙棧法),非遞迴
{
if (T == NULL)
return;
vector<BiNode*> S1,S2;
BiNode *p ;//當前指標所在結點
S1.push_back(T);
while (!S1.empty())
{
p = S1[S1.size() - 1];
S1.pop_back();
S2.push_back(p);
if (p->left)
S1.push_back(p->left);
if (p->right)
S1.push_back(p->right);
}
while (!S2.empty())
{
cout << S2[S2.size() - 1]->val << " ";
S2.pop_back();
}
cout << endl;
}
6 二叉樹層序遍歷
void levelTraverse(TreeNode* root) {
if (root == NULL) {
return;
}
queue<TreeNode*> q;
queue.push_back(root);
while (!q.empty()) {
TreeNode* node = q.pop_front();
cout<<node->val<<" ";
if (node->left != NULL) {
q.push_back(node->left);
}
if (node->right != NULL) {
q.push_back(node->right);
}
}
}
7 二叉樹深度優先遍歷
深度優先遍歷就是先序遍歷。
//深度優先遍歷
void depthFirstSearch(Tree root){
stack<Node *> nodeStack;
nodeStack.push(root);
Node *node;
while(!nodeStack.empty()){
node = nodeStack.top();
cout<<node->data;//遍歷根結點
nodeStack.pop();
if(node->rchild){
nodeStack.push(node->rchild); //先將右子樹壓棧
}
if(node->lchild){
nodeStack.push(node->lchild); //再將左子樹壓棧
}
}
}
8 二叉樹廣度優先遍歷
廣度優先其實就是層序遍歷,利用佇列很容易實現。
//廣度優先遍歷
void breadthFirstSearch(Tree root){
queue<Node *> nodeQueue; //使用C++的STL標準模板庫
nodeQueue.push(root);
Node *node;
while(!nodeQueue.empty()){
node = nodeQueue.front();
nodeQueue.pop();
cout<<node->data;//遍歷根結點
if(node->lchild){
nodeQueue.push(node->lchild); //先將左子樹入隊
}
if(node->rchild){
nodeQueue.push(node->rchild); //再將右子樹入隊
}
}
}
9 求二叉樹節點間最大距離
int GetMaxDistance(BiTree &T)//計算二叉樹結點的最大距離,遞迴法
{
if (T == NULL)
return 0;
int Distance = TreeDepth(T->left) + TreeDepth(T->right);
int l_Distance = GetMaxDistance(T->left);
int r_Distance = GetMaxDistance(T->right);
Distance = (Distance > r_Distance) ? Distance : r_Distance;
Distance = (Distance > l_Distance) ? Distance : l_Distance;
return Distance;
}
10 計算二叉樹葉子節點數目
int CountLeafNode(BiTree &T)//計算二叉樹的葉子節點數目,遞迴法
{
if (T == NULL)
return 0;
if (T->left == NULL&&T->right == NULL)
return 1;
return CountLeafNode(T->left)+CountLeafNode(T->right);
}
11 獲取二叉樹中根節點到指定節點的路徑
//獲取二叉樹中從根節點到指定節點的路徑
void GetNodePath(BiNode* T, BiNode* Node, vector<BiNode*>& Path,int &found)
{
if (T == NULL)
return;
Path.push_back(T);
if (T == Node)
found = 1;
if (!found)
{
GetNodePath(T->left, Node, Path, found);
}
if (!found)
{
GetNodePath(T->right, Node, Path, found);
}
if (!found)
Path.pop_back();
else
return;
}
12 獲取兩條路徑的最後一個共同節點
//獲取兩條路徑的最後一個共同節點
BiNode* GetLastCommonNode(const vector<BiNode*> Path1, const vector<BiNode*> Path2)
{
vector<BiNode*>::const_iterator iter1 = Path1.begin();
vector<BiNode*>::const_iterator iter2 = Path2.begin();
BiNode *p = NULL;
while ( iter1 != Path1.end() && iter2 != Path2.end() && *iter1 != *iter2 )
{
if (*iter1 == *iter2)
p = *iter1;
iter1++;
iter2++;
}
return p;
}
13 獲取兩個結點的最近共同祖先
//獲取兩個結點的最近共同祖先
BiNode* GetLastCommonParent(BiNode* T, BiNode* Node1, BiNode* Node2)
{
if (T == NULL || Node1 == NULL || Node2 == NULL)
return NULL;
vector<BiNode*> Path1, Path2;
int found1 = 0;
int found2 = 0;
GetNodePath(T, Node1, Path1,found1);
GetNodePath(T, Node2, Path2, found2);
return GetLastCommonNode(Path1,Path2);
}