前言:
知道了樹的遍歷的型別以及概念,接下來我們就要設計演算法將其用**優雅的表述出來。(還不清楚概念的可以看另一篇部落格:樹的遍歷基本概念)
開發語言:c++
編輯器:clion
專案原始碼:樹的遍歷
我們以這棵樹為例:
在寫**之前首先定義樹的結構體,並且初始化建立一棵樹:
//定義樹節點的結構體
struct treenode
//建構函式
treenode
(int x)
:val
(x),
left
(nullptr),
right
(nullptr
)treenode
(int x, treenode *left, treenode *right)
:val
(x),
left
(left)
,right
(right)
};
//初始化樹
treenode*
generatetree()
return root;
}
對於前序,後序和中序遍歷,我們可以使用遞迴和非遞迴的方法來解決
遞迴法
1.前序遍歷:對於前序遍歷我們從根節點開始遍歷,遇到乙個節點我們就列印出它的值並且遞迴遍歷左右節點。
//前序遍歷 --遞迴版
void
pre(treenode* root)
}
2. 中序遍歷:對於中序遍歷,我們在遍歷完所有的左節點後再遍歷根節點,列印根節點資訊,然後右節點。
//中序遍歷 --遞迴版
void
medium
(treenode* root)
}
3. 後序遍歷:後序遍歷先遞迴遍歷左子樹,再遞迴遍歷右子樹,然後列印根節點資訊。
//後序遍歷 --遞迴版
void
last
(treenode* root)
}
非遞迴版,由於遞迴就是隱式的使用棧,我們使用非遞迴也就是迭代的方法就要顯示的將棧的使用表示出來。
1. 前序遍歷:從根節點開始遍歷,不斷遍歷左節點直至為空,列印其資訊並且入棧,當遍歷完左邊之後彈出棧頂,遍歷棧頂元素的右子樹。
//前序遍歷 --非遞迴
void
pre1
(treenode* root)if(
!ans.
empty())}}
2. 中序遍歷
//中序遍歷 --非遞迴
/* * 主要思想:從根節點開始入棧,一直向左遍歷,直到左節點為空,此時彈出最左邊的節點,同時將當前節點指向最左邊節點
* 的右節點,重新剛剛的操作,這樣就能保證 中序。例如這個例子:
* 1、 0入棧,1入棧,3入棧,此時當前節點左節點為空,棧內元素為;
* 2、 節點指向3,列印3,彈出3,節點指向3的右節點,因為右節點為空,所以繼續彈出元素1;
* 3、 節點指向1的右節點4,對於4.重複1操作。
* 4、 重複以上操作直到當前節點為空並且棧也為空,結束迴圈。
*/void
medium1
(treenode* root)if(
!ans.
empty())}}
3. 後序遍歷
//後序遍歷非遞迴版
/* * 後序遍歷一定要保證根節點在左右節點之後遍歷,所以遍歷根節點時,我們要判斷它的左右節點是否為空,或者左右節點是否被遍歷過。同時我們壓棧時為了保證
* 先遍歷的是左節點,我們要先將右節點入棧,然後將左節點入棧。
*/void
last1
(treenode* root)
else
}}
*以上所有的方法由於使用了額外的棧開銷(遞迴方法也隱式的呼叫了,因為要儲存你處理過但是還沒有處理完的函式的資訊),同時需要遍歷每乙個元素,所以時間複雜度和空間複雜度都是o(n)
。還有另一種使用常數空間遍歷的方法–morris遍歷,由於比較複雜,我會用另一篇文章來詳細寫。
廣度優先遍歷(bfs):廣度優先遍歷樹,需要用到佇列(queue)來儲存節點物件,佇列的特點就是先進先出。先往佇列中插入左節點,再插右節點,這樣出隊就是先左節點後右節點了。依次彈出就行並列印就行。
//廣度優先遍歷
void
bfs(treenode* root)
}
深度優先遍歷(dfs):深度優先遍歷各個節點,需要使用到棧(stack)這種資料結構。stack的特點是是先進後出。整個遍歷過程如下:首先列印當前節點,然後先往棧中壓入右節點,再壓左節點,這樣出棧就是先左節點後右節點了。
//深度優先遍歷
void
dfs(treenode* root)
}
**執行結果:
源**:
/*
* 樹的遍歷操作
* 2020/10/27
* csu-xzy
* */
#include
using
namespace std;
//定義樹節點的結構體
struct treenode
//建構函式
treenode
(int x)
:val
(x),
left
(nullptr),
right
(nullptr
)treenode
(int x, treenode *left, treenode *right)
:val
(x),
left
(left)
,right
(right)};
//初始化樹
treenode*
generatetree()
return root;
}//前序遍歷 --遞迴版
void
pre(treenode* root)
}//中序遍歷 --遞迴版
void
medium
(treenode* root)
}//後序遍歷 --遞迴版
void
last
(treenode* root)
}//前序遍歷 --非遞迴
void
pre1
(treenode* root)if(
!ans.
empty()
)}}//中序遍歷 --非遞迴
/* * 主要思想:從根節點開始入棧,一直向左遍歷,直到左節點為空,此時彈出最左邊的節點,同時將當前節點指向最左邊節點
* 的右節點,重新剛剛的操作,這樣就能保證 中序。例如這個例子:
* 1、 0入棧,1入棧,3入棧,此時當前節點左節點為空,棧內元素為;
* 2、 節點指向3,列印3,彈出3,節點指向3的右節點,因為右節點為空,所以繼續彈出元素1;
* 3、 節點指向1的右節點4,對於4.重複1操作。
* 4、 重複以上操作直到當前節點為空並且棧也為空,結束迴圈。
*/void
medium1
(treenode* root)if(
!ans.
empty()
)}}//後序遍歷非遞迴版
/* * 後序遍歷一定要保證根節點在左右節點之後遍歷,所以遍歷根節點時,我們要判斷它的左右節點是否為空,或者左右節點是否被遍歷過。同時我們壓棧時為了保證
* 先遍歷的是左節點,我們要先將右節點入棧,然後將左節點入棧。
*/void
last1
(treenode* root)
else}}
//廣度優先遍歷
void
bfs(treenode* root)
}//深度優先遍歷
void
dfs(treenode* root)
}int
main()
二叉樹遍歷演算法和原始碼
1.二叉樹幾種遍歷方法 1 先 根 序遍歷的 遞迴演算法 定義 若二叉樹非空,則依次執行如下操作 訪問根結點 遍歷左子樹 遍歷右子樹。2 中 根 序遍歷的遞迴演算法定義 若二叉樹非空,則依次執行如下操作 遍歷左子樹 訪問根結點 遍歷右子樹。3 後 根 序遍歷得遞迴演算法定義 若二叉樹非空,則依次執行...
二叉樹遍歷演算法
二叉樹是一種非線性的資料結構,在對它進行操作時,總是需要逐一對每個資料元素實施操作,這樣就存在乙個操作順序問題,由此提出了二叉樹的遍歷操作。所謂遍歷二叉樹就是按某種順序訪問二叉樹中的每個結點一次且僅一次的過程。這裡的訪問可以是輸出 比較 更新 檢視元素內容等等各種操作。在這裡寫了個二叉樹遍歷演算法 ...
廣度遍歷二叉樹和深度遍歷二叉樹演算法
二叉樹演算法基本和遞迴有關,前中後序演算法就不提了,主要看一下深度優先遍歷和廣度優先遍歷。實現這2種遍歷需要借助棧或者佇列來儲存中間結果,原因是遍歷過程出現了回溯。1 筆試題 廣度遍歷二叉樹 深度遍歷二叉樹 23 include4 include5 include6 7using namespace...