遍歷的概念:
所謂遍歷(Traversal)是指沿着某條搜索路線,依次對樹中每個結點均做一次且僅做一次訪問。遍歷是二叉樹上最重要的運算之一,是二叉樹上進行其它運算之基礎。二叉樹上訪問結點所做的操作依賴於具體的應用問題。
遍歷方式:
根據訪問結點操作發生位置命名:
① NLR:前序遍歷(PreorderTraversal亦稱(先序遍歷))
——訪問根結點的操作發生在遍歷其左右子樹之前。
② LNR:中序遍歷(InorderTraversal)
——訪問根結點的操作發生在遍歷其左右子樹之中(間)。
③ LRN:後序遍歷(PostorderTraversal)
——訪問根結點的操作發生在遍歷其左右子樹之後。
完整的代碼(C++):
#include <iostream>
#include <queue>
#include <stack>
#include <utility>
using namespace std;
/***********************************************************************************/
/********************************* 定義接口 ****************************************/
/***********************************************************************************/
//二叉樹節點
template <typename T>
struct BiTree
{
T *data;
BiTree *par, *lChild, *rChild;
};
// 構造一個值爲data_value的樹節點
template <typename T> BiTree<T>* CreateBiTree(const T &data_value);
// 銷燬樹
template <typename T> void destory(BiTree<T> *bT);
// 判斷樹是否爲空
template <typename T> bool empty(BiTree<T> *bT);
// 計算樹的深度
template <typename T> int depth(BiTree<T> *bT);
// 把另外一棵樹插入到子樹中
template <typename T>
BiTree<T>* insert(BiTree<T> *bT, BiTree<T> *newBt, const bool &isLeft);
// 生成值爲value的新節點插入到子樹中
template <typename T>
BiTree<T>* insert(BiTree<T>* bT, const T &value, const bool &isLeft);
// 獲取樹的根
template <typename T> BiTree<T>* root(BiTree<T>* bT);
// 查找值爲value的子樹
template <typename T> BiTree<T>* find(BiTree<T>* bT, const T &value);
// 三種遍歷方式(遞歸): 先序、中序、後序
template <typename T> void beforeOrder_traverse_d(BiTree<T>* bT);
template <typename T> void infixOrder_traverse_d(BiTree<T>* bT);
template <typename T> void afterOrder_traverse_d(BiTree<T>* bT);
// 三種遍歷方式(非遞歸): 先序、中序、後序
template <typename T> void beforeOrder_traverse(BiTree<T>* bT);
template <typename T> void infixOrder_traverse(BiTree<T>* bT);
template <typename T> void afterOrder_traverse(BiTree<T>* bT);
//層序遍歷
template <typename T> void layerOrder_traverse(BiTree<T>* bT);
/***********************************************************************************/
/********************************* 接口實現 ****************************************/
/***********************************************************************************/
template <typename T>
BiTree<T>* CreateBiTree(const T &data_value)
{
BiTree<T>* bT = new BiTree<T>;
bT->data = new T(data_value);
bT->par = bT->lChild = bT->rChild = NULL;
return bT;
}
template <typename T>
void destory(BiTree<T> *bT)
{
if(bT){
destory(bT->lChild);
destory(bT->rChild);
delete bT->data;
delete bT;
}
}
template <typename T>
bool empty(BiTree<T> *bT)
{
return bT == NULL;
}
template <typename T>
int depth(BiTree<T> *bT)
{
if(bT){
int lDepth = depth(bT->lChild), rDepth = depth(bT->rChild);
return 1 + (lDepth > rDepth ? lDepth : rDepth);
}
else{
return 0;
}
}
template <typename T>
BiTree<T>* insert(BiTree<T> *bT, BiTree<T> *newBt, const bool &isLeft)
{
if(isLeft){
bT->lChild = newBt;
}
else{
bT->rChild = newBt;
}
newBt->par = bT;
return newBt;
}
template <typename T>
BiTree<T>* insert(BiTree<T>* bT, const T &value, const bool &isLeft)
{
BiTree<T>* newBt = CreateBiTree(value);
return insert(bT, newBt, isLeft);
}
template <typename T>
BiTree<T>* root(BiTree<T>* bT)
{
return bT->par ? root(bT->par) : bT;
}
template <typename T>
BiTree<T>* find(BiTree<T>* bT, const T &value)
{
if(value == *(bT->data)){
return bT;
}
BiTree<T>* res = NULL;
if(bT->lChild){
res = find(bT->lChild, value);
if(res){
return res;
}
}
if(bT->rChild){
res = find(bT->rChild, value);
if(res){
return res;
}
}
return res;
}
template <typename T>
void beforeOrder_traverse_d(BiTree<T>* bT)
{
if(bT){
cout << *(bT->data) << " ";
beforeOrder_traverse_d(bT->lChild);
beforeOrder_traverse_d(bT->rChild);
}
}
template <typename T>
void infixOrder_traverse_d(BiTree<T>* bT)
{
if(bT){
infixOrder_traverse_d(bT->lChild);
cout << *(bT->data) << " ";
infixOrder_traverse_d(bT->rChild);
}
}
template <typename T>
void afterOrder_traverse_d(BiTree<T>* bT)
{
if(bT){
afterOrder_traverse_d(bT->lChild);
afterOrder_traverse_d(bT->rChild);
cout << *(bT->data) << " ";
}
}
template <typename T>
void beforeOrder_traverse(BiTree<T>* bT)
{
stack<BiTree<T>*> st;
BiTree<T>* t = bT;
while(t || ! st.empty()){
if(t){
cout << *(t->data) << " ";
st.push(t);
t = t->lChild;
}
else{
t = st.top();
st.pop();
t = t->rChild;
}
}
}
template <typename T>
void infixOrder_traverse(BiTree<T>* bT)
{
stack<BiTree<T>*> st;
BiTree<T>* t = bT;
while(t || ! st.empty()){
if(t){
st.push(t);
t = t->lChild;
}
else{
t = st.top();
st.pop();
cout << *(t->data) << " ";
t = t->rChild;
}
}
}
template <typename T>
void afterOrder_traverse(BiTree<T>* bT)
{
stack< pair<char, BiTree<T>*> > st;
BiTree<T>* t = bT;
while(t || ! st.empty()){
// 遍歷左子樹
while(t){
st.push( pair<char, BiTree<T>*>('L', t) );
t = t->lChild;
}
// 左右子樹訪問完畢訪問根節點
while(! st.empty() && st.top().first == 'R'){
cout << *(st.top().second->data) << " ";
st.pop();
}
// 遍歷右子樹
if(! st.empty()){
st.top().first = 'R';
t = st.top().second;
t = t->rChild;
}
}
}
template <typename T>
void layerOrder_traverse(BiTree<T>* bT)
{
queue<BiTree<T>*> que;
que.push(bT);
while(! que.empty()){
BiTree<T>* t = que.front();
if(t){
cout << *(t->data) << " ";
que.push(t->lChild);
que.push(t->rChild);
}
que.pop();
}
}
/***********************************************************************************/
/***********************************************************************************/
/***********************************************************************************/
int main()
{
BiTree<int>* bT = CreateBiTree(0);
auto b1 = insert(bT, 1, true);
insert(bT, 2, false);
insert(b1, 3, true);
insert(b1, 4, false);
auto b2 = find(bT, 2);
auto rootT = root(insert(b2, 5, true));
cout << "樹的深度:" << depth(bT) << endl;
cout << "先序遍歷(遞歸):";
beforeOrder_traverse_d(rootT);
cout << endl;
cout << "中序遍歷(遞歸):";
infixOrder_traverse_d(rootT);
cout << endl;
cout << "後序遍歷(遞歸):";
afterOrder_traverse_d(rootT);
cout << endl;
cout << "先序遍歷(非遞歸):";
beforeOrder_traverse(rootT);
cout << endl;
cout << "中序遍歷(非遞歸):";
infixOrder_traverse(rootT);
cout << endl;
cout << "後序遍歷(非遞歸):";
afterOrder_traverse(rootT);
cout << endl;
cout << "層序遍歷:";
layerOrder_traverse(bT);
cout << endl;
destory(bT);
return 0;
}
效果圖:
(手畫的^_^)
2018-8-15 編輯添加:
重新學習數據結構時,發現另外一種二叉樹後序遍歷非遞歸算法,代碼如下:
//後序遍歷二叉樹
template <typename T>
void afterOrder_traverse(BiTree<T>* bT)
{
BiTree<T>* t = bT;
if(t != NULL) {
stack<BiTree<T>*> s;
do {
//將所有最左結點壓棧
while(t) {
s.push(t);
t = t->lChild;
}
int flag = true; // flag爲true表示當前結點的左孩子爲空或者已被訪問
BiTree<T>* lastVisit = NULL; // 上一次訪問的節點
while(!s.empty() && flag) {
t = s.top(); // 注意:這裏只是獲取棧頂元素,而並沒有出棧
if(t->rChild == lastVisit) { // 如果當前結點右孩子爲空,或者已經被訪問過,則訪問當前結點
s.pop(); // 當前結點出棧
cout << *(t->data) << " "; // 訪問節點
lastVisit = t; // 指針變量指向當前結點
} else { // 如果當前結點右孩子不爲空,則先去處理右孩子
t = t->rChild; // 處理右孩子
flag = false; // t的左孩子未被訪問,flag置爲false
//lastVisit = t; // 可省略
}
}
} while(!s.empty());
}
}