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

1. 二叉樹的存儲結構

1.1 順序存儲結構

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

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

在二叉樹的順序存儲結構中,各結點之間的關係是經過下標計算出來的,所以訪問每個結點的雙親和左、右孩子都很是方便。如對於編號爲i的結點,其雙親結點的下標爲⌊i/2⌋,若存在左孩子,則左孩子結點的下標爲2i,若存在右孩子,則右孩子結點的下標爲2i+1。spa

二叉樹的順序存儲結構對於存儲徹底二叉樹是合適的,它可以充分利用存儲空間,但對於通常二叉樹,特別是對於那些單支結點較多的二叉樹來講是很不合適的,由於可能只有少數存儲位置被利用,而多數或絕大多數的存儲位置空間着。指針

1.2 連接存儲結構

 在二叉樹的連接存儲中,一般採用的方法是,在每一個結點中設置3個域:值域、左指針域和右指針域。其結點結構爲:code

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

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

若採用獨立結點,則結點類型可定義爲:二叉樹

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 }
相關文章
相關標籤/搜索