数据结构-----二叉排序树

目录

前言

1.什么是二叉排序树

2.如何构建二叉排序树

3.二叉排序树的操作

3.1定义节点储存方式

3.2插入节点操作

3.2创建二叉排序树

3.4遍历输出(中序遍历)

3.5数据查找操作

3.6获取最大值和最小值

3.7删除节点操作

3.8销毁二叉排序树

4.完整代码


前言

        今天我们继续学习新的知识点----排序二叉树,在此之前我们学习了相关的排序算法,给你一个数组,然后对这个数组进行排序。那么同样的我们也可以去构建一个二叉排序树,在创建树的过程中进行排序,也能实现排序的效果,下面就一起来看看吧!

1.什么是二叉排序树

        二叉排序树(Binary Sort Tree),又称二叉查找树(Binary Search Tree),亦称二叉搜索树。是数据结构中的一类。在一般情况下,查询效率比链表结构要高。 

给定一个二叉树,如果满足以下条件,那就是二叉排序树

  • 若它的左子树不空,则左子树上所有结点的值均小于它根结点的值。
  • 若它的右子树不空,则右子树上所有结点的值均大于它根结点的值。
  • 它的左、右子树都满足为⼆叉排序树

二叉排序树最大的好处就是查找效率高,相较于链表一个一个去查找,二叉排序树可以去根据数据的排序规律来进行查找

二叉排序树图示:

2.如何构建二叉排序树

比如给定一个数组 [62,88,58,47,35,73,51,99,37,93] ,首先拿到第一个数字,以这个数字为根结点(标准),进行构建,如果比这个数字要大的就放到右子树,比这个要小的就放到左子树去,如下图所示:

 这里我们可以看出,这些节点是一个一个去进行插入的,那我们就可以去通过递归插入的方式来创建,依次往下遍历,找到合适的位置再进行插入操作。

3.二叉排序树的操作

3.1定义节点储存方式

#include<stdio.h>
#include<stdlib.h>//二叉排序树节点存储方式
typedef int DataType;
typedef struct binarytreenode {DataType data;	//数据域struct binarytreenode* left;	//左指针 struct binarytreenode* right;	//右指针
}BTnode;

3.2插入节点操作

插入一个节点首先就要找到这个节点应该插入的位置,从跟节点开始,如果比跟节点小就往左,大就往右,直到叶子节点的位置进行插入操作。

代码实现: 

//插入数据
void Insert_node(BTnode** root, DataType data) {if (*root == NULL) {*root = (BTnode*)malloc(sizeof(BTnode));if (!*root) {printf("ERROR\n");exit(-1);}(*root)->data = data;(*root)->left = NULL;(*root)->right = NULL;}else if ((*root)->data <= data)Insert_node(&(*root)->right, data);else if ((*root)->data > data)Insert_node(&(*root)->left, data);
}

3.2创建二叉排序树

创建二叉排序树,只需要一一插入节点,最后返回根节点即可。代码如下:

//创建排序二叉树
BTnode* Create_sortBtree(DataType* arr, int size) {if (!arr)return NULL;else {BTnode* T = NULL;for (int i = 0; i < size; i++) {Insert_node(&T, arr[i]);}return T;}
}

3.4遍历输出(中序遍历)

//中序遍历排序二叉树
void mid_travel(BTnode* T)
{if (!T)return;mid_travel(T->left);printf("%d ", T->data);mid_travel(T->right);
}

3.5数据查找操作

在二叉排序树上查找某一个值节点,然后返回这个节点的操作。这里可以通过递归和非递归两种方法去实现,代码如下:

递归实现: 

BTnode* Btree_search(BTnode* root, DataType target) {if (!root)return NULL;if (target == root->data) {return root;}return target > root->data ? Btree_search(root->right, target) : Btree_search(root->left, target);
}

 非递归实现(迭代实现):

//非递归查找
BTnode* Btree_search_fa(BTnode* T, DataType target) {BTnode* p = T;while (p) {if (p->data == target){return p;}p = target > p->data ? p->right : p->left;}return NULL;
}

3.6获取最大值和最小值

在一个排序二叉树里面获取最大值或者是最小值,说白了也就是找到最右边和最左边节点就行了,二叉排序树的两个最值就在最两边。代码如下:

获取最大值

//获取最大值
int Btree_max(BTnode* T) {BTnode* cur = T;while (cur->right) {cur = cur->right;}return cur->data;
}

 获取最小值

//获取最小值
int Btree_min(BTnode* T) {BTnode* cur = T;while (cur->left) {cur = cur->left;}return cur->data;
}

3.7删除节点操作

删除节点操作,这就有可能会破坏到排序二叉树的结构,所以要分几种情况去处理。一、如果删除的是叶子节点的话,那么就可以直接去删除,因为叶子节点左右节点都为空,不会影响到二叉排序树的结构;二、如果要删除的节点只有一个左子树或者是有一个右子树的话,我们只需要找到这个节点的左节点或者是右节点,然后顶替掉这个要删除的节点即可;三、如果要删除的节点都有左右子树的话,这里我们就需要去遍历找到比这个节点大一位或者是小一位的节点来顶替这个节点。如下图所示:

1.删除叶子节点 

 2.删除只有一个左(右)子树的节点

3.删除有左右子树的节点 

代码实现:

//删除节点
void Btree_del(BTnode* T, DataType l) {if (!T) {printf("fuck no\n");return;}//找到这个要删除节点的父节点BTnode* p = T, * f = NULL;while (p) {if (p->data == l){break;}f = p;p = l > p->data ? p->right : p->left;}if (!p){printf("没有这个节点\n");return;}BTnode* target = p;//此时的要删除目标节点BTnode* par = f; //此时要删除节点的父节点//第一种情况 此节点只有一个子树的时候if (!target->left && target->right != NULL){if (target->data > par->data) {par->right = target->right;}else {par->left = target->right;}free(target);//释放空间target = NULL;}else if (target->left != NULL && !target->right) {if (target->data > par->data) {par->right = target->left;}else {par->left = target->left;}free(target);target = NULL;}//第二种情况,如果删除的是叶节点,直接删除即可else if (!target->left && !target->right) {if (target->data > par->data) {par->right = NULL;}else {par->left = NULL;}free(target);target = NULL;}//第三种情况,如果左右子树都存在的话//可以用右子树的最小元素//或者左子树的最大元素来替代被删除的节点//我这里就直接去用左树的最大代替这个节点else{BTnode* Lchild = target->left;while (Lchild->right != NULL) {Lchild = Lchild->right;}if (target->data > par->data) {par->right = Lchild;}else {par->left = Lchild;}free(target);target = NULL;}printf("Deleting successfully\n");
}

3.8销毁二叉排序树

//销毁
void Destory_btree(BTnode* T) {if (!T)return;BTnode* cur = T;if (cur->left)Destory_btree(cur->left);if (cur->right)Destory_btree(cur->right);free(T);
}

4.完整代码

#include<stdio.h>
#include<stdlib.h>//二叉排序树节点存储方式
typedef int DataType;
typedef struct binarytreenode {DataType data;	//数据域struct binarytreenode* left;	//左指针 struct binarytreenode* right;	//右指针
}BTnode;//插入数据
void Insert_node(BTnode** root, DataType data) {if (*root == NULL) {*root = (BTnode*)malloc(sizeof(BTnode));if (!*root) {printf("ERROR\n");exit(-1);}(*root)->data = data;(*root)->left = NULL;(*root)->right = NULL;}else if ((*root)->data <= data)Insert_node(&(*root)->right, data);else if ((*root)->data > data)Insert_node(&(*root)->left, data);
}//创建排序二叉树
BTnode* Create_sortBtree(DataType* arr, int size) {if (!arr)return NULL;else {BTnode* T = NULL;for (int i = 0; i < size; i++) {Insert_node(&T, arr[i]);}return T;}
}//中序遍历排序二叉树
void mid_travel(BTnode* T)
{if (!T)return;mid_travel(T->left);printf("%d ", T->data);mid_travel(T->right);
}//递归查找数据
BTnode* Btree_search(BTnode* root, DataType target) {if (!root)return NULL;if (target == root->data) {return root;}return target > root->data ? Btree_search(root->right, target) : Btree_search(root->left, target);
}
//非递归查找
BTnode* Btree_search_fa(BTnode* T, DataType target) {BTnode* p = T, * f = NULL;while (p) {if (p->data == target){return f;}f = p;p = target > p->data ? p->right : p->left;}return NULL;
}//获取最大值
int Btree_max(BTnode* T) {BTnode* cur = T;while (cur->right) {cur = cur->right;}return cur->data;
}
//获取最小值
int Btree_min(BTnode* T) {BTnode* cur = T;while (cur->left) {cur = cur->left;}return cur->data;
}//删除节点
void Btree_del(BTnode* T, DataType l) {if (!T) {printf("fuck no\n");return;}//找到这个要删除节点的父节点BTnode* p = T, * f = NULL;while (p) {if (p->data == l){break;}f = p;p = l > p->data ? p->right : p->left;}if (!p){printf("没有这个节点\n");return;}BTnode* target = p;//此时的要删除目标节点BTnode* par = f; //此时要删除节点的父节点//第一种情况 此节点只有一个子树的时候if (!target->left && target->right != NULL){if (target->data > par->data) {par->right = target->right;}else {par->left = target->right;}free(target);//释放空间target = NULL;}else if (target->left != NULL && !target->right) {if (target->data > par->data) {par->right = target->left;}else {par->left = target->left;}free(target);target = NULL;}//第二种情况,如果删除的是叶节点,直接删除即可else if (!target->left && !target->right) {if (target->data > par->data) {par->right = NULL;}else {par->left = NULL;}free(target);target = NULL;}//第三种情况,如果左右子树都存在的话//可以用右子树的最小元素//或者左子树的最大元素来替代被删除的节点//我这里就直接去用左树的最大代替这个节点else{BTnode* Lchild = target->left;while (Lchild->right != NULL) {Lchild = Lchild->right;}if (target->data > par->data) {par->right = Lchild;}else {par->left = Lchild;}free(target);target = NULL;}printf("Deleting successfully\n");
}//销毁
void Destory_btree(BTnode* T) {if (!T)return;BTnode* cur = T;if (cur->left)Destory_btree(cur->left);if (cur->right)Destory_btree(cur->right);free(T);
}int main()
{int a[] = { 53,17,78,9,45,65,87,23 };//创建二叉排序树BTnode* T = Create_sortBtree(a, sizeof(a) / sizeof(int));mid_travel(T);//遍历输出puts("");//删除最大最小值printf("max:%d  min:%d\n", Btree_max(T), Btree_min(T));//查找BTnode* find = Btree_search(T, 23);printf("查找结果%d\n", find->data);//删除节点Btree_del(T, 45);mid_travel(T);puts("");//销毁操作Destory_btree(T);
}
//输出结果:
//9 17 23 45 53 65 78 87
//max:87  min : 9
//查找结果23
//Deleting successfully
//9 17 23 53 65 78 87

以上就是二叉排序树的全部内容了,我们下次见咯!祝各位国庆节快乐!

 分享一张壁纸:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/96631.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AdaBoost(上):数据分析 | 数据挖掘 | 十大算法之一

⭐️⭐️⭐️⭐️⭐️欢迎来到我的博客⭐️⭐️⭐️⭐️⭐️ &#x1f434;作者&#xff1a;秋无之地 &#x1f434;简介&#xff1a;CSDN爬虫、后端、大数据领域创作者。目前从事python爬虫、后端和大数据等相关工作&#xff0c;主要擅长领域有&#xff1a;爬虫、后端、大数据…

Zookeeper经典应用场景实战(二)

文章目录 1、 Zookeeper 分布式锁实战1.1、 什么是分布式锁1.2、 基于数据库设计思路1.3、 基于Zookeeper设计思路一1.4、 基于Zookeeper设计思路二 1、 Zookeeper 分布式锁实战 1.1、 什么是分布式锁 在单体的应用开发场景中涉及并发同步的时候&#xff0c;大家往往采用Sync…

DRM全解析 —— CRTC详解(1)

本文参考以下博文&#xff1a; Linux内核4.14版本——drm框架分析(4)——crtc分析 特此致谢&#xff01; 1. 简介 CRTC实际上可以拆分为CRTC。CRT的中文意思是阴极摄像管&#xff0c;就是当初老电视上普遍使用的显像管&#xff08;老电视之所以都很厚&#xff0c;就是因为它…

【状态估计】将变压器和LSTM与卡尔曼滤波器结合到EM算法中进行状态估计(Python代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

人机言语交互模型的评估要素

智能客服中的言语交互模型评估要素&#xff0c;主要包括以下几个方面&#xff1a; 有效性&#xff1a;指模型能否准确识别和理解用户的言语意图&#xff0c;以及生成正确和合适的回答。可以通过比较模型生成的回答与人工回答的准确率来评估。流畅性&#xff1a;指模型在回答问…

【单调栈】下一个更大元素 II

文章目录 Tag题目来源题目解读解题思路方法一&#xff1a;单调栈循环数组 写在最后 Tag 【单调栈循环数组】【数组】 题目来源 503. 下一个更大元素 II 题目解读 在循环数组中找下一个更大的元素。循环数组指的是&#xff0c;数组的最后一个元素的下一个元素是数组首元素。 …

C语言之动态内存管理篇(1)

目录 为什么存在动态内存分配 动态内存函数的介绍 malloc free calloc realloc 常见的动态内存错误 今天收假了&#xff0c;抓紧时间写几篇博客。我又来赶进度了。今天我们来讲解动态内存管理。&#x1f197;&#x1f197; 为什么存在动态内存分配 假设我们去实现一个…

Excel插件:StatPlus Pro 7.7.0 Crack

Windows 版 StatPlus 借助 StatPlus&#xff0c;人们可以获得一套强大的统计工具和图形分析方法&#xff0c;可以通过简单直观的界面轻松访问。StatPlus 的可能应用范围几乎是无限的 - 社会学、金融分析、生物统计学、经济学、保险业、医疗保健和临床研究 - 仅举几个该程序已被…

SignalIR入门

SignalIR入门 简介教程1.创建项目2.添加 SignalR 客户端库3.创建 SignalR 中心4.配置 SignalR5.添加 SignalR 客户端代码 效果 简介 SignalR 是一个用于构建实时 Web 应用程序的开发工具和库&#xff0c;它可以让服务器端代码与客户端代码之间建立双向通信。SignalR 的中文解释…

什么测试自动化测试?

什么测试自动化测试&#xff1f; 做测试好几年了&#xff0c;真正学习和实践自动化测试一年&#xff0c;自我感觉这一个年中收获许多。一直想动笔写一篇文章分享自动化测试实践中的一些经验。终于决定花点时间来做这件事儿。 首先理清自动化测试的概念&#xff0c;广义上来讲&a…

如何搭建一个 websocket

环境: NodeJssocket.io 4.7.2 安装依赖 yarn add socket.io创建服务器 引入文件 特别注意: 涉及到 colors 的代码&#xff0c;请采取 console.log() 打印 // 基础老三样 import http from "http"; import fs from "fs"; import { Server } from &quo…

第九课 排序

文章目录 第九课 排序排序算法lc912.排序数组--中等题目描述代码展示 lc1122.数组的相对排序--简单题目描述代码展示 lc56.合并区间--中等题目描述代码展示 lc215.数组中的第k个最大元素--中等题目描述代码展示 acwing104.货仓选址--简单题目描述代码展示 lc493.翻转树--困难题…

JavaScript系列从入门到精通系列第十五篇:JavaScript中函数的实参介绍返回值介绍以及函数的立即执行

文章目录 一&#xff1a;函数的参数 1&#xff1a;形参如何定义 2&#xff1a;形参的使用规则 二&#xff1a;函数的返回值 1&#xff1a;函数返回值如何定义 2&#xff1a;函数返回值种类 三&#xff1a;实参的任意性 1&#xff1a;方法可以作为实参 2&#xff1a;将匿…

【Spring Boot】创建一个 Spring Boot 项目

创建一个 Spring Boot 项目 1. 安装插件2. 创建 Spring Boot 项目3. 项目目录介绍和运行注意事项 1. 安装插件 IDEA 中安装 Spring Boot Helper / Spring Assistant / Spring Initializr and Assistant插件才能创建 Spring Boot 项⽬ &#xff08;有时候不用安装&#xff0c;直…

【排序算法】冒泡排序

文章目录 一&#xff1a;排序算法1.1 介绍1.2 分类 二&#xff1a;冒泡排序2.1 基本介绍2.2 图解冒泡排序算法2.3 代码实现 三&#xff1a;算法性能分析3.1 时间复杂度3.2 空间复杂度 一&#xff1a;排序算法 1.1 介绍 排序也称排序算法(Sort Algorithm)&#xff0c;排序是将…

SpringCloud-消息组件

1 简介 了解过RabbitMQ后&#xff0c;可能我们会遇到不同的系统在用不同的队列。比如系统A用的Kafka&#xff0c;系统B用的RabbitMQ&#xff0c;但是没了解过Kafka&#xff0c;因此可以使用Spring Stream&#xff0c;它能够屏蔽地产&#xff0c;像JDBC一样&#xff0c;只关心SQ…

C# 给某个方法设定执行超时时间

C# 给某个方法设定执行超时时间在某些情况下(例如通过网络访问数据)&#xff0c;常常不希望程序卡住而占用太多时间以至于造成界面假死。 在这时、我们可以通过Thread、Thread Invoke&#xff08;UI&#xff09;或者是 delegate.BeginInvoke 来避免界面假死&#xff0c; 但是…

el-table进阶(每条数据分行或合并)

最麻烦的还是css样式&#xff0c;表格样式自己调吧 <!-- ——————————————————————————————————根据数据拓展表格—————————————————————————————————— --> <div style"display: flex"&…

oralce配置访问白名单的方法

目录 配置sqlnet.ora文件 重新加载使配置生效 注意事项 Oracle数据库安全性提升&#xff1a;IP白名单的配置方法 随着互联网的发展&#xff0c;数据库安全问题也越来越严重。Oracle是目前使用较为广泛的一款数据库管理系统&#xff0c;而IP白名单作为提升数据库安全性的有效…

深度学习——权重衰减(weight_decay)

深度学习——权重衰减&#xff08;weight_decay) 文章目录 前言一、权重衰减1.1. 范数与权重衰减1.2. 高维线性回归1.3. 从零开始实现1.3.1.初始化模型参数1.3.2. 定义L₂范数惩罚1.3.3. 定义训练代码实现1.3.4. 不管正则化直接训练1.3.5. 使用权重衰减 1.4. 简洁实现 总结 前言…