1. 程式人生 > >二叉搜尋樹的原始碼分析學習 筆記(基礎版)

二叉搜尋樹的原始碼分析學習 筆記(基礎版)

二叉搜尋樹結構

typedef struct bst_tree_node
{
    type key;
    struct bst_tree_node * left;
    struct bst_tree_node * right;
    struct bst_tree_node * parent;
} node, * bst_tree;
有了二叉搜尋樹的儲存結構,那麼就應該知道怎麼建立

先建立一個結點

static node * create_bstree_node (type key, node * parent, node * left, node * right)
{
    node *
p; if((p = (node * ) malloc(sizeof(node))) == NULL) return NULL; p->key = key; p->left = left; p->right = right; p->parent = parent; return p; }

建立好結點後,再插入到樹中。插入的基本要求要保持二叉搜尋樹的屬性不能被破壞

/**
 * 演算法理解方式是找準位置,然後插入。哈哈,很有意思。切記:找準位置最重要
 */
// tree是根結點 z是插入結點
static node *
bstree_insert(bst_tree tree, node * z) { node * y = NULL; node * x = tree; //迴圈找到適合插入的葉子結點位置 while(x != NULL) { y = x; if(z->key < x->key) x = x->left; else if(z->key > x->key) x = x->right; else {
free(z); //如果相同key值結點,釋放此結點不執行插入 return tree; } } //找到合適的位置後,再插入結點 z->parent = y; if(y == NULL) tree=z; else if(z->key < y->key) y->left = z; else y->right = z; return tree; }

二叉搜尋樹建立好了後,要開始遍歷,下面是三種遍歷方式。函式的形參是二叉搜尋樹的根節點指標。

//先序遍歷方式
void preorder_bsttree(bst_tree tree)
{
    if(tree != NULL)
    {
        printf("%d ", tree->key);
        preorder_bsttree(tree->left);
        preorder_bsttree(tree->right);
    }
}
//中序遍歷方式
void inorder_bstree(bst_tree tree)
{
    if(tree != NULL)
    {
        inorder_bstree(tree->left);
        printf("%d ", tree->key);
        inorder_bstree(tree->right);
    }
}
//後序遍歷方式
void postorder_bstree(bst_tree tree)
{
    if(tree != NULL)
    {
        postorder_bstree(tree->left);
        postorder_bstree(tree->right);
        printf("%d ", tree->key);
    }
}

根據一個值key查詢到對應的結點方法

/**
 * 根據值 key,查詢對應的結點並返回對應的地址
 * 第一步要判斷這個值 key是否合法,當然了這個是很簡單的
 * 下面一步就體現出二叉搜尋樹的特點了
 *      第一步到根節點,key如果大於根節點那麼到右結點下面去比較
 *                     key如果小於根節點那麼到左結點下面去比較
 *      就是這樣執行下去知道結點為空為止
 */
node * bstree_search(bst_tree tree, type key)
{
    if(tree == NULL || tree->key == key)
        return tree;

    if(key < tree->key)
        return bstree_search(tree->left, key);
    else
        return bstree_search(tree->right, key);
}

取得二叉搜尋樹中某個結點的後繼結點存在兩種情況

  • x右子樹不為空,那麼它的後繼結點就是右子樹中最小的一個
  • 如果x結點在根節點的左子樹中 且x結點是一個右子結點不含右子結點(下圖的13結點) 。那麼它的後繼結點就是x的最低父親結點(最低父親結點的條件是:父親結點的左結點等於x)
//查詢某個結點的後繼結點 比如 1 2 3 4 5,查詢3的後繼結點就是4
node * bstree_successor(node * x)
{
    //如果x存在右子樹,則"x的後繼結點"為 "以其右孩子為根的子樹的最小結點"
    if(x->right != NULL)
        return bstree_minimum(x->right);

    //如果x沒有右子樹
    //x是一個左孩子,則x的後繼節點為他的父親結點
    //x是一個右孩子,則x的最低父親結點,並且該父親結點的左結點等於x
    node * y = x->parent;
    while((y!=NULL) && (x == y->right))
    {
        x=y;
        y = y->parent;
    }
    return y;
}

/**
 * 二叉搜尋樹是一個很有意思的東西,
 *  如果要尋找是最大的結點,那麼就在右子樹裡尋找,如果右子樹為空,那麼就是當前的根節點
 *  同理:如果要尋找是最小的結點,那麼就在左子樹裡尋找,如果左子樹為空,那麼就是當前的根節點
 */
//左子樹最左一個結點值是最小的一個結點
node * bstree_minimum(bst_tree tree)
{
    if(tree == NULL)
        return NULL;
    while(tree->left != NULL)
        tree = tree->left;
    return tree;
}
//右子樹最右的一個結點值是最大的一個結點
node * bstree_maximum(bst_tree tree)
{
    if(tree == NULL)
        return NULL;
    while(tree->right != NULL)
        tree= tree->right;
    return tree;
}