資料結構之遍歷二叉樹
遍歷二叉樹
在二叉樹的一些應用中,常常要求在樹中查詢具有某種特徵的結點。這就提出遍歷二叉樹的問題,即如何按某條搜尋路徑巡訪樹中每個結點,使得每個結點均被訪問一次,而且僅被訪問一次。遍歷對線性結構來說,是一個容易解決的問題。而對二叉樹則不然,由於二叉樹是一種非線性結構,每個結點都可能有兩顆子樹,因而需要尋找一種規律,以便使二叉樹上的結點能排列在一個線性佇列上,從而便於遍歷。
回顧二叉樹的遞迴定義可知,二叉樹是由3個基本單元組成:根結點、左子樹和右子樹。因此,若能依次遍歷這三部分,便是遍歷了整個二叉樹。例如以L、D、R分別表示遍歷左子樹、訪問根結點和遍歷右子樹,則可有DLR、LDR、LRD、DRL、RDL、RLD這6種遍歷二叉樹的方案。若限定先左後右、則只有3種情況,分別稱之為前(根)序遍歷、中(根)序遍歷和後(根)序遍歷。基於二叉樹的遞迴定義,可得下述遍歷二叉樹的遞迴演算法定義。
1. 前序遍歷二叉樹的操作:
若二叉樹為空,則空操作返回;否則
1.1.訪問根結點中的資料;
1.2.前序遍歷左子樹;
1.3.前序遍歷右子樹。
前序遍歷二叉樹程式碼如下:
// 前序遍歷二叉樹
void pre_order_traversal(BTreeNode* root)
{
// 二叉樹不為空
if( root != NULL )
{
// 訪問根結點中的資料並列印
printf("%c, ", ((struct Node*)root)->v);
// 前序遍歷左子樹
pre_order_traversal(root->left);
// 前序遍歷右子樹
pre_order_traversal(root->right);
}
}
2.中序遍歷二叉樹的操作:
若二叉樹為空,則空操作返回;否則
2.1.中序遍歷左子樹;
2.2.訪問根結點中的資料;
2.3.中序遍歷右子樹。
中序遍歷二叉樹程式碼如下:
// 中序遍歷二叉樹
void middle_order_traversal(BTreeNode* root)
{
// 二叉樹不為空
if( root != NULL )
{
// 中序遍歷左子樹
middle_order_traversal(root->left);
// 訪問根結點中的資料並列印
printf("%c, ", ((struct Node*)root)->v);
// 中序遍歷右子樹
middle_order_traversal(root->right);
}
}
3.後序遍歷二叉樹的操作:
若二叉樹為空,則空操作返回;否則
3.1.中序遍歷左子樹;
3.2.中序遍歷右子樹;
3.3.訪問根結點中的資料。
後序遍歷二叉樹程式碼如下:
// 後序遍歷二叉樹
void post_order_traversal(BTreeNode* root)
{
// 二叉樹不為空
if( root != NULL )
{
// 後序遍歷左子樹
post_order_traversal(root->left);
// 後序遍歷右子樹
post_order_traversal(root->right);
// 訪問根結點中的資料並列印
printf("%c, ", ((struct Node*)root)->v);
}
}
從上述二叉樹遍歷的定義可知,3種遍歷演算法之不同處僅在於訪問根結點和遍歷左、右子樹的先後關係。
對二叉樹進行遍歷的搜尋路徑除了上述前序、中序和後序外,還可以從上到下、從左到右按層次進行。
4.層次遍歷二叉樹的操作:
若二叉樹為空,則空操作返回;否則
4.1. 訪問根結點中的資料;
4.2. 訪問第二層所有結點的資料;
4.3. 訪問第三層所有結點的資料;
4.4. 。。。。。。
顯然,層次遍歷二叉樹不能使用遞迴的方法,那我們應該怎麼辦你?我們可以應用佇列來實現,佇列相關內容參考資料結構之鏈式佇列的優化。首先將根結點入列,然後迴圈查詢佇列中是否有元素,有元素就出列一次,再將出列元素代表的結點的左右子樹入列,周而復始,直至佇列中沒有元素為止。實現程式碼如下:
// 層次遍歷二叉樹
void level_order_traversal(BTreeNode* root)
{
// 二叉樹不為空
if( root != NULL )
{
// 建立佇列
LinkQueue* queue = LinkQueue_Create();
// 佇列建立成功
if( queue != NULL )
{
// 將二叉樹根結點入列
LinkQueue_Append(queue, root);
// 佇列長度不為零,即佇列中有元素
while( LinkQueue_Length(queue) > 0 )
{
// 將結點元素出列
struct Node* node = (struct Node*)LinkQueue_Retrieve(queue);
// 列印出列的元素
printf("%c, ", node->v);
// 將結點的左右子樹入列
LinkQueue_Append(queue, node->header.left);
LinkQueue_Append(queue, node->header.right);
}
}
// 銷燬佇列
LinkQueue_Destroy(queue);
}
}
驗證程式碼如下:
int main(int argc, char *argv[])
{
// 建立二叉樹
BTree* tree = BTree_Create();
// 定義二叉樹內容
struct Node n1 = {{NULL, NULL}, 'A'};
struct Node n2 = {{NULL, NULL}, 'B'};
struct Node n3 = {{NULL, NULL}, 'C'};
struct Node n4 = {{NULL, NULL}, 'D'};
struct Node n5 = {{NULL, NULL}, 'E'};
struct Node n6 = {{NULL, NULL}, 'F'};
// 插入二叉樹
BTree_Insert(tree, (BTreeNode*)&n1, 0, 0, 0);
BTree_Insert(tree, (BTreeNode*)&n2, 0x00, 1, 0);
BTree_Insert(tree, (BTreeNode*)&n3, 0x01, 1, 0);
BTree_Insert(tree, (BTreeNode*)&n4, 0x00, 2, 0);
BTree_Insert(tree, (BTreeNode*)&n5, 0x02, 2, 0);
BTree_Insert(tree, (BTreeNode*)&n6, 0x02, 3, 0);
// 顯示整體二叉樹
printf("Full Tree: \n");
BTree_Display(tree, printf_data, 4, '-');
// 測試前序遍歷二叉樹功能
printf("Pre Order Traversal:\n");
pre_order_traversal(BTree_Root(tree));
printf("\n");
// 測試中序遍歷二叉樹功能
printf("Middle Order Traversal:\n");
middle_order_traversal(BTree_Root(tree));
printf("\n");
// 測試後序遍歷二叉樹功能
printf("Post Order Traversal:\n");
post_order_traversal(BTree_Root(tree));
printf("\n");
// 測試層次遍歷二叉樹功能
printf("Level Order Traversal:\n");
level_order_traversal(BTree_Root(tree));
printf("\n");
// 銷燬二叉樹
BTree_Destroy(tree);
return 0;
}
顯然,遍歷二叉樹的演算法中的基本操作是訪問結點,則不論按哪一種次序進行遍歷,對含有n個結點的二叉樹,其時間複雜度均為O(n)。所需輔助空間為遍歷過程中棧的最大容量,即樹的深度,在最壞情況下為n,則空間複雜度也為O(n)。
通過以上程式碼發現,二叉樹僅僅比單連結串列多了一個指標域,但其遍歷演算法的種類卻增加了很多 。遞迴定義的資料結構採用遞迴的演算法進行遍歷往往能達到簡單可靠的效果 。
遍歷二叉樹程式碼:遍歷二叉樹C實現程式碼
相關文章
- 資料結構 二叉樹遍歷資料結構二叉樹
- 資料結構——樹與二叉樹的遍歷資料結構二叉樹
- 【資料結構】二叉樹的建立與遍歷資料結構二叉樹
- 資料結構-二叉樹的儲存結構與遍歷資料結構二叉樹
- 資料結構與演算法-二叉樹遍歷資料結構演算法二叉樹
- 實戰資料結構(11)_二叉樹的遍歷資料結構二叉樹
- 【資料結構】二叉樹遍歷(遞迴+非遞迴)資料結構二叉樹遞迴
- 資料結構與演算法——二叉樹的前序遍歷,中序遍歷,後序遍歷資料結構演算法二叉樹
- 【資料結構&演算法】11-樹基礎&二叉樹遍歷資料結構演算法二叉樹
- python資料結構之二叉樹遍歷的實現Python資料結構二叉樹
- 資料結構實驗:二叉樹的遍歷(C語言版)資料結構二叉樹C語言
- 用python講解資料結構之樹的遍歷Python資料結構
- Python資料結構——解析樹及樹的遍歷Python資料結構
- 二叉樹遍歷方法總結二叉樹
- 資料結構之「二叉樹」資料結構二叉樹
- 資料結構 排序二叉樹(BST) 插入刪除查詢 中序遍歷 銷燬(後序遍歷)資料結構排序二叉樹
- 二叉樹---遍歷二叉樹
- 二叉樹遍歷二叉樹
- 資料結構-二叉樹的遍歷(類C語言描寫敘述)資料結構二叉樹C語言
- 二叉樹的構造與遍歷二叉樹
- LintCode 前序遍歷和中序遍歷樹構造二叉樹二叉樹
- 遍歷結果推導二叉樹二叉樹
- 【圖解資料結構】 一組動畫徹底理解二叉樹三種遍歷圖解資料結構動畫二叉樹
- [資料結構]二叉樹的前中後序遍歷(遞迴+迭代實現)資料結構二叉樹遞迴
- [資料結構] 根據前中後序遍歷中的兩種構造二叉樹資料結構二叉樹
- 一本正經的聊資料結構(5):二叉樹的儲存結構與遍歷資料結構二叉樹
- 二叉樹遍歷方法二叉樹
- 二叉樹遍歷 -- JAVA二叉樹Java
- 二叉樹的遍歷二叉樹
- JAVA遍歷二叉樹Java二叉樹
- 388,先序遍歷構造二叉樹二叉樹
- 資料結構(樹):二叉樹資料結構二叉樹
- 重學資料結構之樹和二叉樹資料結構二叉樹
- C++樹——遍歷二叉樹C++二叉樹
- 資料結構之「二叉搜尋樹」資料結構
- 【資料結構與演算法】二叉樹的 Morris 遍歷(前序、中序、後序)資料結構演算法二叉樹
- Codeup《演算法筆記》9.2小節——資料結構專題(2)->二叉樹的遍歷->二叉樹演算法筆記資料結構二叉樹
- SDUTOJ 2128 樹結構練習——排序二叉樹的中序遍歷排序二叉樹