二叉樹的存儲結構和遍歷算法


1. 二叉樹的存儲結構

1.1 順序存儲結構

順序存儲一棵二叉樹時,首先對該樹中的每個結點進行編號,然后以各結點的編號為下標,把各結點的值對應存儲到一個一位數組中。每個結點的編號與等深度的滿二叉樹中對應結點的編號相等,即樹根結點的編號為1,接着按照從上到下和從左到右的次序,若一個結點的編號為i,則左、右孩子的編號分別為2i和2i+1。如圖,各結點上方的數字就是該結點的編號。

假設分別采用一維數組data1和data2來順序存儲上圖的兩棵二叉樹,則兩數組中各元素的值如下圖所示。

在二叉樹的順序存儲結構中,各結點之間的關系是通過下標計算出來的,因此訪問每一個結點的雙親和左、右孩子都非常方便。如對於編號為i的結點,其雙親結點的下標為⌊i/2⌋,若存在左孩子,則左孩子結點的下標為2i,若存在右孩子,則右孩子結點的下標為2i+1。

二叉樹的順序存儲結構對於存儲完全二叉樹是合適的,它能夠充分利用存儲空間,但對於一般二叉樹,特別是對於那些單支結點較多的二叉樹來說是很不合適的,因為可能只有少數存儲位置被利用,而多數或絕大多數的存儲位置空間着。

1.2 鏈接存儲結構

 在二叉樹的鏈接存儲中,通常采用的方法是,在每個結點中設置3個域:值域、左指針域和右指針域。其結點結構為:

鏈接存儲的另一種方法是:在上面的結點結構中再增加一個parent指針域,用來指向其雙親結點。這種存儲結構既便於查找孩子結點,也便於查找雙親結點,當然也帶來存儲空間的相應增加。

同單鏈表相同,二叉鏈表既可由獨立分配的結點鏈接而成,也可由數組中的元素結點鏈接而成。

若采用獨立結點,則結點類型可定義為:

1 struct BTreeNode {
2     ElemType data;
3     BTreeNode* left;
4     BTreeNode* right;       
5 };

若采用元素結點,則結點類型可定義為:

1 struct ABTreeNode {
2     ElemType data;
3     int left, right;
4 };

元素結點從下標為1的位置起使用,下標為0的位置的左指針域通常用來存儲樹根指針,右指針域通常用來存儲空閑鏈表的表頭指針,空閑鏈表由空閑結點的right域鏈接而成。

2. 二叉樹遍歷

二叉樹遍歷算法有:前序遍歷、中序遍歷、后序遍歷和按層遍歷。

若將跟結點、左子樹和右子樹分別用D、L和R表述,則前序遍歷順序為DLR,中序遍歷順序為LDR,后序遍歷順序為LRD。

對於上圖二叉樹,

前序遍歷為:ABCDEFG

中序遍歷為:CBDAEGF

后序遍歷為:CDBGFEA

按層遍歷為:ABECDFG

2.1 前序遍歷算法

1 void PreOrder(BTreeNode* BT) {
2     if(BT != NULL) {
3         cout << BT->data << ' ';     //訪問根結點
4         PreOrder(BT->left);          //前序遍歷左子樹
5         PreOrder(BT->right);         //前序遍歷右子樹
6     }
7 }

2.2 中序遍歷算法

1 void InOrder(BTreeNode* BT) {
2     if(BT != NULL) {
3         InOrder(BT->left);          //中序遍歷左子樹
4         cout << BT->data << ' ';    //訪問根結點
5         InOrder(BT->right);         //中序遍歷右子樹
6     }
7 }

2.3 后序遍歷算法

1 void PostOrder(BTreeNode* BT) {
2     if(BT != NULL) {
3         PostOrder(BT->left);        //后序遍歷左子樹
4         PostOrder(BT->right);       //后序遍歷右子樹
5         cout << BT->data << ' ';    //訪問根結點
6     }
7 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM