樹常用的遍歷方式有四種,分別爲前序遍歷,中序遍歷,後序遍歷和層次遍歷,下面的代碼依次實現了它們的遞歸以及非遞歸方法。
// tree.cpp : 此文件包含 "main" 函數。程序執行將在此處開始並結束。
//
#include "pch.h"
#include <iostream>
#include<stack>
#include<queue>
using namespace std;
typedef struct Node
{
char data;
struct Node *lchild, *rchild;
}Node;
//通過先序的方式創建樹,#表示空節點
/*
A
B C
D E F #
# # # # # #
創建上面的樹應輸入應爲 ABD##E##CF###
前序遍歷:ABDECF
中序遍歷:DBEAFC
後序遍歷:DEBFCA
層次遍歷:ABCDEF
*/
void creatTree(Node* &root)
{
char data;
cin >> data;
if (data == '#')
root = NULL;
else
{
root = new Node;
root->data = data;
creatTree(root->lchild);
creatTree(root->rchild);
}
}
//打印一個節點的數據
void visit(Node* node)
{
if(node!=NULL)
cout << node->data;
}
//遞歸-前序遍歷,先訪問跟節點,然後訪問左節點,最後訪問右節點,每一個節點都要準守這樣的規則
void preTraversal(Node* root)
{
//訪問跟節點
if (root != NULL)
{
visit(root);
preTraversal(root->lchild);
preTraversal(root->rchild);
}
}
//遞歸-中序遍歷,先訪問跟左節點,然後訪問中節點,最後訪問右節點,每一個節點都要準守這樣的規則
void midTraversal(Node* root)
{
if (root != NULL)
{
midTraversal(root->lchild);
visit(root);
midTraversal(root->rchild);
}
}
//遞歸-後序遍歷,先訪問左節點,然後訪問右節點,最後訪問根節點,每一個節點都要準守這樣的規則
void postTraversal(Node* root)
{
if (root != NULL)
{
postTraversal(root->lchild);
postTraversal(root->rchild);
visit(root);
}
}
//非遞歸-前序遍歷
/*
思想:用棧來實現。首先訪問根節點,然後將根節點入棧,接着訪問當前節點的左節點,然後入棧,當左節點訪問完後,
出棧,並依次訪問右節點
*/
void un_preTraversal(Node* root)
{
stack<Node*> stack;
//當前節點
Node* p = root;
while (p != NULL || stack.size() != 0)
{
if (p != NULL)
{
visit(p);//訪問p之前一定要保證p不爲空
stack.push(p);
p = p->lchild;
}
else
{
p = stack.top();
stack.pop();
p = p->rchild;
}
}
}
//非遞歸-中序遍歷
/*
思想:用棧來實現。從根節點開始依次遍歷當前節點的左節點,並依次入棧,當左節點遍歷完成後,獲取
棧頂元素並出棧,然後訪問該節點,並依次遍歷其右節點
*/
void un_midTraversal(Node* root)
{
stack<Node*> stack;
Node* p = root;
while (p != NULL || stack.size() != 0)
{
if (p != NULL)
{
stack.push(p);
p = p->lchild;
}
else
{
p = stack.top();
stack.pop();
visit(p);
p = p->rchild;
}
}
}
//非遞歸-後序遍歷
/*
思想:用棧來實現。先根節點開始依次遍歷左節點,已經遍歷過了的標記爲'l',然後依次遍歷右節點,遍歷過的標記爲'r',
只有當標記爲'r'時才能訪問該節點。
*/
//定義一個有標記的結構體
typedef struct TNode
{
Node* node;//樹的節點的指針
char tag;//標記
}TNode;
void un_postTraversal(Node* root)
{
//當前節點
Node *p = root;
TNode *n;
stack<TNode*> stack;
while (p != NULL || stack.empty() == false)
{
//遍歷左節點並標記
while (p != NULL)
{
n = new TNode;
n->node = p;
n->tag = 'l';
stack.push(n);
p = p->lchild;
}
//出棧
n = stack.top();
stack.pop();
//遍歷當前節點的右子樹
if (n->tag == 'l')
{
n->tag = 'r';
//再次入棧
stack.push(n);
//此時p==NULL,一定要給p當前的節點
p = n->node;
p = p->rchild;
}
//左右子樹遍歷完成後訪問該節點
else
{
visit(n->node);
//並把p置空防止
p = NULL;
}
}
}
//樹的層次遍歷
//思想:使用隊列queue。先將根節點入隊列,循環判斷當前隊列不爲空時,將頭元素出隊列並訪問頭元素,然後在將它的左節點和右節點入隊列
void levelTraversal(Node* root)
{
queue<Node*> q;
Node* p = root;
q.push(p);
while (q.empty() == false)
{
p = q.front();
q.pop();
visit(p);
if (p->lchild != NULL)
q.push(p->lchild);
if (p->rchild != NULL)
q.push(p->rchild);
}
}
int main()
{
//創建上面的樹應輸入應爲 ABD##E##CF###
Node* root;
creatTree(root);
cout << "遞歸-前序遍歷:";
preTraversal(root);
cout << endl;
cout << "遞歸-中序遍歷:";
midTraversal(root);
cout << endl;
cout << "遞歸-後序遍歷:";
postTraversal(root);
cout << endl;
cout << "非遞歸-前序遍歷:";
un_preTraversal(root);
cout << endl;
cout << "非遞歸-中序遍歷:";
un_midTraversal(root);
cout << endl;
cout << "非遞歸-後序遍歷:";
un_postTraversal(root);
cout << endl;
cout << "層次遍歷:";
levelTraversal(root);
cout << endl;
}