1. 程式人生 > >二叉搜尋樹與平衡二叉樹

二叉搜尋樹與平衡二叉樹

 二叉搜尋樹(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;
}