二叉樹四種遍歷方式

2021-07-14 14:49:26 字數 3082 閱讀 4730

/* 二叉樹的四種遍歷方式

*/#include #include using namespace std;

// 二叉樹節點的定義

class treenode

};// 遞迴方式,每個結點只遍歷一次,時間複雜度o(1),遞迴最多呼叫n次,空間複雜度o(n)

// 先序:根-》遞迴左-》遞迴右

void preorder(treenode* root)

// 中序:遞迴左-》根-》遞迴右

void inorder(treenode* root)

// 後序:遞迴左-》遞迴右-》根

void postorder(treenode* root)

// 非遞迴,使用棧,每個節點只需遍歷一次,時間複雜度o(n),使用棧,只需壓入或彈出各一次,空間複雜度o(n)

// 先序:根壓入,從棧頂彈出結點,並訪問,

// 壓入當前右孩子,壓入當前左孩子,則出棧順序與先序遍歷一致

void preorder2(treenode* root)

}// 中序:初始指標pnode指向根,

// 若pnode不空,則pnode壓入,pnode指向當前左孩子,一直到最左,

// 若pnode為空,從棧頂彈出結點,並訪問,pnode當前右孩子

void inorder2(treenode* root)

else

}}// 後序,使用2個棧:設定兩個棧stk, stk2;

// 將根結點壓入第乙個棧stk;彈出stk棧頂的結點,並把該結點壓入第二個棧stk2;

// 將當前結點的左孩子和右孩子先後分別入棧stk;當所有元素都壓入stk2後,依次彈出stk2的棧頂結點,並訪問之。

// 第乙個棧的入棧順序是:根結點,左孩子和右孩子;壓入第二個棧的順序是:根結點,右孩子和左孩子。

// 因此,第二個棧彈出的順序就是:左孩子,右孩子和根結點。

void postorder2(treenode* root)

while(!stk2.empty())

}// 後序,使用1個棧:

// 每次迴圈開始時,當前結點更新為棧頂

// 首先向下遍歷,指向之前訪問的結點的指標prev為空時,或者當前訪問的是prev的孩子時,繼續向下訪問左孩子並壓入,左孩子沒有則訪問右孩子並壓入

// 之後是從左孩子向上遍歷,即當前訪問的是prev的父結點時,如果父節點有右孩子,繼續向下訪問右孩子,並壓入

// prev不為空,並且當前訪問的節點也不是prev的孩子,說明已經到達葉子節點或父結點,之後輸出當前節點,並彈出

// 每個步驟操作完成後,將prev更新為當前結點

void postorder3(treenode* root)

else if(pnode->left==prev)

else

prev = pnode;

}}// morris 遍歷:線索二叉樹,在o(1)空間內,o(n)時間內完成遍歷,通過修改葉子結點的左右空指標指向前驅或後記

// 中序:

// 1. 如果當前節點的左孩子為空,則輸出當前節點並將其右孩子作為當前節點。

// 2. 如果當前節點的左孩子不為空,在當前節點的左子樹中找到當前節點在中序遍歷下的前驅節點。

// a) 如果前驅節點的右孩子為空,將它的右孩子設定為當前節點。當前節點更新為當前節點的左孩子。

// b) 如果前驅節點的右孩子為當前節點,將它的右孩子重新設為空(恢復樹的形狀)。輸出當前節點。當前節點更新為當前節點的右孩子。

// 3. 重複以上1、2直到當前節點為空。

// 使用兩個輔助指標,空間複雜度o(1),

// 時間複雜度o(n):n個結點二叉樹有n-1條邊,每條邊最多有兩次,一次用於找前驅,一次用於訪問該結點

void inordermorris(treenode* root)

else

//已經找到prev

if(prev->right==null)

else}}

}// 前序:與中序相似,在於輸出的順序

// 1. 如果當前節點的左孩子為空,則輸出當前節點並將其右孩子作為當前節點。

// 2. 如果當前節點的左孩子不為空,在當前節點的左子樹中找到當前節點在中序遍歷下的前驅節點。

// a) 如果前驅節點的右孩子為空,將它的右孩子設定為當前節點。輸出當前節點(在這裡輸出,這是與中序遍歷唯一一點不同)。當前節點更新為當前節點的左孩子。

// b) 如果前驅節點的右孩子為當前節點,將它的右孩子重新設為空。當前節點更新為當前節點的右孩子。

// 3. 重複以上1、2直到當前節點為空。

// 時間、空間複雜度與中序相同

void preordermorris(treenode* root)

else

if(prev->right == null)

else}}

}// 後序:稍複雜,需要建立臨時結點dump,令其左孩子是root,

// 需要子過程:倒序輸出某兩個節點之間路徑上的各個節點

// 當前節點設定為臨時節點dump。

// 1. 如果當前節點的左孩子為空,則將其右孩子作為當前節點。

// 2. 如果當前節點的左孩子不為空,在當前節點的左子樹中找到當前節點在中序遍歷下的前驅節點。

// a) 如果前驅節點的右孩子為空,將它的右孩子設定為當前節點。當前節點更新為當前節點的左孩子。

// b) 如果前驅節點的右孩子為當前節點,將它的右孩子重新設為空。倒序輸出從當前節點的左孩子到該前驅節點這條路徑上的所有節點。當前節點更新為當前節點的右孩子。

// 3. 重複以上1、2直到當前節點為空。

void reversefromto(treenode* from, treenode* to)

}void printreverse(treenode* from, treenode* to)

reversefromto(to,from);//恢復樹的形狀

}void postordermorris(treenode* root)

//前驅pprev已找到

if(pprev->right==null)

else}}

}int main()

二叉樹的四種遍歷方式

前言最近做題用到很多次二叉樹的遍歷,因此寫這篇文章記錄二叉樹的四種遍歷方式。首先為了方便,先假設二叉樹的結構如下 struct treenode 對於程式的輸入為 3 根節點root 9 20 4 10 15 71.二叉樹的層次遍歷 層次遍歷就是依次遍歷樹的每一層。借助佇列,可以輕鬆實現。void ...

二叉樹的四種遍歷方式

二叉樹是一種很常見的資料結構,其結構如下圖 下面接受他的四種遍歷方式 前提 這裡先給出測試中的二叉樹結構,如下圖所示 該二叉樹對應的幾種遍歷方式的結果順序 先序遍歷 10 6 4 8 14 12 16 中序遍歷 4 6 8 10 12 14 16 後序遍歷 4 8 6 12 16 14 10 層次遍...

二叉樹 四種遍歷及其他應用

先序遍歷按照根結點 左孩子 右孩子的順序進行訪問。void preorder1 bitree root 根據前序遍歷訪問的順序,優先訪問根結點,然後再分別訪問左孩子和右孩子。即對於任一結點,其可看做是根結點,因此可以直接訪問,訪問完之後,若其左孩子不為空,按相同規則訪問它的左子樹 當訪問完其左子樹時...