[C语言实现]实现二叉查找树基本操作(递归版,图示)

定义

二叉查找树是一种特殊的二叉树,它不仅是一颗二叉树,还满足如下性质

对于任何非叶子节点,他的左节点都小于它本身,而右节点都大于其本身.
它的左右子树也分别而二叉搜索树

一般情况下,在这么一棵树中进行查找,它的时间复杂度是 longn l o n g n
但是在最坏情况下,一棵树会退化成单链表,那么此时的查找时间复杂度就是 n n

实现

头文件

#pragma once
#include<stdio.h>
typedef char SearchTreeType;
typedef struct SearchTreeNode
{
  SearchTreeType key;
  struct SearchTreeNode* lchild;
  struct SearchTreeNode* rchild;
}SearchTreeNode;
void SearchTreeInit(SearchTreeNode** root,SearchTreeType key);
void SearchTreeInsert(SearchTreeNode** root, SearchTreeType key);
SearchTreeNode* SearchTreeFind(SearchTreeNode** root, SearchTreeType to_find);
SearchTreeNode* _SearchTreeRemove(SearchTreeNode* root, SearchTreeType to_delete);

插入的实现

插入肯定会插入在叶子节点,
我们比较将要插入的节点和当前节点的大小关系,
如果大于当前节点,就需要在它的右子树寻找合适的节点插入
如果小于当前节点,就要在它的左子树寻找何时的节点插入

void SearchTreeInsert(SearchTreeNode** root, SearchTreeType key)
{
  if(root == NULL)
    return;
  if(*root == NULL)
  {
    SearchTreeInit(root,key);
  }
  //递归插入
  _SearchTreeInsert_R(*root,key);
}
SearchTreeNode* _SearchTreeInsert_R(SearchTreeNode* root, SearchTreeType key)
{
  if(root == NULL)
  {
    root = (SearchTreeNode*)malloc(sizeof(SearchTreeNode));
    root->key = key;
    root->rchild = NULL;
    root->rchild = NULL;
  }
  if(key > root->key)
  {
    root->rchild = _SearchTreeInsert_R(root->rchild,key);
  }
  else if(key < root->key)
  {
    root->lchild = _SearchTreeInsert_R(root->lchild,key);
  }
  else if( key == root->key )
  {
    return root;
  }
  return root;
}

查找的实现

依然是一个比较的过程,查找节点比当前节点大,就在当前节点的右子树中继续查找
查找节点比当前节点小,就在其左子树进行查找
如果遇到了NULL,就表示查找失败.
代码很简单就不一一列举了.

删除的实现

删除就比较复杂了,因为在删除后还要保证这棵树是一个二叉查找树.
这里要分情况讨论

删除的是叶子节点

《[C语言实现]实现二叉查找树基本操作(递归版,图示)》

例如我们要删除的是3 ,那么我们就应该找到3的父节点5,将5的左子树置空即可
《[C语言实现]实现二叉查找树基本操作(递归版,图示)》

删除的节点的左子树为空

《[C语言实现]实现二叉查找树基本操作(递归版,图示)》
例如我们要删除的是3 ,那么我们就应该找到3的父节点5,将5的左子树指向 3的右子树,然后释放该节点
《[C语言实现]实现二叉查找树基本操作(递归版,图示)》

删除的节点右子树为空

《[C语言实现]实现二叉查找树基本操作(递归版,图示)》
同上一种情况,将找到3的父节点5,将5的左子树指向 3的左子树,然后释放该节点
《[C语言实现]实现二叉查找树基本操作(递归版,图示)》

删除节点左右子树都非空

《[C语言实现]实现二叉查找树基本操作(递归版,图示)》
这里我们有两种可能的方案
1. 在3的左子树中找到最大的节点(2.5) 将2.5和3调换位置,然后将置换后的3删除
《[C语言实现]实现二叉查找树基本操作(递归版,图示)》
2. 在3的右子树中找到最小节点(3.5),将2.5和3调换位置,然后将置换后的3删除
《[C语言实现]实现二叉查找树基本操作(递归版,图示)》

我们只要按这4种情况不重不漏的分析下去,代码就很好写了

SearchTreeNode* _SearchTreeRemove(SearchTreeNode* root, SearchTreeType to_delete)
{
  if(root == NULL)
    return NULL;
  if(root->key > to_delete)
  {
    root->lchild = _SearchTreeRemove(root->lchild,to_delete);  
  }
  if(root->key < to_delete)
  {
    root->rchild = _SearchTreeRemove(root->rchild,to_delete);
  }
  if(root->key == to_delete)
  {
    // root 是叶子节点
    if(root->lchild == NULL && root->rchild == NULL)
    {
      free(root);
      root = NULL;
      return NULL;
    }
    // root 非叶子节点 而且左子树为空,和右子树中最小元素交换,后删除找到的节点
    else if(root->lchild == NULL && root->rchild != NULL)
    {
      SearchTreeNode* to_return = root->rchild;
      free(root);
      root = NULL;
      return to_return;
    }
    // root 非叶子节点,右子树为空,和左子树中最大元素交换,后删除找到的节
    else if(root->rchild == NULL && root->lchild != NULL)
    {
      SearchTreeNode* to_return = root->lchild;
      free(root);
      root = NULL;
      return to_return;
    }
    // root 非叶子节点, 左子树中最大值和右子树中最大值 二选一交换 后删除找到的节
    else if(root->lchild != NULL && root->rchild != NULL)
    {
      //采用赋值法
      //在左子树取最大值
      SearchTreeNode* max = root->lchild;
      SearchTreeNode* max_parent = root->lchild; 
      while(max->rchild)
      {
        max_parent = max;
        max = max->rchild;
      }
      root->key = max->key;
      //左子树是叶子节点(特殊情况)
      if(max_parent == max)
      {
        free(max);
        max = NULL;
        root->lchild = NULL;
      }
      else 
      {
        //不用判断将左子树的最大值至为空
        free(max_parent->rchild);
        max_parent->rchild = NULL;
      }
      return root;
    }
  }
  return root;
}
    原文作者:二叉查找树
    原文地址: https://blog.csdn.net/kwinway/article/details/80380782
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞