数据结构之二叉搜索树的基本操作

二叉搜索树

二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。

以上摘录自百度百科,简单来说,二叉搜索树就是任意一棵树,右子树最大,接下来是根节点,最后是左子树。
这里写图片描述
所以在二叉搜索树里面查找某一个元素可以说是非常简单了。

基本操作

首先二叉搜索树,也是二叉树。所以它应该有最基本的一些操作。这里主要是创建子树,初始化二叉树,打印等。

//定义二叉树结构体,孩子表示法
typedef char SearchTreeType;

typedef struct SearchTreeNode {
  SearchTreeType data;
  struct SearchTreeNode* lchild;
  struct SearchTreeNode* rchild;
} SearchTreeNode;


//初始化二叉搜索树
void SearchTreeInit(SearchTreeNode** pRoot); //初始化二叉搜索树
//实现
void SearchTreeInit(SearchTreeNode** pRoot) //初始化二叉搜索树
{
  if(pRoot == NULL) {
    return;//非法输入
  }
  *pRoot = NULL;
  return;
}

//创建子树
//实现
SearchTreeNode* CreatTreeNode(SearchTreeType node) 
{
  SearchTreeNode* new_node = (SearchTreeNode*)malloc(sizeof(SearchTreeNode));
  new_node->data = node;
  new_node->lchild = NULL;
  new_node->rchild = NULL;
  return new_node;
}

//打印二叉搜索树,便于调试
//实现
void PreOrder(SearchTreeNode* root)//先序
{
  if(root == NULL) {
    return;
  }
  printf("%c ", root->data);
  PreOrder(root->lchild);
  PreOrder(root->rchild);
}

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

void SearchTreePrintChar(SearchTreeNode* root) 
{
  if(root == NULL) {
    return;
  }
  PreOrder(root);
  printf("\n");
  InOrder(root);
  printf("\n");
  return;
}

//销毁二叉搜索树
//实现
void DestroyNode(SearchTreeNode** pRoot)
{
  free(*pRoot);
  *pRoot = NULL;
}

void SearchDestroy(SearchTreeNode** pRoot)//销毁二叉搜索树
{
  if(pRoot == NULL) {
    return;
  }
  if(*pRoot == NULL) {
    return;
  }
  SearchTreeNode* root = *pRoot;
  SearchDestroy(&root->lchild);
  SearchDestroy(&root->rchild);
  DestroyNode(&root);
  return;
}


查找

//实现,递归版本的查找二叉搜索树
SearchTreeNode* SearchTreeFind(SearchTreeNode* root, 
                               SearchTreeType to_find) //查找二叉搜索树
{
  if(root == NULL) {
    return NULL;
  }
  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;
  }
}
//非递归版本的查找二叉搜索树
SearchTreeNode* SearchTreeFindByLoop(SearchTreeNode* root, 
                               SearchTreeType to_find) //非递归版本查找二叉搜索树
{
  if(root == NULL) {
    return NULL;
  }
  while(root != NULL) {
    if(to_find > root->data) {
      root = root->rchild;
    } else if(to_find < root->data){
      root = root->lchild;
    } else {
      return root;
    }
  }
  return NULL;
}

插入

二叉搜索树的插入过程,就是一个遍历的过程。因为插入前后都要保证二叉搜索树本身的性质。所以在插入的时候应该判断插入点。所以可以用要插入的元素与二叉搜索树内部元素比较。如果比根节点小,那么再继续与根节点左子树比较,如果大,与根节点右子树比较。直至到一个合适的位置插入。

//递归实现插入
void SearchTreeInsert(SearchTreeNode** pRoot, SearchTreeType to_insert)//二叉搜索树插入
{
  if(pRoot == NULL) {
    return;
  }
  if(*pRoot == NULL) {
    *pRoot = CreatTreeNode(to_insert);
    return;
  }
  SearchTreeNode* root = *pRoot;
  if(to_insert < root->data) {
    SearchTreeInsert(&root->lchild, to_insert);
  } if(to_insert > root->data) {
    SearchTreeInsert(&root->rchild, to_insert);
  } else {
    return;
  }
}

//非递归版本的插入
void SearchTreeInsertByLoop(SearchTreeNode** pRoot, SearchTreeType to_insert)//非递归版本二叉搜索树插入
{
  if(pRoot == NULL) {
    return;
  }
  if(*pRoot == NULL) {
    *pRoot = CreatTreeNode(to_insert);
    return;
  }

  SearchTreeNode* root = *pRoot;
  SearchTreeNode* pre = NULL;
  while(root != NULL) {
    if(to_insert < root->data) {
      pre = root;
      root = root->lchild;
    } else if(to_insert > root->data) {
      pre = root;
      root = root->rchild;
    } else {
      return;
    }
  }
  if(to_insert > pre->data) {
    pre->rchild = CreatTreeNode(to_insert);
  } else {
    pre->lchild = CreatTreeNode(to_insert);
  }
  return;
}

删除

删除二叉搜索树与插入相同,也需要保证删除的前后该树都是一个二叉搜索树。所以这个时候就需要讨论了。
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

//递归版的实现
void SearchTreeRemove(SearchTreeNode** pRoot, SearchTreeType to_remove)//删除二叉搜索树中某一个元素
{
  if(pRoot == NULL) {
    return;
  }
  if(*pRoot == NULL) {
    return;
  }
  SearchTreeNode* root = *pRoot;
  if(to_remove > root->data) {
    SearchTreeRemove(&root->rchild, to_remove);
  } else if(to_remove < root->data) {
    SearchTreeRemove(&root->lchild, to_remove);
  } else {
    if(root->lchild == NULL && root->rchild == NULL) {
      DestroyNode(&root);
      return;
    } else if(root->lchild != NULL && root->rchild == NULL) {
      SearchTreeNode* cur = root;
      root = root->lchild;
      DestroyNode(&cur);
      return;
    } else if(root->lchild == NULL && root->rchild != NULL) {
      SearchTreeNode* cur = root;
      root = root->rchild;
      DestroyNode(&cur);
      return;
    } else {
      SearchTreeNode* min = root->rchild;
      SearchTreeNode* pre = min;
      while(min->lchild != NULL) {
        pre = min;
        min = min->lchild;
      }
      root->data = min->data;
      pre->lchild = min->rchild;
      DestroyNode(&min);
      return;
    }
  }
}
//非递归版本的实现
void SearchTreeRemoveByLoop(SearchTreeNode** pRoot, SearchTreeType to_remove)//非递归版本删除二叉搜索树中某一个元素
{
  if(pRoot == NULL) {
    return;
  }
  if(*pRoot == NULL) {
    return;
  }

  SearchTreeNode* root = *pRoot;
  SearchTreeNode* parent = root;
  while(root != NULL) {
    if(to_remove > root->data) {
      parent = root;
      root = root->rchild;
    } else if(to_remove < root->data) {
      parent = root;
      root = root->lchild;
    } else {
      break;
    }
  }
  if(root == NULL) {
    return;
  }

  if(root->lchild == NULL && root->rchild == NULL) {
    DestroyNode(&root);
    return;
  } else if(root->lchild != NULL && root->rchild == NULL) {
    SearchTreeNode* cur = root;
    root = root->lchild;
    DestroyNode(&cur);
    return;
  } else if(root->lchild == NULL && root->rchild != NULL) {
    SearchTreeNode* cur = root;
    root = root->rchild;
    DestroyNode(&cur);
    return;
  } else {
    SearchTreeNode* min = root->rchild;
    SearchTreeNode* pre = min;
    while(min->lchild != NULL) {
      pre = min;
      min = min->lchild;
    }
    root->data = min->data;
    pre->lchild = min->rchild;
    DestroyNode(&min);
    return;
  }
}

欢迎大家共同讨论,如有错误及时联系作者指出,并改正。谢谢大家!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一、实验目的: 理解二叉树特别是完全二叉树的性质,掌握二叉树的存储结构(二叉链表);熟练掌握二叉树的常用操作算法(初始化、插入结点、删除结点、遍历等);初步掌握二叉树的应用。 二、实验内容: 要求采用二叉链表作为存储结构,完成二叉树的建立,前序、中序和后序遍历的操作,求所有叶子及结点总数的操作等。 具体要求如下: ①给出基于二叉链表的二叉树类的定义; ②给出二叉树初始化(构造函数)的实现; ③给出二叉树三种遍历算法的递归实现; ④二叉树先序遍历的非递归算法实现; ⑤利用二叉树的遍历算法求二叉树的结点数、二叉树的叶结点数、二叉树的高度; ⑥二叉树的撤销删除 三、实验步骤: 1、需求分析: 本演示程序用JAVA编写,完成树的生成,任意位置的插入、删除,以及遍历二叉树中的结点,查找和修改树中元素的值。 ① 输入的形式和输入值的范围:插入元素时需要输入插入的位置和元素的值;删除元素时输入删除元素的位置;遍历时采用三种遍历方法中的一种遍历方法;修改操作时需要输入的元素的值;查找操作时,需要找到要查找元素的位置。在所有输入中,元素的值都是整数。 ② 输出的形式:在所有四种操作中都显示操作是否正确以及操作后树中的内容。其中删除操作后显示删除的元素的值,遍历二叉树中的元素,查找操作、修改操作后显示修改的值。 ③ 程序所能达到的功能:完成树的生成(通过插入操作)、插入、删除、遍历、查找、修改操作。 ④ 测试数据: A. 树中已有以50,25,75,12,37,43,30,33,87,93,97为关键字的结点 B. 插入操作中依次输入10,20,30,40,50,60,70,80,90,100十个数 C. 删除操作中输入10删除值为10的元素 D. 查找操作中输入20,30,40,50返回这个元素在树中的位置 2.概要设计: 1)为了实现上述程序功能,需要定义树的抽象数据类型: public int iData; public double dData; public Node leftChild; public Node rightChild; private Node root;int value; private Node getSuccessor; 基本操作:{ Tree () 操作结果:构造一个空的二叉树 insert () 初始条件:是否存在一个空二叉树 操作结果:往二叉树中插入数值 delete () 初始条件:存在一非空的二叉树 操作条件:将二叉树中的元素删除 displayTree () 初始条件:存在一非空的树 操作条件:显示非空树中的所有元素的值 getString () 初始条件:存在一非空的二叉树 操作结果:返回整个字符串的数值 getChar () 初始条件:存在一非空的二叉树 操作结果:返回字符型的数值 getInt () 初始条件:存在一非空的二叉树 操作结果:返回整型的数值 find () 初始条件:存在一非空二叉树 操作结果:从二叉树中查找某一元素 traverse () 初始条件:存在一非空的二叉树 操作结果:对二叉树中的元素进行遍历 preorder () 初始条件:存在一非空的二叉树 操作结果:对二叉树中的元素进行先根遍历 inOrder () 初始条件:存在一非空的二叉树 操作结果:对二叉树中的元素进行中根遍历 postOrder () 初始条件:存在一非空的二叉树 操作结果:对二叉树中的元素进行后根遍历 DisplayNode () 初始条件:存在一非空的二叉树 操作结果:显示出二叉树中的整形数值和双精度浮点型数值 public static void main 操作结果:调用主函数

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值