1. 程式人生 > >查詢之二叉排序樹(Binary Sort Tree)及其C實現

查詢之二叉排序樹(Binary Sort Tree)及其C實現

大話資料結構學習筆記 - 查詢之二叉排序樹(Binary Sort Tree)及其C實現

二叉排序樹

Search_Binary_Search_Tree

二叉排序樹(Binary Sort Tree):又稱為 二叉查詢樹, 它或者是一個空樹,或者是具有下列性質的二叉樹

  • 若它的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值
  • 若它的右子樹不空,則右子樹上所有結點的值均大於它的根結點的值
  • 它的左、右子樹也分別為二叉排序樹

二叉排序樹主要是為了提高查詢和插入刪除關鍵字的速度

二叉樹結構

/* 二叉樹的二叉連結串列結點結構定義 */
typedef struct BiTNode         /* 結點結構 */
{
    int
data; /* 結點資料 */ struct BiTNode *lchild, *rchild; /* 左右孩子指標 */ }BiTNode, *BiTree;

查詢

/*
 * 遞迴查詢二叉排序樹 T 中是否存在 key, 指標 f 指向 T 的雙親, 其初始呼叫值是 NULL. 若查詢成功, 則指標 p 指向該資料元素結點, 並返回 TRUE
 * 否則 指標 p 指向查詢路徑上訪問的最後一個結點並返回 FALSE
 *
 */
Status SearchBST(BiTree T, int key, BiTNode *f, BiTNode **p)
{
    if
(!T) /* 查詢不成功 */ { *p = f; return FALSE; } else if(key == T->data) /* 查詢成功 */ { *p = T; return TRUE; } else if(key < T->data) return SearchBST(T->lchild, key, T, p); /* 在左子樹中繼續查詢 */ else return SearchBST(T->rchild, key, T, p); /* 在右子樹中繼續查詢 */
}

插入

/*
 * 當二叉排序樹 T 中不存在關鍵字等於 key 的資料元素時, 插入 key 並返回 TRUE, 否則返回 FALSE
 */
Status InsertBST(BiTree *T, int key)
{
    BiTNode *p, *s;
    if(!SearchBST(*T, key, NULL, &p))  /* 查詢不成功 */
    {
        s = CreateBiTNode(key);
        if(!p)
            *T = s;  /* 插入 s 為新的根節點 */
        else if(key < p->data)
            p->lchild = s;  /* 插入 s 為左孩子 */
        else
            p->rchild = s;  /* 插入 s 為右孩子 */
        return TRUE;
    }
    return FALSE;  /* 樹中已有關鍵字相同的結點, 不再插入 */
}

刪除

/*
 * 從二叉排序樹中刪除節點 p, 並重接它的左或右子樹
 */
Status Delete(BiTNode **p)
{
    BiTNode *q, *s;
    if((*p)->lchild == NULL)  /* 若右子樹為空,則只需重接它的左子樹 */
    {
        q = *p;
        *p = (*p)->rchild;
        free(q);
    }
    else if((*p)->rchild == NULL)  /* 若左子樹為空,則只需重接它的右子樹 */
    {
        q = *p;
        *p = (*p)->lchild;
        free(q);
    }
    else  /* 左右子樹均不空 */
    {
        q = *p;
        s = (*p)->lchild;  /* s 為其左子樹 */
        while(s->rchild)   /* 轉左,尋找其左子樹最右結點, 即尋找待刪結點的前驅 */
        {
            q = s;
            s = s->rchild;
        }
        (*p)->data = s->data;  /* s 指向被刪結點的直接前驅 */
        if(q != (*p))
            q->rchild = s->lchild;  /* 重接 q 的右子樹 */
        else
            q->lchild = s->lchild;  /* 重接 q 的左子樹 */
        free(s);
    }
    return TRUE;
}

/*
 * 若二叉排序樹 T 中存在關鍵字等於 key 的資料元素時, 則刪除該資料元素結點, 並返回 TRUE; 否則返回 FALSE.
 */
Status DeleteBST(BiTree *T, int key)
{
    if(!(*T))       /* 不存在關鍵字等於 key 的資料元素 */
        return FALSE;
    else if(key == (*T)->data)    /* 找到關鍵字等於 key 的資料元素 */
        return Delete(T);
    else if(key < (*T)->data)
        return DeleteBST(&(*T)->lchild, key);
    else
        return DeleteBST(&(*T)->rchild, key);
}

複雜度

Search_Binary_Search_Tree_time_complexity

若二叉排序樹比較平衡,即其深度與完全二叉樹相同,均為log2n+1,類似於上圖左圖 那麼查詢的時間複雜度就為O(logn), 近似於折半查詢。若插入序列以排好序,則最壞情況類似於上圖右圖,時間複雜度為O(n), 等同於順序查詢。

程式碼

結語

如上覆雜度分析,二叉排序樹的超照效能取決於二叉排序樹的形狀,但其形狀不確定,取決於輸入序列。如何構建一個平衡的二叉排序樹呢?請看下節文章 平衡二叉樹