C和指针学习总结之在链式二叉搜索树和静态数组二叉搜索树中删除一个值的比较

24 篇文章 2 订阅
8 篇文章 0 订阅

前言

本文主要总结一下如何在链式二叉树和数组二叉树中删除一个值。

源代码

  1. 在链式二叉树中删除一个值

l_t_del.c

/*
 - Delete a node from a linked binary search tree
 */
void delete(TREE_TYPE value)
{
    TreeNode *current;
    TreeNode **link;

    /*
     * First, locate the value. It must exist in the tree or this routine
     * will abort the program.
     */
    link = &tree;

    while ((current = *link) != NULL && value != current->value){
        if (value < current->value)
            link = &current->left;
        else
            link = &current->right;
    }
    assert(current != NULL);

    /*
     * We've found the value. See how many children it has.
     */
    if (current->left == NULL && current->right == NULL){
        /*
         * It is a leaf; no children to worry about!
         */
        *link = NULL;
        free(current);
    }
    else if (current->left == NULL || current->right == NULL){
        /*
         * The node has only one child, so the parent will simply
         * inherit it.
         */
        if (current->left != NULL)
            *link = current->left;
        else
            *link = current->right;
        free(current);
    }
    else {
        /*
         * The node has two children! Replace its value with the
         * largest value from its left subtree, and then delete that
         * node instead.
         */
        TreeNode *this_child;
        TreeNode *next_child;

        this_child = current->left;
        next_child = this_child->right;
        while (next_child != NULL){
            this_child = next_child;
            next_child = this_child->right;
        }

        /*
         * Delete the child and replace the current value with
         * this_child's value.
         */
        value = this_child->value;
        delete(value);
        current->value = value;
    }
}

主要分为4种情况进行处理:

  • 要删除的值未在树中找到,终止程序;
  • 找到要删除的值的位置,左右子节点为空。把指向该地址的指针变量设为NULL并释放内存空间。
  • 找到要删除的值的位置,左右子节点有一个非空。把指向该地址的指针变量设为它左或右子节点指向的地址,并释放原先指向的内存空间。
  • 找到要删除的值的位置,左右子节点都不为空。从它的左子节点中寻找最大的值,用该值替换要删除的值,并把存放最大值的内存空间释放。此时,原先要删除的值的位置存放的是它的左子节点中的最大值,而原先存放这个最大值的内存空间已被释放。
    最后一种情况存放那个最大值的结构体中,它的left指针可能指向NULL,也可能指向一个存放数据的地址。而它的right指针始终指向NULL,因为最大的值已被找到。
  1. 在静态数组形式的二叉搜索树中删除一个值

a_t_del.c

/*
 * Delete a node from an arrayed binary search tree
 */
void delete(TREE_TYPE value)
{
    int current;
    int left;
    int right;
    int left_subtree_empty;
    int right_subtree_empty;

    /*
     * First, locate the value. It must exist in the tree or this routine
     * will abort the program.
     */
    current = 1;

    while (tree[current] != value){
        if (value < tree[current])
            current = left_child(current);
        else
            current = right_child(current);
        assert(current < ARRAY_SIZE);
        assert(tree[current] != 0);
    }

    /*
     * We've found the value. If is is a leaf, simply set it to zero.
     * Otherwise, if its left subtree is not empty, replace the node's value
     * with the rightmost (largest) child from its left subtree, and then
     * delete that node. Otherwise, replace the value with the leftmost
     * (smallest) child from its right subtree, and delete that node.
     */
    left = left_child(current);
    right = right_child(current);
    left_subtree_empty = left > ARRAY_SIZE || tree[left] == 0;
    right_subtree_empty = right > ARRAY_SIZE || tree[right] == 0;

    if (left_subtree_empty && right_subtree_empty)
        /*
         * The value has no children; simply set it to zero.
         */
        tree[current] = 0;
    else {
        int this_child;
        int next_child;

        if (!left_subtree_empty){
            /*
             * The left subtree is nonempty. Find its rightmost
             * child.
             */
            this_child = left;
            next_child = right_child(this_child);

            while (next_child < ARRAY_SIZE
                   && tree[next_child] != 0){
                this_child = next_child;
                next_child = right_child(this_child);
            }
        }
        else {
            /*
             * The right subtree is nonempty. Find its leftmost
             * child.
             */
            this_child = right;
            next_child = left_child(this_child);

            while (next_child < ARRAY_SIZE
                   && tree[next_child] != 0){
                this_child = next_child;
                next_child = left_child(this_child);
            }
        }

        /*
         * Delete the child and replace the current value with
         * this_child's value.
         */
        value = tree[this_child];
        delete(value);
        tree[current] = value;
    }
}

主要分为3种情况进行处理:

  • 未在树中找到要删除的值,终止程序。
  • 在树中找到要删除的值的位置,没有左右子节点。把该位置设为0。
  • 在树中找到要删除的值的位置,有左右子节点。如果有左子节点则优先在左子节点中寻找最大值,并把该值复制到要删除的值的位置;如果没有左子节点则在右子节点中寻找最小值,并把该值复制到要删除的值的位置。

总结

这两种方式始终都是以二叉树的排序进行删除操作的,左子节点的值永远比父节点的值小,右子节点的值永远比父节点的值大。
在链式的删除中,可以随时释放节点的内存空间,需要插入时再分配。而数组则不行,始终占据着一块内存空间。
当要删除的节点有子节点时,数组需要进行的递归操作比较多,特别是当该子节点还有多个子节点时,链式需要进行的递归操作比较少,更多的是改变指针指向的地址即可。链式比数组在内存利用率和删除操作上效率更高。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程小老弟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值