1. 程式人生 > >資料結構樹之二分查詢樹

資料結構樹之二分查詢樹

二叉查詢樹Binary Search Tree),也稱有序二叉樹(ordered binary tree),排序二叉樹(sorted binary tree),是指一棵空樹或者具有下列性質的二叉樹:

  1. 若任意節點的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值;
  2. 任意節點的右子樹不空,則右子樹上所有結點的值均大於它的根結點的值;
  3. 任意節點的左、右子樹也分別為二叉查詢樹。
  4. 沒有鍵值相等的節點(no duplicate nodes)。

二叉查詢樹的性質:

  二叉查詢樹本質上是一種二叉樹,所以上章講的二叉樹的性質他都有。

二叉查詢樹的思想:

  二叉排序樹的查詢過程和次優

二叉樹類似,通常採取二叉連結串列作為二叉排序樹儲存結構中序遍歷二叉排序樹可得到一個關鍵字的有序序列,一個無序序列可以通過構造一棵二叉排序樹變成一個有序序列,構造樹的過程即為對無序序列進行排序的過程。每次插入的新的結點都是二叉排序樹上新的葉子結點,在進行插入操作時,不必移動其它結點,只需改動某個結點的指標,由空變為非空即可。搜尋,插入,刪除的複雜度等於樹高,O(log(n)).

二叉查詢樹的操作:

  /*二叉樹的鏈式定義*/

1 #define DataType int
2 //二叉樹的前序遍歷
3 typedef struct BiTNode    //二元查詢樹的節點
4 {
5 DataType m_Value; 6 BiTNode *m_pLeft; 7 BiTNode *m_pRight; 8 }BiTNode;

  //建立二元查詢樹,相當於一個個的插入

 1 void addBSTreeNode(BiTNode *&pCurrent,DataType value)
 2 {
 3     if(NULL == pCurrent)    //如果是空的話就建立節點
 4     {
 5         BiTNode *pBSTree = new BiTNode();
 6         pBSTree->m_pLeft  = NULL;
7 pBSTree->m_pRight = NULL; 8 pBSTree->m_Value = value; 9 pCurrent = pBSTree; 10 } 11 else 12 { 13 if(pCurrent->m_Value > value) 14 { 15 addBSTreeNode(pCurrent->m_pLeft,value); 16 } 17 else if(pCurrent->m_Value < value) 18 { 19 addBSTreeNode(pCurrent->m_pRight,value); 20 } 21 else 22 { 23 cout << "重複插入"; 24 } 25 } 26 }

  //二分查詢樹的搜尋,時間複雜度O(logn)

 1 BiTNode * searchBSTreeNode(BiTNode *pCurrent,DataType value)
 2 {
 3     if(pCurrent == NULL || pCurrent->m_Value == value)
 4     {
 5         return pCurrent;
 6     }
 7     if(pCurrent->m_Value > value)
 8     {
 9         return searchBSTreeNode(pCurrent->m_pLeft,value);
10     }
11     else
12     {
13         return searchBSTreeNode(pCurrent->m_pRight,value);
14     }
15 }

  //返回二叉查詢樹中的最小值

1 BiTNode * getMinValueFromBSTree(BiTNode *pCurrent)
2 {
3     while(pCurrent->m_pLeft)
4         pCurrent = pCurrent->m_pLeft;
5     return pCurrent;
6 }

  //返回二叉查詢樹中的最大值

1 BiTNode * getMaxValueFromBSTree(BiTNode *pCurrent)
2 {
3     while(pCurrent->m_pRight)
4         pCurrent = pCurrent->m_pRight;
5     return pCurrent;
6 }

  //返回二叉查詢樹中的一個節點的後繼結點

 1 BiTNode * getSuccessorNode(BiTNode *pCurrent,BiTNode *x)
 2 {
 3     if(!x||!pCurrent)
 4         return NULL;
 5     //如果x節點的右子樹不為空,那麼後繼結點一定是右子樹的最左結點
 6     if(x->m_pRight)
 7         return getMinValueFromBSTree(x->m_pRight);
 8     //如果是空節點
 9     while(pCurrent)
10     {
11         if(x->m_Value < pCurrent->m_Value)                //如果比正在檢查的節點小,
12             if(getMaxValueFromBSTree(pCurrent->m_pLeft)->m_Value == x->m_Value)    //根節點只有可能是他左子樹的最大節點的後繼結點
13                 return pCurrent;
14             else
15                 pCurrent = pCurrent->m_pLeft;
16         else
17                 pCurrent = pCurrent->m_pRight;
18     }
19     return pCurrent;
20 }

//返回二叉查詢樹中的一個節點的前驅結點

 1 BiTNode * getPredecessorNode(BiTNode *pCurrent,BiTNode *x)
 2 {
 3     if(!x||!pCurrent)
 4         return NULL;
 5     //如果x節點的左子樹不為空,那麼後繼結點一定是左子樹的最右結點
 6     if(x->m_pLeft)
 7         return getMaxValueFromBSTree(x->m_pLeft);
 8     //如果是空節點
 9     while(pCurrent)
10     {
11         if(x->m_Value > pCurrent->m_Value)                                            //如果比正在檢查的節點小,
12             if(getMinValueFromBSTree(pCurrent->m_pRight)->m_Value == x->m_Value)    //根節點只有可能是他右子樹的最小結點的前驅結點
13                 return pCurrent;
14             else
15                 pCurrent = pCurrent->m_pRight;
16         else
17                 pCurrent = pCurrent->m_pLeft;
18     }
19     return pCurrent;
20 }

  //返回一個結點的雙親結點

 1 BiTNode * getParentsNode(BiTNode *pCurrent,BiTNode * x)
 2 {
 3     if(!pCurrent || pCurrent == x ||!x)    //根為空或者就是根節點,則無父節點
 4         return NULL;
 5     while(pCurrent)
 6     {
 7         if(pCurrent->m_pLeft == x || pCurrent->m_pRight == x)
 8             return pCurrent;
 9         if(x->m_Value < pCurrent->m_Value)
10             pCurrent = pCurrent->m_pLeft;
11         else
12             pCurrent = pCurrent->m_pRight;
13     }
14     return NULL;
15 }

  //刪除二叉查詢樹中一個值為指定值的結點---這個有點長,主要是有些重複的操作可以封裝到函式中去,我沒有!

  1 void deleteNodeFromBSTreeNode(BiTNode *&pCurrent,DataType value)
  2 {
  3     if(!pCurrent)
  4         return;
  5     BiTNode *fitNode = searchBSTreeNode(pCurrent,value);    //找到要刪除的結點
  6     if(!fitNode)                                            //是NULL,直接返回。沒找到要刪除的結點
  7         return ;
  8     BiTNode *parents = getParentsNode(pCurrent,fitNode),*temp = NULL;    //得到要刪除結點的父親結點
  9     if(!fitNode->m_pLeft)    //如果左結點為空
 10     {
 11         if(parents)
 12         {
 13             if(fitNode == parents->m_pLeft)    //如果是父結點的左結點
 14             {
 15                 parents->m_pLeft = fitNode->m_pRight;
 16             }
 17             else
 18             {
 19                 parents->m_pRight = fitNode->m_pRight;
 20             }
 21         }
 22         else    //沒有父結點,那要刪除的就是根節點
 23         {
 24             pCurrent = fitNode->m_pRight;
 25         }
 26     }
 27     else if(!fitNode->m_pRight)        //如果右結點為空
 28     {
 29         if(parents)
 30         {
 31             if(fitNode == parents->m_pLeft)    //如果是父結點的左結點
 32             {
 33                 parents->m_pLeft = fitNode->m_pLeft;
 34             }
 35             else
 36             {
 37                 parents->m_pRight = fitNode->m_pLeft;
 38             }
 39         }
 40         else    //沒有父結點,那要刪除的就是根節點
 41         {
 42             pCurrent = fitNode->m_pLeft;
 43         }
 44     }
 45     else //左右孩子都不為空
 46     {
 47         //找到右子樹中左邊的的結點---即右子樹最小值結點
 48         temp =  getMinValueFromBSTree(fitNode->m_pRight);
 49         if(fitNode->m_pRight != temp)    
 50         {
 51             BiTNode *parents1 = getParentsNode(pCurrent,temp);
 52             if(parents1)
 53             {
 54                 //肯定是在父結點的左結點上
 55                 parents1->m_pLeft = temp->m_pRight;
 56             }
 57             else
 58             {
 59                 //不可能沒有父結點了
 60             }
 61             temp->m_pRight = fitNode->m_pRight;
 62             temp->m_pLeft  = fitNode->m_pLeft;
 63             if(parents)
 64             {
 65                 if(parents->m_pLeft == fitNode)
 66                 {
 67                     parents->m_pLeft =  temp;
 68                 }
 69                 else
 70                 {
 71                     parents->m_pRight = temp;
 72                 }
 73             }
 74             else
 75             {
 76                 pCurrent = temp;
 77             }
 78         }
 79         else
 80         {
 81             if(parents)
 82             {
 83                 if(parents->m_pLeft == fitNode)
 84                 {
 85                     parents->m_pLeft =  temp;
 86                     temp ->m_pLeft = fitNode->m_pLeft;
 87                 }
 88                 else
 89                 {
 90                     parents->m_pRight = temp;
 91                     temp ->m_pLeft = fitNode->m_pLeft;
 92                 }
 93             }
 94             else
 95             {
 96                 pCurrent = temp;
 97             }
 98         }
 99     }
100 }

  //以下是對二叉查詢樹的操作例項

 1 int main()
 2 {
 3     BiTNode * root = NULL,*p;
 4     addBSTreeNode(root,15);
 5     addBSTreeNode(root,6);
 6     addBSTreeNode(root,18);
 7     addBSTreeNode(root,3);
 8     addBSTreeNode(root,7);
 9     addBSTreeNode(root,17);
10     addBSTreeNode(root,20);
11     addBSTreeNode(root,2);
12     addBSTreeNode(root,4);
13     addBSTreeNode(root,13);
14     addBSTreeNode(root,9);
15     p = searchBSTreeNode(root,18);
16     if(p)    cout << &p << ":" << p->m_Value << endl;
17     else    cout << "不存在!" << endl;
18     cout << "最大值:" <<getMaxValueFromBSTree(root)->m_Value << endl;
19     cout << "最小值:" <<getMinValueFromBSTree(root)->m_Value << endl;
20     cout << "2後繼結點值為:" << getSuccessorNode(root,searchBSTreeNode(root,2))->m_Value << endl;
21     cout << "3後繼結點值為:" << getSuccessorNode(root,searchBSTreeNode(root,3))->m_Value << endl;
22     cout << "4後繼結點值為:" << getSuccessorNode(root,searchBSTreeNode(root,4))->m_Value << endl;
23     cout << "6後繼結點值為:" << getSuccessorNode(root,searchBSTreeNode(root,6))->m_Value << endl;
24     cout << "7後繼結點值為:" << getSuccessorNode(root,searchBSTreeNode(root,7))->m_Value << endl;
25     cout << "9後繼結點值為:" << getSuccessorNode(root,searchBSTreeNode(root,9))->m_Value << endl;
26     cout << "13後繼結點值為:" << getSuccessorNode(root,searchBSTreeNode(root,13))->m_Value << endl;
27     cout << "15後繼結點值為:" << getSuccessorNode(root,searchBSTreeNode(root,15))->m_Value << endl;
28     cout << "17後繼結點值為:" << getSuccessorNode(root,searchBSTreeNode(root,17))->m_Value << endl;
29     cout << "18後繼結點值為:" << getSuccessorNode(root,searchBSTreeNode(root,18))->m_Value << endl;
30 
31 
32     cout << "3前驅結點值為:" << getPredecessorNode(root,searchBSTreeNode(root,3))->m_Value << endl;
33     cout << "4前驅結點值為:" << getPredecessorNode(root,searchBSTreeNode(root,4))->m_Value << endl;
34     cout << "6前驅結點值為:" << getPredecessorNode(root,searchBSTreeNode(root,6))->m_Value << endl;
35     cout << "7前驅結點值為:" << getPredecessorNode(root,searchBSTreeNode(root,7))->m_Value << endl;
36     cout << "9前驅結點值為:" << getPredecessorNode(root,searchBSTreeNode(root,9))->m_Value << endl;
37     cout << "13前驅結點值為:" << getPredecessorNode(root,searchBSTreeNode(root,13))->m_Value << endl;
38     cout << "15前驅結點值為:" << getPredecessorNode(root,searchBSTreeNode(root,15))->m_Value << endl;
39     cout << "17前驅結點值為:" << getPredecessorNode(root,searchBSTreeNode(root,17))->m_Value << endl;
40     cout << "18前驅結點值為:" << getPredecessorNode(root,searchBSTreeNode(root,18))->m_Value << endl;
41     cout << "20前驅結點值為:" << getPredecessorNode(root,searchBSTreeNode(root,20))->m_Value << endl;
42 
43     deleteNodeFromBSTreeNode(root,15);
44     inOrderVisitUseRecur(root);
45     cout << endl;
46     return 0;
47 }

  //以上程式碼全部本人手工敲上去的,如有錯誤請留言。如若轉載,請註明出處!