二叉搜索树的基本操作

  • 二叉搜索树又称二叉排序树,具有以下性质:

    1.若它的左子树不为空,则左子树上所有节点的值均小于根节点的值;

    2.若它的右子树不为空,则右子树上所有节点的值均大于根节点的值。

如下图所示结构即为一个二叉搜索树:

                

  • 二叉搜索树的基本操作:
#pragma once

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

typedef char SearchNodeType;

typedef struct SearchNode{
    SearchNodeType data;
    struct SearchNode* lchild;
    struct SearchNode* rchild;
}SearchNode;

SearchNode* CreateSearchNode(SearchNodeType value);
void SearchTreeInit(SearchNode** pRoot);
void SearchTreeDestroy(SearchNode** pRoot);
void DestroySearchNode(SearchNode* node);
void SearchTreeInsert(SearchNode** pRoot,SearchNodeType to_insert);
SearchNode* SearchTreeFind(SearchNode* root,SearchNodeType to_find);
void SearchTreePrintChar(SearchNode* root,const char* msg);
void PreOrder(SearchNode* root);
void InOrder(SearchNode* root);
void SearchTreeRemove(SearchNode** pRoot,SearchNodeType to_remove);
void SearchTreeInsert1(SearchNode** pRoot,SearchNodeType to_insert);
SearchNode* SearchTreeFind1(SearchNode* root,SearchNodeType to_find);
void SearchTreeRemove1(SearchNode** pRoot,SearchNodeType to_remove);

1.初始化

void SearchTreeInit(SearchNode** pRoot){
    if(pRoot == NULL)
        return;
    *pRoot = NULL;
    return;
}

2.创建新节点

SearchNode* CreateSearchNode(SearchNodeType value){
    SearchNode* new_node = (SearchNode*)malloc(sizeof(SearchNode));
    new_node->data = value;
    new_node->lchild = NULL;
    new_node->rchild = NULL;
    return new_node;
}

3.销毁节点

void DestroySearchNode(SearchNode* node){
    free(node);
}

4.销毁树

void SearchTreeDestroy(SearchNode** pRoot){
    if(pRoot == NULL)
        return;
    SearchNode* root = *pRoot;
    SearchTreeDestroy(&root->lchild);
    SearchTreeDestroy(&root->rchild);
    DestroySearchNode(root);
    *pRoot = NULL;
    return;
}

5.往二叉搜索树中插入数据

(1)递归版本

void SearchTreeInsert(SearchNode** pRoot,SearchNodeType to_insert){
    if(pRoot == NULL)//非法输入
        return;
    if(*pRoot == NULL){//空树
        SearchNode* new_node = CreateSearchNode(to_insert);
        *pRoot = new_node;
        return;
    }
    //对于树非空的情况,递归插入
    SearchNode* cur = *pRoot;
    if(to_insert < cur->data){//若要插入的数据小于根节点的值,则往左子树中插入
        SearchTreeInsert(&cur->lchild,to_insert);
    }
    else if(to_insert > cur->data){//若要插入的数据大于根节点的值,则往右子树中插入
        SearchTreeInsert(&cur->rchild,to_insert);
    }
    else{//插入的元素与根节点的值相同
        //约定二叉搜索树中所有元素均不重复,返回表示不作任何动作,插入失败
        return;
    }
}

(2)非递归版本

void SearchTreeInsert1(SearchNode** pRoot,SearchNodeType to_insert){
    if(pRoot == NULL)
        return;
    if(*pRoot == NULL){//单独处理空树的情况
        *pRoot = CreateSearchNode(to_insert);
        return;
    }
    //对于非空的树,先找到插入的位置,把要插入元素的父节点记录下来
    SearchNode* cur = *pRoot;//新元素要放置的位置
    SearchNode* pre = NULL;//新元素的父节点
    while(1){
        if(cur == NULL)//找到插入的位置,跳出循环
            break;
        if(to_insert < cur->data){
            pre = cur;
            cur = cur->lchild;
        }
        else if(to_insert > cur->data){
            pre = cur;
            cur = cur->rchild;
        }
        else{//发现相同的元素,按约定:二叉搜索树中的所有元素均不重复,直接插入失败
            return;
        }
    }
    SearchNode* new_node = CreateSearchNode(to_insert);
    if(new_node->data < pre->data){
       pre->lchild = new_node; 
    }
    else{
        pre->rchild = new_node;
    }
    return;
}

6.在二叉搜索树中查找数据

(1)递归版本

SearchNode* SearchTreeFind(SearchNode* root,SearchNodeType to_find){
    if(to_find < root->data){//递归查找左子树
        return SearchTreeFind(root->lchild,to_find);
    }
    else if(to_find > root->data){//递归查找右子树
        return SearchTreeFind(root->rchild,to_find);
    }
    else{
        return root;
    }
}

(2)非递归版本

SearchNode* SearchTreeFind1(SearchNode* root,SearchNodeType to_find){
    SearchNode* cur = root;
    while(1){
        if(cur == NULL)//空树
            return NULL;
        if(to_find < cur->data){
            cur = cur->lchild;
        }
        else if(to_find > cur->data){
            cur = cur->rchild;
        }
        else{
            break;
        }
    }
    return cur;
}

7.打印二叉搜索树

void PreOrder(SearchNode* root){
    if(root == NULL)
        return;
    printf("%c ",root->data);
    PreOrder(root->lchild);
    PreOrder(root->rchild);
    return;
}

void InOrder(SearchNode* root){
    if(root == NULL)
        return;
    InOrder(root->lchild);
    printf("%c ",root->data);
    InOrder(root->rchild);
    return;
}

void SearchTreePrintChar(SearchNode* root,const char* msg){
    printf("[%s]\n",msg);
    printf("先序遍历:");
    PreOrder(root);
    printf("\n");
    printf("中序遍历:");
    InOrder(root);
    printf("\n");
    return;
}

8.删除二叉搜索树中的数据

(1)递归版本

void SearchTreeRemove(SearchNode** pRoot,SearchNodeType to_remove){
    if(pRoot == NULL)//非法输入
        return;
    if(*pRoot == NULL)//空树
        return;
    SearchNode* root = *pRoot;
    if(to_remove <  root->data){//递归查找左子树
        SearchTreeRemove(&root->lchild,to_remove);
        return;
    }
    else if(to_remove >  root->data){//递归查找右子树
        SearchTreeRemove(&root->rchild,to_remove);
        return;
    }
    else{//分情况讨论
        if(root->lchild == NULL && root->rchild == NULL){//要删除的节点无左右子树
            *pRoot = NULL;
            DestroySearchNode(root);
            return;
        }
        else if(root->lchild != NULL && root->rchild == NULL){//要删除的节点只有左子树
            *pRoot = root->lchild;
            DestroySearchNode(root);
            return;
        }
        else if(root->lchild == NULL && root->rchild != NULL){//要删除的节点只有右子树
            *pRoot = root->rchild;
            DestroySearchNode(root);
            return;
        }
        else{//要删除的节点有左右子树
            SearchNode* min = root->rchild;
            while(min->lchild != NULL){//先找到右子树中的最小节点
                min = min->lchild;
            }
            root->data = min->data;//将要删除的节点的值与最小节点的值交换
            SearchTreeRemove(&root->rchild,min->data);//从当前节点的右子树出发,尝试递归的删除刚刚被交换的值
            return;
        }
    }
    return;
}

(2)非递归版本

void SearchTreeRemove1(SearchNode** pRoot,SearchNodeType to_remove){
    if(pRoot == NULL)
        return;
    if(*pRoot == NULL)
        return;
    //先找到要删除的节点
    SearchNode* to_remove_node = *pRoot;
    SearchNode* parent = NULL;
    while(to_remove_node != NULL){
        if(to_remove < to_remove_node->data){
            parent = to_remove_node;
            to_remove_node = to_remove_node->lchild;
        }
        else if(to_remove > to_remove_node->data){
            parent = to_remove_node;
            to_remove_node = to_remove_node->rchild;
        }
        else{//找到了要删除的节点
            break;
        }
    }
    //若找到,分情况:
    if(to_remove_node->lchild == NULL && to_remove_node->rchild == NULL){//左右子树均为空
        if(to_remove_node == *pRoot)//根节点即为要删除的节点
            *pRoot = NULL;
        else{//根节点不是要删除的节点
            if(to_remove_node->data < parent->data)
                parent->lchild = NULL;
            else
                parent->rchild = NULL;
        }
        DestroySearchNode(to_remove_node);
    }
    else if(to_remove_node->lchild != NULL && to_remove_node->rchild == NULL){//只有左子树
         if(to_remove_node == *pRoot)
            *pRoot = to_remove_node->lchild;
        else{
            if(to_remove_node->data < parent->data)
                parent->lchild = to_remove_node->lchild;
            else
                parent->rchild = to_remove_node->lchild;
        }
        DestroySearchNode(to_remove_node);
    }
    else if(to_remove_node->lchild == NULL && to_remove_node->rchild != NULL){//只有右子树
         if(to_remove_node == *pRoot)
            *pRoot = to_remove_node->rchild;
        else{
            if(to_remove_node->data < parent->data)
                parent->lchild = to_remove_node->rchild;
            else
                parent->rchild = to_remove_node->rchild;
        }
        DestroySearchNode(to_remove_node);
    }
    else{//同时有左右子树
        SearchNode* min = to_remove_node->lchild;
        SearchNode* min_parent = to_remove_node;
        while(min->lchild != NULL){
            min_parent = min;
            min = min->lchild;
        }//循环结束,min指向to_remove_node右子树的最小值
        to_remove_node->data = min->data;
        if(min->data < min_parent->data)//min为min_parent的左子树
            min_parent->lchild = min->rchild;
        else//min为min_parent的右子树
            min_parent->rchild = min->rchild;
        DestroySearchNode(min);
        return;
    }
    return;
}

  • 测试函数:
#include"search.h"

#define PRINT_HEAD printf("\n============%s============\n",__FUNCTION__);

void TestInit(){
    PRINT_HEAD;
    SearchNode** pRoot = NULL;
    SearchTreeInit(pRoot);
    printf("pRoot expect NULL,actual %p\n",pRoot);
    return;
}

void TestInsert(){
    PRINT_HEAD;
    SearchNode* root = NULL;
    SearchTreeInit(&root);
    SearchTreeInsert(&root,'a');
    SearchTreeInsert(&root,'d');
    SearchTreeInsert(&root,'b');
    SearchTreeInsert(&root,'e');
    SearchTreeInsert(&root,'c');
    SearchTreeInsert(&root,'f');
    SearchTreePrintChar(root,"插入六个元素");
    return;
}

void TestFind(){
    PRINT_HEAD;
    SearchNode* root = NULL;
    SearchTreeInit(&root);
    SearchTreeInsert(&root,'a');
    SearchTreeInsert(&root,'d');
    SearchTreeInsert(&root,'b');
    SearchTreeInsert(&root,'e');
    SearchTreeInsert(&root,'c');
    SearchTreeInsert(&root,'f');
    SearchNode* ret = SearchTreeFind(root,'c');
    printf("ret expect c,actual %c\n",*ret);
}

void TestRemove(){
    PRINT_HEAD;
    SearchNode* root = NULL;
    SearchTreeInit(&root);
    SearchTreeInsert(&root,'a');
    SearchTreeInsert(&root,'d');
    SearchTreeInsert(&root,'b');
    SearchTreeInsert(&root,'e');
    SearchTreeInsert(&root,'c');
    SearchTreeInsert(&root,'f');
    SearchTreePrintChar(root,"插入六个元素");
    SearchTreeRemove(&root,'c');
    SearchTreePrintChar(root,"删除一个元素");
    return;
}

void TestInsert1(){
    PRINT_HEAD;
    SearchNode* root = NULL;
    SearchTreeInit(&root);
    SearchTreeInsert(&root,'a');
    SearchTreeInsert(&root,'d');
    SearchTreeInsert(&root,'b');
    SearchTreeInsert(&root,'e');
    SearchTreeInsert(&root,'c');
    SearchTreeInsert(&root,'f');
    SearchTreePrintChar(root,"插入六个元素");
    return;
}

void TestFind1(){
    PRINT_HEAD;
    SearchNode* root = NULL;
    SearchTreeInit(&root);
    SearchTreeInsert(&root,'a');
    SearchTreeInsert(&root,'d');
    SearchTreeInsert(&root,'b');
    SearchTreeInsert(&root,'e');
    SearchTreeInsert(&root,'c');
    SearchTreeInsert(&root,'f');
    SearchNode* val = SearchTreeFind(root,'c');
    printf("val expect c,actual %c\n",*val);
}

void TestRemove1(){
    PRINT_HEAD;
    SearchNode* root = NULL;
    SearchTreeInit(&root);
    
    SearchTreeInsert(&root,'d');
    SearchTreeInsert(&root,'b');
    SearchTreeInsert(&root,'f');
    SearchTreeInsert(&root,'a');
    SearchTreeInsert(&root,'c');
    SearchTreeInsert(&root,'e');
    SearchTreeInsert(&root,'g');
    SearchTreePrintChar(root,"插入六个元素");
    SearchTreeRemove(&root,'c');
    SearchTreePrintChar(root,"删除一个元素");
    return;
}

int main(){
    TestInit();
    TestInsert();
    TestFind();
    TestRemove();
    TestInsert1();
    TestFind1();
    TestRemove1();
    return 0;
}

  • 结果演示:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值