目錄
幫助理解:浙江大學數據結構:https://www.bilibili.com/video/BV1H4411N7oD?p=33
1 先序遍歷
//前序遍歷
void ProOrderTraverse(BiTree tree)
{
if (tree == NULL)
return;
cout << tree->data << " ";
ProOrderTraverse(tree->lchild);
ProOrderTraverse(tree->rchild);
}
//非遞歸前序遍歷
void ProOrder(BiTree pRoot)
{
if (pRoot == NULL)
return;
BiTree p = pRoot;
stack<BiTree>s;
while (p != NULL || !s.empty())
{
while (p != NULL)
{
s.push(p);
cout << p->data << " "; //第一次遇見的時候輸出
p = p->lchild;
}
if (!s.empty())
{
p = s.top();
s.pop();
p = p->rchild;
}
}
}
2 中序遍歷
//中序遍歷
void midOrderTraverse(BiTree tree)
{
if (tree == NULL)
return;
midOrderTraverse(tree->lchild);
cout << tree->data << " ";
midOrderTraverse(tree->rchild);
}
//非遞歸中序遍歷
void midOrder(BiTree pRoot)
{
if (pRoot == NULL)
return;
BiTree p = pRoot;
stack<BiTree>s;
while (p != NULL || !s.empty())
{
while (p!=NULL)
{
s.push(p);
p = p->lchild;
}
if (!s.empty())
{
p = s.top();
cout << p->data << " "; //第二次遇見的時候輸出
s.pop();
p = p->rchild;
}
}
}
3 後序遍歷
3.1 對於後序遍歷的非遞歸遍歷,可以將先序遍歷的左右順序顛倒,逆序輸出結果。(喜歡用這一種)
根→左→右 ——(顛倒左右順序)——根→右→左——(逆序輸出)——左→右→根
3.2 對於任一結點P,將其入棧,然後沿其左子樹一直往下搜索,直到搜索到沒有左孩子的結點,此時該結點出現在棧頂,但是此時不能將其出棧並訪問, 因此其右孩子還爲被訪問。所以接下來按照相同的規則對其右子樹進行相同的處理,當訪問完其右孩子時,該結點又出現在棧頂,此時可以將其出棧並訪問。這樣就 保證了正確的訪問順序。可以看出,在這個過程中,每個結點都兩次出現在棧頂,只有在第二次出現在棧頂時,才能訪問它。因此需要多設置一個變量標識該結點是 否是第一次出現在棧頂。
//後序遍歷
void postOrderTraverse(BiTree pRoot)
{
if (pRoot == NULL)
return;
postOrderTraverse(pRoot->lchild);
postOrderTraverse(pRoot->rchild);
cout << pRoot->data<<" ";
}
//後序遍歷非遞歸
void PostOrderNoRecursion(BiTree pRoot){
if (pRoot == NULL){
cout << "Root is NULL!" << endl;
return;
}
stack<BiTree> s1; //輔助棧
stack<BiTree> s2; //逆序記錄遍歷結果
BiTree p = pRoot;
while(p || !s1.empty()){
if(p){
s2.push(p);//根節點先壓棧
s1.push(p);
p = p->rchild;//找右兒子
}
else{
p = s1.top();
s1.pop();
p = p->lchild;//找左兒子
}
}
//此時倒序輸出stack2即爲後序遍歷的序列
while(!s2.empty()){
p = s2.top();
s2.pop();
cout << p->data << " ";
}
cout<<endl;
}
4 層序遍歷
定義一個隊列,將根節點入隊。
取隊首元素出隊,將他的左右兒子入隊。
知道隊空,遍歷結束。
//層序遍歷
void printTree(BiTree pRoot)
{
queue<BiTree> q; //定義一個隊列,數據類型是二叉樹指針,不要僅是int!!不然無法遍歷
q.push(pRoot);
while (!q.empty())
{
BiTree front = q.front();
cout<<front->data<<" ";
q.pop();
if(front->lchild != nullptr)
q.push(front->lchild);
if (front->rchild != nullptr)//判斷最前面的右節點是否爲空,不是則放入隊列
q.push(front->rchild);
}
}
深度優先dfs——先序遍歷
廣度優先bfs——層次遍歷
測試代碼:
#include<iostream>
#include<stdlib.h>
#include<stack>
#include<queue>
using namespace std;
#define len 15 //定義一個長度
typedef int ElemType;
typedef struct BiTNode
{
ElemType data;
struct BiTNode *lchild, *rchild;
}BiTNode, *BiTree;
typedef struct Node
{
BiTree btnode;
bool isfirst;
}Node,*node;
//向下遍歷,找到節點s應該插入的位置,節點有重複時,忽略這個節點
void SearchTreeNode(BiTree &root, BiTree &s) //注意:使用引用傳遞
{
if (root == NULL)
return;
if (s->data > root->data)
{
if (root->rchild == NULL)
{
root->rchild = s;
return;
}
SearchTreeNode(root->rchild, s);//s值大於根節點值,未到達葉子節點,繼續向右孩子遍歷
}
else if (s->data < root->data)
{
if (root->lchild == NULL)
{
root->lchild = s;
return;
}
SearchTreeNode(root->lchild, s);//s值小於根節點值,未到達葉子節點,繼續向左孩子遍歷
}
}
//插入一個節點,樹爲空,插入節點即爲根節點,否則找合適的位置插入
void InsertNode(BiTree &tree, BiTree &s) //注意:使用引用傳遞
{
if (tree == NULL)
tree = s;
else
SearchTreeNode(tree, s);
}
//二叉排序樹創建,每次增加一個結點,插到現有的二叉樹上去
void CreateOrderBinaryTree(BiTree &tree, int *a)
{
for (int i = 0; i < len; i++)
{
BiTree s = (BiTree)malloc(sizeof(BiTNode));
s->data = a[i];
s->lchild = NULL;
s->rchild = NULL;
InsertNode(tree, s);
}
}
//前序遍歷
void ProOrderTraverse(BiTree tree)
{
if (tree == NULL)
return;
cout << tree->data << " ";
ProOrderTraverse(tree->lchild);
ProOrderTraverse(tree->rchild);
}
//非遞歸前序遍歷
void ProOrder(BiTree pRoot)
{
if (pRoot == NULL)
return;
BiTree p = pRoot;
stack<BiTree>s;
while (p != NULL || !s.empty())
{
while (p != NULL)
{
s.push(p);
cout << p->data << " "; //第一次遇見的時候輸出
p = p->lchild;
}
if (!s.empty())
{
p = s.top();
s.pop();
p = p->rchild;
}
}
}
//中序遍歷
void midOrderTraverse(BiTree tree)
{
if (tree == NULL)
return;
midOrderTraverse(tree->lchild);
cout << tree->data << " ";
midOrderTraverse(tree->rchild);
}
//非遞歸中序遍歷
void midOrder(BiTree pRoot)
{
if (pRoot == NULL)
return;
BiTree p = pRoot;
stack<BiTree>s;
while (p != NULL || !s.empty())
{
while (p!=NULL)
{
s.push(p);
p = p->lchild;
}
if (!s.empty())
{
p = s.top();
cout << p->data << " "; //第二次遇見的時候輸出
s.pop();
p = p->rchild;
}
}
}
//後序遍歷
void postOrderTraverse(BiTree pRoot)
{
if (pRoot == NULL)
return;
postOrderTraverse(pRoot->lchild);
postOrderTraverse(pRoot->rchild);
cout << pRoot->data<<" ";
}
//非遞歸實現後續遍歷
void postOrder(BiTree pRoot)
{
if (pRoot == NULL)
return;
stack<node>s;
BiTree p = pRoot;
node tmp;
while (p!=NULL || !s.empty())
{
while (p != NULL) //沿左子樹一直往下搜索,直至出現沒有左子樹的結點
{
node btn = (node)malloc(sizeof(Node));
btn->btnode = p;
btn->isfirst = true;
s.push(btn);
p = p->lchild;
}
if (!s.empty())
{
tmp = s.top();
s.pop();
if (tmp->isfirst == true) //第一次出現在棧頂
{
tmp->isfirst = false;
s.push(tmp);
p = tmp->btnode->rchild;
}
else //第二次出現在棧頂
{
cout << tmp->btnode->data<<" ";
p = NULL;
}
}
}
}
void PostOrderNoRecursion(BiTree pRoot){
if (pRoot == NULL){
cout << "Root is NULL!" << endl;
return;
}
stack<BiTree> s1; //輔助棧
stack<BiTree> s2; //逆序記錄遍歷結果
BiTree p = pRoot;
while(p || !s1.empty()){
if(p){
s2.push(p);
s1.push(p);
p = p->rchild;
}
else{
p = s1.top();
s1.pop();
p = p->lchild;
}
}
//此時倒序輸出stack2即爲後序遍歷的序列
while(!s2.empty()){
p = s2.top();
s2.pop();
cout << p->data << " ";
}
cout<<endl;
}
//非遞歸實現後續遍歷
void postorder(BiTree pRoot)
{
if (pRoot == NULL)
return;
stack<BiTree>s;
BiTree cur = pRoot, pre = NULL;
s.push(pRoot);
while (!s.empty())
{
cur = s.top();
if ((cur->lchild == NULL&&cur->rchild == NULL) ||
((pre == cur->lchild || pre == cur->rchild) && pre != NULL))
{
cout << cur->data << " ";
s.pop();
pre = cur;
}
else
{
if (cur->rchild != NULL)
s.push(cur->rchild);
if (cur->lchild != NULL)
s.push(cur->lchild);
}
}
}
//層序遍歷
void printTree(BiTree pRoot)
{
queue<BiTree> q; //定義一個隊列,數據類型是二叉樹指針,不要僅是int!!不然無法遍歷
q.push(pRoot);
while (!q.empty())
{
BiTree front = q.front();
cout<<front->data<<" ";
q.pop();
if(front->lchild != nullptr)
q.push(front->lchild);
if (front->rchild != nullptr)//判斷最前面的右節點是否爲空,不是則放入隊列
q.push(front->rchild);
}
}
int main()
{
int a[len] = { 62, 88, 58, 47, 35, 73, 51, 99, 37, 93, 23, 27, 45, 21, 12 };
//int a[] = {1,2,3,4,5};
BiTree tree = NULL;
//創建一個二叉樹,並中序遍歷
CreateOrderBinaryTree(tree, a);
cout << "前序遍歷" << endl;
ProOrderTraverse(tree);
cout << endl;
ProOrder(tree);
cout << endl<<endl;
cout << "中序遍歷" << endl;
midOrderTraverse(tree);
cout << endl;
midOrder(tree);
cout << endl<<endl;
cout << "後序遍歷" << endl;
postOrderTraverse(tree);
cout << endl;
postOrder(tree);
cout << endl;
postorder(tree);
cout << endl<<endl;
cout << "後序遍歷2" << endl;
PostOrderNoRecursion(tree);
cout << endl;
cout << "層序遍歷" << endl;
printTree(tree);
cout << endl;
return 0;
}
測試用例:
參考:https://blog.csdn.net/happyjacob/article/details/83116702