什么是二叉查找树?

二叉查找树又叫二叉排序树,缩写为BST,全称Binary Sort Tree或者Binary Search Tree

以下定义来自百度百科:

二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:

  • 若左子树不空,则左子树上所有节点的值均小于它的根节点的值;
  • 若右子树不空,则右子树上所有节点的值均大于它的根节点的值;
  • 左、右子树也分别为二叉排序树;
  • 没有键值相等的节点。

二叉查找树C语言实现

二叉查找树是将数值比当前节点数值大的优先放到左子树,数值被当前节点大的放倒右子树;

C语言要实现以下几个接口:

  • 查找节点;
  • 插入节点;
  • 删除节点;

查找节点

  1. 若根结点的关键字值等于查找的关键字,成功。
  2. 否则,若小于根结点的关键字值,递归查左子树。
  3. 若大于根结点的关键字值,递归查右子树。
  4. 若子树为空,查找不成功。
Positon	search_tree_find(ElementType x, SearchTree root) {

	if (root == NULL) {
return NULL;
}
if (x < root->value) {
root = search_tree_find(x, root->left);
}
else if (x < root->value) {
root = search_tree_find(x, root->right);
}
return root;
}

查找最大值

如下图所示找出最小值只需要递归查找右子树即可;

Positon search_tree_find_max(SearchTree root) {
if (root == NULL) {
return NULL;
}
if (root->right != NULL) {
root = search_tree_find_max(root->right);
}
return root; }

查找最小值

如下图所示找出最小值只需要递归查找左子树即可;

Positon search_tree_find_min(SearchTree root) {
if (root == NULL) {
return NULL;
}
if (root->left != NULL) {
root = search_tree_find_min(root->left);
}
return root;
}

插入节点

插入节点其实和查找节点类似,这里主要是递归得查找需要插入节点的位置,最终将节点插入,search_tree_insert最终会返回一个新的根,如下图所示,想要将5 插入到图中左侧的树中,递归查找的节点4之后,因为5大于4,所以需要往右下插入节点,但是传入的root-right == NULL成立,所以最终分配新节点,并将节点value赋值为5,然后返回一棵新树;

SearchTree search_tree_insert(ElementType x, SearchTree root) {
//如果是一棵空树,则新建一棵树
if (root == NULL) {
root = (SearchTree)malloc(sizeof(TreeNodeType));
if (root == NULL) {
return NULL;
}
root->value = x;
root->left = NULL;
root->right = NULL;
return root;
}
if (x < root->value) {
root->left = search_tree_insert(x, root->left);
}
else if (x > root->value) {
root->right = search_tree_insert(x, root->right);
}
return root;
}

删除节点

节点的删除,需要判断三种情况:

  • 需要删除的是叶子节点(直接删除节点即可);
  • 删除的节点只有一个子节点(将父节点值替换为子节点,然后删除子节点即可);
  • 删除的节点有两个子节点(用该节点右子树的最小节点来替换当前节点,然后将最小节点删除即可);

具体如下;删除情况如下;

1) Node to be deleted is leaf: Simply remove from the tree.

              50                            50
/ \ delete(20) / \
30 70 ---------> 30 70
/ \ / \ \ / \
20 40 60 80 40 60 80

2) Node to be deleted has only one child: Copy the child to the node and delete the child

              50                            50
/ \ delete(30) / \
30 70 ---------> 40 70
\ / \ / \
40 60 80 60 80

3) Node to be deleted has two children: Find inorder successor of the node. Copy contents of the inorder successor to the node and delete the inorder successor. Note that inorder predecessor can also be used.

              50                            60
/ \ delete(50) / \
40 70 ---------> 40 70
/ \ \
60 80 80

The important thing to note is, inorder successor is needed only when right child is not empty. In this particular case, inorder successor can be obtained by finding the minimum value in right child of the node.

附录

search_tree.h

#ifndef SEARCH_TREE
#define SEARCH_TREE #ifdef __cplusplus
extern "C" {
#endif #include <stdio.h> typedef int ElementType;
typedef struct TreeNode TreeNodeType;
typedef TreeNodeType * SearchTree;
typedef TreeNodeType * Positon; struct TreeNode
{
ElementType value;
TreeNodeType *left;
TreeNodeType *right;
}; SearchTree search_tree_make_empty(SearchTree root);
Positon search_tree_find(ElementType x, SearchTree root);
Positon search_tree_find_max(SearchTree root);
Positon search_tree_find_min(SearchTree root);
SearchTree search_tree_insert(ElementType x, SearchTree root);
SearchTree search_tree_delete(ElementType x, SearchTree root);
void search_tree_print(SearchTree root); #ifdef __cplusplus
}
#endif #endif // !SEARCH_TREE

search_tree.c

#include "search_tree.h"

SearchTree search_tree_make_empty(SearchTree root) {

	if (root != NULL) {
search_tree_make_empty(root->left);
search_tree_make_empty(root->right);
}
return NULL;
} Positon search_tree_find(ElementType x, SearchTree root) { if (root == NULL) {
return NULL;
}
if (x < root->value) {
root = search_tree_find(x, root->left);
}
else if (x < root->value) {
root = search_tree_find(x, root->right);
}
return root;
}
Positon search_tree_find_max(SearchTree root) {
if (root == NULL) {
return NULL;
}
if (root->right != NULL) {
root = search_tree_find_max(root->right);
}
return root; }
Positon search_tree_find_min(SearchTree root) {
if (root == NULL) {
return NULL;
}
if (root->left != NULL) {
root = search_tree_find_min(root->left);
}
return root;
}
SearchTree search_tree_insert(ElementType x, SearchTree root) { //如果是一棵空树,则新建一棵树
if (root == NULL) {
root = (SearchTree)malloc(sizeof(TreeNodeType));
if (root == NULL) {
return NULL;
}
root->value = x;
root->left = NULL;
root->right = NULL;
return root;
}
if (x < root->value) {
root->left = search_tree_insert(x, root->left);
}
else if (x > root->value) {
root->right = search_tree_insert(x, root->right);
}
return root;
} SearchTree search_tree_delete(ElementType x, SearchTree root) { TreeNodeType *tmpNode = NULL;
if (root == NULL) {
return NULL;
} if (x < root->value) {
root->left = search_tree_delete(x, root->left);
}
else if (x > root->value) {
root->right = search_tree_delete(x, root->right);
}
else {
// have two subtrees
if (root->left && root->right) {
tmpNode = search_tree_find_min(root->right);
root->value = tmpNode->value;
root->right = search_tree_delete(tmpNode->value, root->right);
}
// only have one subtree
else {
tmpNode = root;
if (root->left != NULL) {
root = root->left;
}
if (root->right != NULL) {
root = root->right;
}
free(tmpNode);
}
}
return root;
}
#define SIZE 50
void search_tree_print(SearchTree root) {
int head = 0, tail = 0;
TreeNodeType *p[SIZE] = { NULL };
TreeNodeType *tmp;
TreeNodeType *last = root;
TreeNodeType *nlast = root;
if (root != NULL) {
p[head] = root;
tail++;
// Do Something with p[head]
}
else {
return;
}
//环形队列作为缓冲器
while (head % SIZE != tail % SIZE) {
tmp = p[head % SIZE];
// Do Something with p[head]
printf("%d ", tmp->value);
if (tmp->left != NULL) { // left
p[tail++ % SIZE] = tmp->left;
nlast = tmp->left;
}
if (tmp->right != NULL) { // right
p[tail++ % SIZE] = tmp->right;
nlast = tmp->right;
}
if (last == tmp) {
printf("\n");
last = nlast;
}
head++;
}
return;
}

main.cpp

#include <iostream>
#include "search_tree.h" using namespace std; int main() {
SearchTree tmp = NULL;
SearchTree search_tree = NULL;
search_tree = search_tree_make_empty(search_tree);
search_tree = search_tree_insert(50, search_tree);
search_tree = search_tree_insert(40, search_tree);
search_tree = search_tree_insert(30, search_tree);
search_tree = search_tree_insert(60, search_tree);
search_tree = search_tree_insert(70, search_tree);
search_tree = search_tree_insert(80, search_tree); search_tree_print(search_tree); tmp = search_tree_find_min(search_tree);
printf("min value is %d\n", tmp->value);
printf("address is 0x%08x\n", tmp); tmp = search_tree_find_max(search_tree);
printf("max value is %d\n", tmp->value);
printf("address is 0x%08x\n", tmp); search_tree = search_tree_delete(50, search_tree);
search_tree_print(search_tree); search_tree = search_tree_delete(70, search_tree);
search_tree_print(search_tree); getchar();
return 0;
}

执行结果如下:

数据结构学习:二叉查找树的概念和C语言实现的更多相关文章

  1. 数据结构:二叉查找树(C语言实现)

    数据结构:二叉查找树(C语言实现) ►写在前面 关于二叉树的基础知识,请看我的一篇博客:二叉树的链式存储 说明: 二叉排序树或者是一棵空树,或者是具有下列性质的二叉树: 1.若其左子树不空,则左子树上 ...

  2. Prolog学习:基本概念 and Asp.net与Dojo交互:仪器仪表实现

    Asp.net与Dojo交互:仪器仪表实现 项目中需要用到仪器仪表的界面来显示实时的采集信息值,于是便遍地寻找,参考了fusionchart和anychart之后,发现都是收费的,破解的又没有这些功能 ...

  3. 编译原理(一)绪论概念&文法与语言

    绪论概念&文法与语言 以老师PPT为标准,借鉴部分教材内容,AlvinZH学习笔记. 绪论基本概念 1. 低级语言:字位码.机器语言.汇编语言.与特定的机器有关,功效高,但使用复杂.繁琐.费时 ...

  4. Docker学习之基本概念

    Docker学习之基本概念 作为一个后端noder,不了解docker有点说不过去,这节开始,学习一些docker层面的东西. 什么是docker Docker最初是dotCloud公司创始人Solo ...

  5. 前端学习 第三弹: JavaScript语言的特性与发展

    前端学习 第三弹: JavaScript语言的特性与发展 javascript的缺点 1.没有命名空间,没有多文件的规范,同名函数相互覆盖 导致js的模块化很差 2.标准库很小 3.null和unde ...

  6. 算法设计和数据结构学习_5(BST&AVL&红黑树简单介绍)

    前言: 节主要是给出BST,AVL和红黑树的C++代码,方便自己以后的查阅,其代码依旧是data structures and algorithm analysis in c++ (second ed ...

  7. Oracle RAC学习笔记:基本概念及入门

    Oracle RAC学习笔记:基本概念及入门 2010年04月19日 10:39 来源:书童的博客 作者:书童 编辑:晓熊 [技术开发 技术文章]    oracle 10g real applica ...

  8. Java IO学习笔记:概念与原理

    Java IO学习笔记:概念与原理   一.概念   Java中对文件的操作是以流的方式进行的.流是Java内存中的一组有序数据序列.Java将数据从源(文件.内存.键盘.网络)读入到内存 中,形成了 ...

  9. C++数据结构之二叉查找树(BST)

    C++数据结构之二叉查找树(BST) 二分查找法在算法家族大类中属于“分治法”,二分查找的过程比较简单,代码见我的另一篇日志,戳这里!因二分查找所涉及的有序表是一个向量,若有插入和删除结点的操作,则维 ...

随机推荐

  1. 如何用python批量生成真实的手机号码

    前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者:Python测试社区 1目 标 场 景 平时在工作过程中,偶尔会需要大 ...

  2. C. Beautiful Regional Contest

    用前缀和写一直wa.. 思路:让金牌和银牌最少,通多增加铜牌的方式来扩大总奖牌的个数. #include<bits/stdc++.h> using namespace std; map&l ...

  3. C - Ivan the Fool and the Probability Theory---div2

    题目连接:https://codeforces.com/contest/1248/problem/C 思路: 注意上下两排的关系,如果说上面那一排有两个方格连续,那么他相邻的两排必定和他相反,如果说当 ...

  4. asp.net core web api + Element-UI的Vue管理后台

    后端:asp.net core web api + EF Core 前端:VUE + Element-UI+ Node环境的后台管理系统. 线上地址:http://www.wangjk.wang/ 密 ...

  5. 爬虫与反爬相生相克,道高一丈魔高一尺,如何隐藏ID(附代码)

    Python 反爬篇之 ID 混淆 作为爬虫的一方,如果知道了某个站点的数据自增 ID,那么就能轻而易举把整个站点都爬下来. 是不是有点耸人听闻,你去看很多大站例如油管.P 站等,他们都不会轻易把业务 ...

  6. 使用hexo和coding建立静态博客站点

    背景 由于工作性质的原因,做技术的总想记录和分享一下自己的学习和成长历程,向这世界证明我来过.写文章,发博客,一开始使用51cto,广告太多,看起来让人很痛苦:接着试用了博客园,广告少一些,但感觉还是 ...

  7. SpringBoot项目集成Redis

    一.在pom文件中添加依赖 <!-- 集成redis --> <dependency> <groupId>org.springframework.boot</ ...

  8. 2019-2020-1 20199308《Linux内核原理与分析》第七周作业

    <Linux内核分析> 第六章 进程的描述和进程的创建 6.1 进程的描述 操作系统内核实现操作系统的三大管理功能: 进程管理(进程)-核心 内存管理(虚拟内存) 文件系统(文件) 为了管 ...

  9. SAP采购订单入库后不允许修改单价增强

    需求:在根据采购订单做了入库凭证之后,如果用户反审批采购订单去修改单价,系统提示‘已收货,不允许修改单价’. 判断流程:是否有入库凭证 如果采购订单条件按采购信息记录定价,这个价格本来就不能修改,只能 ...

  10. Spring Boot Starters介绍

    文章目录 Web Start Test Starter Data JPA Starter Mail Starter 结论 对于任何一个复杂项目来说,依赖关系都是一个非常需要注意和消息的方面,虽然重要, ...