二叉搜索树
时间:2022-06-22
本文章向大家介绍二叉搜索树,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
版权声明:本文为博主原创文章,转载请注明博客地址: https://blog.csdn.net/zy010101/article/details/83033069
二叉搜索树(Binary Search Tree)也叫做二叉排序树或者二叉查找树。顾名思义,它是一种对排序和查找都很有用的特殊二叉树。
二叉查找树满足以下性质:(假设二叉查找树中每个节点元素都是不同的,它也可以为空)
- 非空左子树的所有键值小于其根节点的键值;
- 非空右子树的所有键值大于其根节点的键值;
- 左,右两棵子树都是二叉搜索树
二叉搜索树本质上还是一棵二叉树,只不过对它做了限定,就行队列和栈一样,它们是对线性表做了限制。对二叉搜索树的遍历和创建操作与普通二叉树一致。但是二叉搜索树的特点使得对它的查找,插入,删除变得有些不同。
二叉搜索树的平均深度是O(logn)的,一般不会造成爆栈的。
二叉搜索树的对于查找问题的解决,本质上还是二分法的使用。但是不同于我们对一个有序数组使用的二分查找法。有序数组上施加的二分查找是元素个数恒定不变的(不进行插入和删除操作),称之为静态查找。二叉搜索树则可以支持插入和删除操作,它使得查找的范围可以动态变化,称之为动态查找。
如果按照查找操作是如何进行的来分类,那么二叉搜索树和二分查找都是基于比较实现的;另外一种实现查找的方式是基于映射实现的,即:散列表,或者称之为哈希表。
二叉搜索树的ATD和操作集
#ifndef BST
#define BST
#include<iostream>
#include<stack>
using std::cout;
using std::cin;
using std::stack;
typedef struct TreeNode Tree;
typedef Tree * PTree;
typedef PTree Position;
typedef int ElementType;
struct TreeNode
{
ElementType data;
PTree left;
PTree right;
};
Position Find(ElementType k, PTree T); //递归版查找
Position Find(ElementType k, PTree T,int a); //迭代版查找
Position FindMax(PTree T); //返回最大元素
Position FindMin(PTree T); //返回最小元素
void InorderTraversal(PTree T); //递归版中序遍历
void InorderTraversal(PTree T,int a); //迭代版中序遍历
PTree Insert(ElementType x, PTree T); //插入操作
PTree Delete(ElementType x, PTree T); //删除操作
int PostinorderGetHeight(PTree T); //二叉树的高度
#endif // !BST
二叉搜索树操作集的C++实现代码:
#include "searchtree.h"
//递归版本实现的查找函数,二叉树的平均深度是O(log n),可以递归的
Position Find(ElementType k, PTree T)
{
if (NULL == T)
{
return NULL; //空树
}
if (k < T->data) //k小于data,去该节点的左子树查找。
{
return Find(k,T->left);
}
else if (k > T->data) //k大于data,去该节点的右子树查找。
{
return Find(k, T->right);
}
else if (k == T->data) //k等于data,直接返回该节点。
{
return T;
}
}
Position Find(ElementType k, PTree T, int a)
{
while (T) //树不空执行循环
{
if (k > T->data)
{
T = T->right; //转右子树查找
}
else if (k < T->data)
{
T = T->left; //转左子树查找
}
else
{
return T; //找到了该元素
}
}
return NULL; //没有找到该元素
}
Position FindMax(PTree T)
{
if (NULL == T)
{
return NULL; //空树
}
else
{
while (T->right)
{
T = T->right; //最大值在其右子树上,且该右子树无右子树
}
return T; //返回最大值所在节点
}
}
Position FindMin(PTree T)
{
if (NULL == T)
{
return NULL; //空树
}
else
{
while (T->left)
{
T = T->left; //最小值在其左子树上,且该左子树无左子树
}
return T; //返回最小值所在节点
}
}
void InorderTraversal(PTree T)
{
if (T)
{
InorderTraversal(T->left);
cout << T->data << ' ';
InorderTraversal(T->right);
}
}
void InorderTraversal(PTree T, int a)
{
if (NULL == T)
{
return;
}
else
{
stack<PTree> S; //创建空栈
while (T || !S.empty())
{
while (T)
{
S.push(T); //将T压入栈中
T = T->left; //转左子树
}
if(!S.empty())
{
/*T = (PTree)malloc(sizeof(Tree));
T->data = S.top()->data;
T->left = S.top()->left;
T->right = S.top()->right;*/
T = S.top();
cout << T->data << ' ';
T = T->right; //转右子树
S.pop(); //删除栈顶元素
}
}
}
}
PTree Insert(ElementType x, PTree T)
{
PTree temp = NULL;
PTree BT = T;
if (!T)
{
T = (PTree)malloc(sizeof(Tree));
T->data = x;
T->left = T->right = NULL;
return T;
}
else
{
while (T)
{
if (x < T->data)
{
if (!T->left) //若左子树为空,插入到这里
{
temp = (PTree)malloc(sizeof(Tree));
temp->data = x;
temp->left = NULL;
temp->right = NULL;
T->left = temp;
break;
}
else //若不空,转左子树
{
T = T->left;
}
}
if (x > T->data)
{
if (!T->right) //若右子树为空,插入到这里
{
temp = (PTree)malloc(sizeof(Tree));
temp->data = x;
temp->left = NULL;
temp->right = NULL;
T->right = temp;
break;
}
else //若不空,转右子树
{
T = T->right;
}
}
if (x == T->data) //找到这个元素
{
break;
//如果要插入的元素已经在该树中存在,那么一般有两种做法
//1.什么操作也不做,适合在不追求重复元素的场合使用
//2.向树的ADT中增加一个域,用来保存该元素的出现次数。这样使得树
//增加了一下附加空间,但是,却比将重复信息放入树中好的多,这样避免
//了树深度的增加。
//在这里我们采用第一种方式,什么也不做。
}
}
return BT;
}
}
PTree Delete(ElementType x, PTree T)
{
PTree temp;
if (!T)
{
cout << "删除元素未找到!n";
}
else
{
if (x < T->data)
{
T->left = Delete(x, T->left); //递归删除左子树
}
else if (x > T->data)
{
T->right = Delete(x, T->right); //递归删除右子树
}
else
{
if (T->left && T->right) //左右子树都存在
{
temp = FindMin(T->right);
//temp = FindMax(T->left);
T->data = temp->data;
T->right = Delete(T->data, T->right);
}
else
{
temp = T;
if (!T->left) //右子树存在或者左右子树都不存在
{
T = T->right;
}
else if (!T->right) //左子树存在或者左右子树都不存在
{
T = T->left;
}
free(temp);
}
return T;
}
}
}
int PostinorderGetHeight(PTree T)
{
if (T)
{
int l, r, max;
l = PostinorderGetHeight(T->left);
r = PostinorderGetHeight(T->right);
max = l > r ? l : r;
return max + 1;
}
else
{
return 0;
}
}
main.cpp文件
#include"searchtree.h"
int main()
{
PTree BT = NULL;
for (int i = 5; i < 10; i++) //把根节点设置为5,插入5-9;
{
BT = Insert(i, BT);
}
for (int i = 0; i < 5; i++) //插入0-4.
{
BT = Insert(i, BT);
}
Insert(5, BT);
//理论上中序遍历输出应该是0 1 2 3 4 5 6 7 8 9
cout << "中序遍历输出:";
InorderTraversal(BT,1);
cout << "n树的深度是:";
cout << PostinorderGetHeight(BT);
cout << "n树中最大元素是:" << FindMax(BT)->data;
cout << "n树中最小元素是:" << FindMin(BT)->data;
cout << 'n' << "删除元素5后,中序遍历结果:";
BT = Delete(5, BT);
InorderTraversal(BT);
cout << 'n';
PTree temp;
cout << "查找5这个元素的结果:";
temp = Find(5, BT);
if (NULL == temp)
{
cout << "未找到!n";
}
else
{
cout << temp->data << 'n';
}
cout << "查找3这个元素的结果:";
temp = Find(3, BT);
if (NULL == temp)
{
cout << "未找到!n";
}
else
{
cout << temp->data << 'n';
}
system("pause");
return 0;
}
运行结果:
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.gong.mybatis.da
- 【python-leetcode378-二分查找】有序矩阵中的第k小元素
- 使用cookie来记录用户登录次数,为何次数不更新
- (二)golang--windows下vscode的安装以及go环境的配置
- mybatis文件映射之使用#取值时的一些规则
- 【论文笔记】Improved Residual Networks for Image and Video Recognition(ResNet新变体:IResNet)
- SQL语句在MYSQL中的运行过程和各个组件的介绍
- (五)golang--常用的一些玩意
- 关于MYSQL 的日志系统
- (六)golang--变量
- springmvc之文件上传
- (七)golang--变量之基本数据类型(看这篇就够了)
- Mybatis学习笔记(五)Mybatis中已经显示数据已修改但数据库中记录未更新问题
- 【自然语言处理(一)】相关基础技能
- MySQL innoDB的事务隔离