二叉查找樹

  二叉樹的定義是一棵樹的每一個節點最多隻有兩個兒子,使二叉樹成爲二叉查找樹的性質是,對於樹中的每一個節點X,它的左子樹中的關鍵字比X中的小,而它的右子樹則比X中的關鍵字大。算法

  二叉樹節點能夠定義成以下形式:spa

1 struct BSTreeNode {
2     BSTreeNode* pLeft;
3     BSTreeNode* pRight;
4     int nData;
5 };

  二叉樹很是簡單,下面再介紹幾個基本的操做。指針

  1、插入code

    插入一個關鍵字Key從根節點開始,若是Key比此節點關鍵字大,則往右邊繼續往下,直到節點爲空,如下代碼爲非遞歸寫法,要寫成遞歸寫法也是很是容易的blog

 1 //返回樹的根節點
 2 BSTreeNode* BSTreeInsert(BSTreeNode* pRoot, int nData) {
 3     if (pRoot == nullptr) {
 4         pRoot = new BSTreeNode;
 5         pRoot->pLeft = pRoot->pRight = nullptr;
 6         pRoot->nData = nData;
 7     }
 8     else {
 9         BSTreeNode* pParent = pRoot;
10         BSTreeNode* pCursor = pParent;
11         while (pCursor) {
12             pParent = pCursor;
13             if (nData > pCursor->nData)
14                 pCursor = pCursor->pRight;
15             else if (nData < pCursor->nData)
16                 pCursor = pCursor->pLeft;
17             else
18                 return pRoot;
19         }
20         pCursor = new BSTreeNode;
21         pCursor->nData = nData;
22         pCursor->pLeft = pCursor->pRight = nullptr;
23         if (nData > pParent->nData)
24             pParent->pRight = pCursor;
25         else if (nData < pParent->nData)
26             pParent->pLeft = pCursor;
27     }
28     return pRoot;
29 }

  2、獲取最小值排序

    一直往左邊遍歷,直到節點爲空。遞歸

 1 BSTreeNode* BSTreeMinimumNode(BSTreeNode* pRoot) {
 2     if (pRoot == nullptr)
 3         return nullptr;
 4 
 5     BSTreeNode* pCursor = pRoot;
 6     while (pCursor->pLeft) {
 7         pCursor = pCursor->pLeft;
 8     }
 9     return pCursor;
10 }

  3、獲取最大值class

    一直往右邊遍歷,直到節點爲空。二叉樹

 1 BSTreeNode* BSTreeMaximumNode(BSTreeNode* pRoot) {
 2     if (pRoot == nullptr)
 3         return nullptr;
 4 
 5     BSTreeNode* pCursor = pRoot;
 6     while (pCursor->pRight) {
 7         pCursor = pCursor->pRight;
 8     }
 9     return pCursor;
10 }

  4、刪除遍歷

    二叉查找樹的刪除稍複雜一些,先查找此樹待刪除節點,當找到此節點(設爲X)時,先判斷左子節點和右子節點是否爲空,若是有任一子節點爲空,則刪除很是容易,只須要將空節點的兄弟節點代替要刪除的節點     便可。而若是左子節點和右子節點都不爲空,則在待刪除節點的右子樹中找一個值最小的節點(設爲Y),而後將此最小節點的值賦值給待刪除結點X,而後在右子樹中刪除此最小節點Y,並且Y一定左子節點爲空的,刪除會很是簡單。代碼以下:

 1 BSTreeNode* BSTreeDelete(BSTreeNode* pRoot, int nData) {
 2     if (pRoot == nullptr)
 3         return nullptr;
 4     else if (nData > pRoot->nData) {
 5         pRoot->pRight = BSTreeDelete(pRoot->pRight, nData);
 6         return pRoot;
 7     }
 8     else if (nData < pRoot->nData) {
 9         pRoot->pLeft = BSTreeDelete(pRoot->pLeft, nData);
10         return pRoot;
11     }
12     else {
13         if (pRoot->pLeft == nullptr || pRoot->pRight == nullptr) {
14             BSTreeNode* pNode = (pRoot->pRight == nullptr) ? pRoot->pLeft : pRoot->pRight;
15             delete pRoot;
16             return pNode;
17         }
18         else {
19             BSTreeNode* pNode = BSTreeMinimumNode(pRoot->pRight);
20             pRoot->nData = pNode->nData;
21             pRoot->pRight = BSTreeDelete(pRoot->pRight, pNode->nData);
22             return pRoot;
23         }
24     }
25 }

  返回值是傳入的樹被刪除nData後樹的根節點。刪除後,經過遞歸回溯,將返回值賦值給原節點對應的左子樹或右子樹。

  在《算法導論》裏面,採用的是非遞歸刪除,因此在那裏討論若是X的左右子節點不爲空,則查找右子樹中的後繼節點Y(也就是最小節點)時,還討論了若是後繼Y是X的右子節點的狀況,若是是右子節點則直接拿Y替換X,不然拿Y的右子節點先替換X中的值,再拿Y的右子節點替換Y。我的感受不如遞歸刪除的代碼簡潔明瞭。並且非遞歸刪除裏面,節點必須保持對父節點的引用,也就是說節點的定義裏面要加一個父節點指針。

  5、二叉樹的遍歷

    二叉樹的遍歷有三種遍歷方式,先序遍歷,中序遍歷,後序遍歷

    先序遍歷:自己,左子節點,右子節點。

    中序遍歷:左子節點,自己,右子節點。

    後序遍歷:左子節點,右子節點,自己。

  以如下二叉樹爲例:

      

  先序遍歷輸出:ABDECFG

  中序遍歷輸出:DBEAFCG

  後序遍歷輸出:DEBFGCA

  由以上可知,中序遍歷輸出的是排序好的結果。

  6、查找

    查找就不用說了,二叉查找樹,在平均狀況下,時間爲O(logN),也就是樹的高度

相關文章
相關標籤/搜索