二叉排序树的基本操作

       二叉排序树也叫二叉查找树(BST);

        满足特性:左子树的结点值 <  根结点值  <  右子树的结点值。不管是左子树还是右子树都满足这个关系式。

 

二叉排序树的基本操作有:1、插入结点 2、查找结点  3、删除结点

1、插入结点:插入结点时为了保证二叉树的性质,我们必须要先查找插入的位置,再插入,下面是插入操作的代码:

// 插入结点
int insertNode(BSTree *root,int val){
    if(*root == NULL){
        *root = getNode(val);   // 获取结点

        if(*root == NULL) return 0;
        else return 1;
    }
    else if( (*root)->key == val ){
        return 0;  // 不能存在相同的元素
    }
    else if( (*root)->key > val){
        return insertNode( &(*root)->lChild,val );
    }
    else{
        return insertNode( &(*root)->rChild,val );
    }
}

2、查找结点(循环实现)

// 查
// // 循环实现
BSTNode* findNode(BSTNode *root,int val){
    while(root != NULL && root->key != val){
        if(root->key > val){
            root = root->lChild;
        }
        else{
            root = root->rChild;
        }
    }
    return root;
}

3、删除结点(重点,难点)

删除结点分三种情况:

(1)待删除的结点没有左右子树(叶子结点):因为删除叶子结点并不影响二叉排序树的特性,所以可以直接删除。

(2)待删除的结点只有左子树或者右子树(单分支结点):这时只需要将待删结点的中序前驱结点连到待删结点的非空子树域即可。

(3)待删除的节点含有左右子树(双分支结点),这时候需要用待删结点的中序前驱或者中序后继代替原来的结点。如下图

 要是不会找可以按中序遍历的方式找到。

中序前驱:在待删结点的左子树中,第一个右指针指向NULL的结点,它的右子树肯定为空。

中序后继:在待删结点的右子树中,第一个左指针指向NULL的结点,它的左子树肯定为空。

        

中序遍历序列:

20,     30 ,  50  ,   60     ,80,100,120,160,180,200;

因为他们的中中序遍历序列中的位置分别是待删结点的前驱和后继。

// 获取根结点的中序后继结点的值
int InGetNextNode(BSTNode *node,BSTNode *pre){
    BSTNode *temp = pre;  // 保存根节点

    while(node->lChild != NULL){
        pre = node;
        node = node->lChild;
    }

    if(temp == pre){
        pre->rChild = node->rChild;
    }
    else{
        pre->lChild = node->rChild;
    }

    int ans = node->key;
    free(node);
    node = NULL;
    return ans;
}
// 获取根结点的中序前驱结点的值
int InGetPreNode(BSTNode *node,BSTNode *pre){
    BSTNode *temp = pre; // 保存根结点
    while(node->rChild != NULL){
        pre = node;
        node = node->rChild;
    }
    if(temp == pre){
        pre->lChild = node->lChild;
    }
    else{
        pre->rChild = node->lChild;
    }

    int ans = node->key;
    free(node);
    node = NULL;
    return ans;
}

完整代码如下:

/** date : 22-22-25
 *  二叉排序树的基本操作
 */

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

// 二叉排序树的基本操作
typedef struct BSTNode{
    int key;
    struct BSTNode *lChild,*rChild;
}BSTNode,*BSTree;

int Count;
BSTNode *Pre = NULL;

// 获取结点
BSTNode *getNode(int val);

// 插入结点
int insertNode(BSTree *root,int val);


// 中序遍历二叉排序树
void visit(BSTNode *node);
void inOrder(BSTree root);

// 删除节点
int InGetNextNode(BSTNode *node,BSTNode *pre);
int InGetPreNode(BSTNode *node,BSTNode *pre);
int deleteNode(BSTree root,int val,int flag); // flag 表示标记, == 0 表示左孩子, == 1 表示右孩子

// 释放结点内存
void freeNode(BSTree root);

// // 循环实现
BSTNode* findNode(BSTNode *root,int val);

void test01();

int main(){
    test01();

    return 0;
}

void test01(){
    int nums[] = {50,100,30,20,90,99,88,78,66,21,9,12,120,110,150}; //
    int length = sizeof(nums) / sizeof(int);
    printf("length = %d\n",length);

    BSTNode *root = NULL;

    for(int i = 0;i < length;++i){
        insertNode(&root,nums[i]);
    }

    inOrder(root);
    printf("\n\n");

    int ret = deleteNode(root,50,0);
    if(ret == 0)
        printf("删除失败!!!\n\n");
    else
        printf("删除成功!!!\n\n");

    inOrder(root);

    Count = 0;
    freeNode(root);
    root = NULL;

    printf("\n释放了 %d 个结点!\n",Count);
}

// 获取结点
BSTNode *getNode(int val){
    BSTNode *node = (BSTNode *) malloc(sizeof(BSTNode));
    if(node == NULL) return NULL;
    node->key = val;

    node->lChild = node->rChild = NULL;
    return node;
}

// 插入结点
int insertNode(BSTree *root,int val){
    if(*root == NULL){
        *root = getNode(val);   // 获取结点

        if(*root == NULL) return 0;
        else return 1;
    }
    else if( (*root)->key == val ){
        return 0;  // 不能存在相同的元素
    }
    else if( (*root)->key > val){
        return insertNode( &(*root)->lChild,val );
    }
    else{
        return insertNode( &(*root)->rChild,val );
    }
}
// 中序遍历二叉排序树
void visit(BSTNode *node){
    if(node == NULL) return ;
    printf("%d\t",node->key);
}
void inOrder(BSTree root){
    if(root == NULL) return ;

    inOrder(root->lChild);
    visit(root);
    inOrder(root->rChild);
}

// 删除节点

// 获取根结点的中序后继结点的值
int InGetNextNode(BSTNode *node,BSTNode *pre){
    BSTNode *temp = pre;  // 保存根节点

    while(node->lChild != NULL){
        pre = node;
        node = node->lChild;
    }

    if(temp == pre){
        pre->rChild = node->rChild;
    }
    else{
        pre->lChild = node->rChild;
    }

    int ans = node->key;
    free(node);
    node = NULL;
    return ans;
}
// 获取根结点的中序前驱结点的值
int InGetPreNode(BSTNode *node,BSTNode *pre){
    BSTNode *temp = pre; // 保存根结点
    while(node->rChild != NULL){
        pre = node;
        node = node->rChild;
    }
    if(temp == pre){
        pre->lChild = node->lChild;
    }
    else{
        pre->rChild = node->lChild;
    }

    int ans = node->key;
    free(node);
    node = NULL;
    return ans;
}
int deleteNode(BSTree root,int val,int flag){
    if(root == NULL){
        return 0;
    }
    else if(root->key < val){
        Pre = root;
        return deleteNode(root->rChild,val,1);
    }
    else if(root->key > val){
        Pre = root;
        return deleteNode(root->lChild,val,0);
    }
    else{
        // 叶子结点
        if(root->lChild == NULL && root->rChild == NULL){
            if(Pre != NULL){
                if(flag == 1)
                    Pre->rChild = NULL;
                else
                    Pre->lChild = NULL;
            }

            free(root);
            root = NULL;
        }
        // 只有一个分支结点
        else if(root->lChild == NULL || root->rChild == NULL){
            if(root->lChild == NULL){
                if(flag == 1)  // 右指针
                    Pre->rChild = root->rChild;
                else
                    Pre->lChild = root->rChild;
            }
            else{
                if(flag == 1) // 右指针
                    Pre->rChild = root->lChild;
                else
                    Pre->lChild = root->lChild;
            }
            free(root);
            root = NULL;
        }
        // 含有两个分支的结点
        else{
            //int t = InGetPreNode(root->lChild,root);
            int t = InGetNextNode(root->rChild,root);

            root->key = t;  // 值替换
        }

        return 1;  // 删除成功
    }
}

// 释放结点内存
void freeNode(BSTree root){
    if(root == NULL) return ;

    freeNode(root->lChild);
    freeNode(root->rChild);

    free(root);
    root = NULL;

    ++ Count;
}

// 查
// // 循环实现
BSTNode* findNode(BSTNode *root,int val){
    while(root != NULL && root->key != val){
        if(root->key > val){
            root = root->lChild;
        }
        else{
            root = root->rChild;
        }
    }
    return root;
}

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值