二叉搜尋樹與平衡二叉樹
二叉搜尋樹(BST)
二叉搜尋樹也是一種樹,適用與一般二叉樹的全部操作,但二叉搜尋樹能夠實現資料的快速查詢
性質:
非空左子樹的所有鍵值小於其根節點的鍵值
非空右子樹的所有鍵值大於其根節點的鍵值
左右子樹都是二叉搜尋樹
二叉搜尋樹的插入、查詢、刪除
刪除主要分三種情況來討論:
(1)要刪除的是葉子結點:直接刪除
(2)要刪除的節點只有一個孩子節點:將其父節點的指標指向要刪除節點的孩子節點
(3)要刪除的節點有左、右兩顆子樹:
用另一個結點替代被刪除結點:右子樹的最小元素或者左子樹的最大元素
其中刪除操作的程式碼較複雜,暫未給出。
平衡二叉樹(AVL樹)(此處的AVL起源於一個發現者的人名)
以上已經知道一個數組二分查詢的演算法,可以以二叉查詢樹來實現,但一般該二叉查詢樹的效率比不上/陣列的二分查詢
這是由於二叉查詢樹是不平衡的。。要想縮短一個二叉搜尋樹的查詢時間,需要將二叉查詢樹調整為平衡二叉樹。
衡量二叉搜尋樹搜尋效率的標準:平均查詢長度(ASL):每個結點比較次數和/結點數
平衡因子(BF):左子樹的高度減去右子樹的高度。
判斷一個二叉搜尋樹是否為一個平衡二叉樹:|BF|小於等於1
當對一個平衡二叉樹插入一個結點後,AVL樹就變的不平衡了
平衡二叉樹的調整:分為四種情況
(1)多餘點在樹的不平衡子樹的根結點的右子樹的右邊:RR插入,需要RR旋轉
(2)多餘點在樹的不平衡子樹的根結點的左子樹的左邊:LL插入,需要LL旋轉
(3)多餘點在樹的不平衡子樹的根結點的右子樹的左邊:RL插入,需要RL旋轉
(3)多餘點在樹的不平衡子樹的根結點的左子樹的右邊:LR插入,需要LR旋轉
平衡二叉樹的程式碼後續會給出
以下程式碼實現了二叉樹 的插入、查詢操作。。並給出了一個《劍指offer》上的一道筆試題:查詢一個二叉搜尋樹中第k小的元素。
#include <iostream> #include <stack> using namespace std; typedef int ElementType; typedef struct TreeNode{ ElementType val; struct TreeNode *left; struct TreeNode *right; TreeNode(ElementType x) : val(x),left(NULL),right(NULL){} }Node, *BST; int count=1; /*插入的方式建立一個二叉搜尋樹*/ BST Insert(ElementType x,BST bst) { if(bst==NULL){ bst = new Node(x); bst->left = NULL; bst->right = NULL; } else{ if(x<bst->val) bst->left = Insert(x,bst->left); else bst->right = Insert(x,bst->right); } return bst; } /*查詢二叉搜尋樹中的某個元素,並返回該結點*/ BST Find(BST bst, ElementType num) { if(!bst) return NULL; if(num < bst->val) return Find(bst->left,num); else if(num > bst->val) return Find(bst->right,num); else return bst; //return bst; } /*查詢第k小的元素!採用前序遍歷遞迴方法,當遍歷到第k小的數時返回該節點(非空),並讓程式逐級返回----此處不易理解*/ BST KthNode(BST bst, int k) { if(bst==NULL) return NULL; BST left = KthNode(bst->left,k); if(left!=NULL) return left; if(count==k) return bst; count++; BST right = KthNode(bst->right,k); if(right!=NULL) return right; return NULL; } //中序遍歷 void inorderTraverse(BST bst) { if(bst) { cout << bst->val << " "; inorderTraverse(bst->left); inorderTraverse(bst->right); } } //前序遍歷---只有二叉搜尋樹的中序遍歷輸出的結果從小到大排列,後序遍歷並不是從大到小排列 void preorderTraverse(BST bst) { if(bst) { preorderTraverse(bst->left); cout << bst->val << " "; preorderTraverse(bst->right); } } int main() { BST bst = NULL; bst = Insert(5,bst); bst = Insert(3,bst); bst = Insert(6,bst); bst = Insert(2,bst); bst = Insert(4,bst); bst = Insert(7,bst); inorderTraverse(bst); cout << endl; preorderTraverse(bst); cout << endl; Node* Knode = KthNode(bst, 5); cout << Knode->val << endl; Node* Fnode = Find(bst,4); cout << Fnode->val << endl; }