資料結構樹之二分查詢樹
阿新 • • 發佈:2018-12-23
二叉查詢樹(Binary Search Tree),也稱有序二叉樹(ordered binary tree),排序二叉樹(sorted binary tree),是指一棵空樹或者具有下列性質的二叉樹:
- 若任意節點的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值;
- 任意節點的右子樹不空,則右子樹上所有結點的值均大於它的根結點的值;
- 任意節點的左、右子樹也分別為二叉查詢樹。
- 沒有鍵值相等的節點(no duplicate nodes)。
二叉查詢樹的性質:
二叉查詢樹本質上是一種二叉樹,所以上章講的二叉樹的性質他都有。
二叉查詢樹的思想:
二叉排序樹的查詢過程和次優
二叉查詢樹的操作:
/*二叉樹的鏈式定義*/
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 }
//以上程式碼全部本人手工敲上去的,如有錯誤請留言。如若轉載,請註明出處!