zoukankan      html  css  js  c++  java
  • 二叉排序树

    二叉排序树(BST,Binary Sort Tree)具有这样的性质:对于二叉树中的任意节点,如果它有左子树或右子树,则该节点的数据成员大于左子树所有节点的数据成员,且小于右子树所有节点的数据成员。排序二叉树的中序遍历结果是从小到大排列的。

    二叉排序树的查找和插入比较好理解,主要来看一下删除时的情况。

    如果需要查找并删除如图8-6-8中的37, 51, 73,93这些在二叉排序树中是叶子的结点,那是很容易的,毕竟删除它们对整棵树来说,其他结点的结构并未受到影响。


    对于要删除的结点只有左子树或只有右子树的情况,相对也比较好解决。那就是结点删除后,将它的左子树或右子树整个移动到删除结点的位置即可,可以理解为独子继承父业。比如图8-6-9,就是先删除35和99两结点,再删除58结点的变化图,最终,整个结构还是一个二叉排序树。


    但是对于要删除的结点既有左子树又有右子树的情况怎么办呢?比如图8-6-10中的47结点若要删除了,它的两儿子和子孙们怎么办呢?


    前人总结的比较好的方法就是,找到需要删除的结点p的直接前驱(或直接后继)s,用s来替换结点p,然后再删除此结点s,如图8-6-12所示。

    注意:这里的前驱和后继是指中序遍历时的顺序。


    Deletion

    There are three possible cases to consider:

    Deleting a leaf (node with no children): Deleting a leaf is easy, as we can simply remove it from the tree.

    Deleting a node with one child: Remove the node and replace it with its child.

    Deleting a node with two children: Call the node to be deleted N. Do not delete N. Instead, choose either its in-order successor node or its in-

    order predecessor node, R. Replace the value of N with the value of R, then delete R.

    As with all binary trees, a node's in-order successor is the left-most child of its right subtree, and a node's in-order predecessor is the right-most 

    child of its left subtree. In either case, this node will have zero or one children. Delete it according to one of the two simpler cases above.


    下面来看代码:(参考《linux c 编程一站式学习》

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
     
    /*************************************************************************
        > File Name: binarysearchtree.h
        > Author: Simba
        > Mail: dameng34@163.com
        > Created Time: Sat 29 Dec 2012 06:05:55 PM CST
     ************************************************************************/

    #ifndef BST_H
    #define BST_H

    typedef struct node *link;
    struct node
    {
        unsigned char item;
        link left, right;
    };

    link search(link t, unsigned char key);
    link insert(link t, unsigned char key);
    link delete(link t, unsigned char key);
    void print_tree(link t);

    #endif



     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
     
    /*************************************************************************
        > File Name: binarysearchtree.c
        > Author: Simba
        > Mail: dameng34@163.com
        > Created Time: Sat 29 Dec 2012 06:08:08 PM CST
     ************************************************************************/

    #include<stdio.h>
    #include<stdlib.h>
    #include "binarysearchtree.h"

    static link make_node(unsigned char item)
    {
        link p = malloc(sizeof(*p));
        p->item = item;
        p->left = p->right = NULL;
        return p;
    }

    static void free_node(link p)
    {
        free(p);
    }

    link search(link t, unsigned char key)
    {
        if (!t)
            return NULL;
        if (t->item > key)
            return search(t->left, key);
        if (t->item < key)
            return search(t->right, key);
        /* if (t->item == key) */
        return t;
    }

    link insert(link t, unsigned char key)
    {
        if (!t)
            return make_node(key);
        if (t->item > key) /* insert to left subtree */
            t->left = insert(t->left, key);
        else /* if (t->item <= key), insert to right subtree */
            t->right = insert(t->right, key);
        return t;
    }


    link delete(link t, unsigned char key)
    {
        link p;
        if (!t)
            return NULL;
        if (t->item > key) /* delete from left subtree */
            t->left = delete(t->left, key);
        else if (t->item < key) /* delete from right subtree */
            t->right = delete(t->right, key);
        else   /* if (t->item == key) */
        {
            if (t->left == NULL && t->right == NULL)
            {
                /* if t is a leaf node */
                free_node(t);
                t =  NULL;
            }
            else if (t->left)  /* if t has left subtree */
            {
                /* replace t with the rightmost node in left subtree */
                for (p = t->left; p->right; p = p->right);
                t->item = p->item; /* 将左子树下最靠右的节点值赋予想要删除的节点 */
                t->left = delete(t->left, t->item); 
            }
            
            else  /* if t has right subtree */
            {
                /* replace t with the leftmost node in right subtree */
                for (p = t->right; p->left; p = p->left);
                t->item = p->item;
                t->right = delete(t->right, t->item);
            }
        }
        return t;
    }

    void print_tree(link t)
    {
        if (t)
        {
            printf("(");
            printf("%d", t->item);
            print_tree(t->left);
            print_tree(t->right);
            printf(")");
        }
        else
            printf("()");
    }



     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
     
    /*************************************************************************
        > File Name: main2.c
        > Author: Simba
        > Mail: dameng34@163.com
        > Created Time: Sat 29 Dec 2012 06:22:57 PM CST
     ************************************************************************/

    #include<stdio.h>
    #include<stdlib.h>
    #include<time.h>
    #include "binarysearchtree.h"

    #define RANGE 100
    #define N 6

    void print_item(link p)
    {
        printf("%d", p->item);
    }

    int main(void)
    {
        int i, key;
        link root = NULL;
        srand(time(NULL));
        for (i = 0; i < N; i++)
        {
            root = insert(root, rand() % RANGE); /* 第一次循环root从NULL变成根节点值,接下去
                                                    的循环虽然迭代root,但在插入节点过程中root的值始终不变 */
            printf("root = 0x%x ", (unsigned int)root);
        }

        printf(" \tree");
        print_tree(root);
        printf(" ");

        while (root)
        {
            key = rand() % RANGE;
            if (search(root, key))
            {
                printf("delete %d in tree ", key);
                root = delete(root, key); /* root虽然迭代,但返回的仍是先前的值,即根节点的值保持不变
                                             直到全部节点被删除,root变成NULL即0x0 */
                printf("root = 0x%x ", (unsigned int)root);

                printf(" \tree");
                print_tree(root); /* 传递给函数的一直是根节点的值,直到树清空,root变成NULL */
                printf(" ");
            }
        }
        return 0;
    }


    输出为:



    如果我们使用了The Tree Preprocessor,可以将以括号展示的排序二叉树转换成树形展示,如下图



    以前此工具可以在 http://www.essex.ac.uk/linguistics/clmt/latex4ling/trees/tree/ 下载,现已找不到链接,我将其上传到csdn,需要的可以去下载。

    http://download.csdn.net/detail/simba888888/5334093


    最后提一下,我们希望构建出来的二叉排序树是比较平衡的,即其深度与完全二叉树相同,那么查找的时间复杂度研究度O(logn),近似于折半查找,

    但如果出现构造的树严重不平衡,如完全是左斜树或者右斜树,那么查找时间复杂度为O(n),近似于顺序查找。那如何让二叉排序树平衡呢?

    事实上还有一种平衡二叉树(AVL树),也是一种二叉排序树,其中每个结点的左子树和右子树的高度差至多等于1。


    补充:delete() 在《data structure and algorithm analysis in c》 中的实现,个人觉得比较清晰,也挺好理解的,如下:

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
     
    link FindMin(link T)
    {
        if (T != NULL)
            while (T->left != NULL)
                T = T->left;

        return T;
    }

    link delete(unsigned char X, link T)
    {
        link tmp;
        if (T == NULL)
        {
            printf("Tree is empty! ");
            return NULL;
        }

        if (X < T->key) //go left
            T->left = delete(X, T->left);
        else if (X > T->key) // go right
            T->right = delete(X, T->right);

        /* found elem to be deleted*/
        else if (T->left && T->right) //have two children
        {
            // replace with smallest in right subtree
            tmp = FindMin(T->right);
            T->key = tmp->key;
            T->right = delete(T->key, T->right);
        }
        else //one or zero children
        {
            tmp = T;
            if (T->left == NULL)
                T = T->right;
            else if (T->right == NULL)
                T = T->left;
            free(tmp);
        }

        return T;
    }


    参考:

    《大话数据结构》

    《linux c 编程一站式学习》

    《Data Structures》

  • 相关阅读:
    Excel表格函数逻辑排错
    MobaXterm体验最好的SSH客户端
    Excel中的常用函数
    Shell 知识点2020
    Linux 知识点2020
    Python知识点2020
    es6 模版字符串
    es6对象定义简写
    es6解构赋值
    ES6 let const关键字
  • 原文地址:https://www.cnblogs.com/alantu2018/p/8471854.html
Copyright © 2011-2022 走看看