二叉排序树可以看做是一个较好的数据存储模型,因为在二叉排序树中有属于它自己的一套方法对数据进行高效操作:
1> 数据的链式存储
2> 数据的排序 (有序读取)
3> 查找数据(指定数据,最大值、最小值)
4> 数据的删除 (更新ing...)
本篇文章将会介绍二叉排序树的建立以及对应的一些操作;
****************************************************************************************************************************************
一:建立 ( 将数据存进二叉排序树 )
使用排序二叉树,首先需要我么将数据存储到该二叉树中,
这里首先建立一个二叉树(这里首先树的节点结构体):
typedef struct node
{
int data;
struct node *lchild, *rchild;
}*BinS_Tree,BinS_Tree_Node;
然后通过依次读取数据通过递归让数据自动按照下面逻辑结构布局:
大小关系如图箭头所示;
代码实现:
void BinS_Tree_Insert(BinS_Tree *T, int data)
{
if (*T == NULL)
{
BinS_Tree r = (BinS_Tree)malloc(sizeof(BinS_Tree_Node));
r->data = data; r->lchild = NULL; r->rchild = NULL;
*T = r;
return;
}
else if (data < (*T)->data)
{
BinS_Tree_Insert(&((*T)->lchild),data);
}
else
{
BinS_Tree_Insert(&((*T)->rchild),data);
}
}
int main()
{
BinS_Tree T;
T = NULL;
srand(unsigned(time(NULL)));
for (int i = 0; i < 10; i++)
{
BinS_Tree_Insert(&T, rand() % 100);
}
注意:
这里我们可以在Main函数中直接定义,然后将T赋空;
BinS_Tree T;
T = NULL;
这里还需要注意的一点是,函数的参数中使用了二级指针BinS_Tree *T:
之所以这样做,是因为在该函数内(该变生存期)结束后,其一级指针的数据会被直接更改,函数内部修改后的数据也会被带出。
最简单的例子就是两个整数的交换,如果函数中的形参仅仅是变量swap(int a, int b),那么main函数中的两个数也不会被改变,将函数形参换为对应指针即可实现正常交换swap(int *a, int *b)。
但是!!
如果给了上图中的一系列数据(50,38,70,30,45,60,75,40,48,80),真的能够利用上面的源码存储成图中的逻辑结构吗?
( 忽略源码中的随机赋值,使用指定数组 );
结果是否定的,为什么呢?插入函数没错,但是在主函数中赋值的时候出现了部分纰漏:
在我们的插入函数中,因为使用的是二级指针,下图的这个地方是让每一次插入后,T都指向新插入的节点;
问题来了,这就会导致我们创建的二叉树每个节点只有一个分支,结构也偏离了我们的预期目标。
那么将这句删掉不就可以了吗?当然也是不可以的,这里之所以给T赋值是因为T初始化的时候是为空的,如果取消这一句,T就会一直保持NULL,遍历的时候就会遇到麻烦。
这时我们就会想到新的方法:
将根节点存储起来,使得T一直指向根节点,然后在每次调用之前都对T进行一次根节点赋值,代码如下:
int main()
{
BinS_Tree T,root;
T = NULL;
root = NULL;
srand(unsigned(time(NULL)));
for (int i = 0; i < 10; i++)
{
if (i == 0)
{
BinS_Tree_Insert(&T, rand() % 100);
root = T;
}
else
{
T = root;
BinS_Tree_Insert(&T, rand() % 100);
}
}
}
二:查询(指定数据,最大值、最小值)
1> 查询最大值、最小值
void Search_MinData(BinS_Tree T)
{
if (!T)
return;
if (T->lchild == NULL)
{
cout << "The MinData is : " << T->data << endl;
}
else
{
Search_MinData(T->lchild);
}
}
void Search_MaxData(BinS_Tree T)
{
if (!T)
return;
if (T->rchild == NULL)
{
cout << "The MaxData is : " << T->data << endl;
}
else
{
Search_MinData(T->rchild);
}
}
因为数据的存储结构是有一定规律的 (见上图),这里使用递归进行查询就是寻找最左边的叶子和最右边的叶子;
2> 查询指定数据
bool Search_Data(BinS_Tree T, int data)
{
bool Find = false;
if (!T)
return false;
if (T->data == data)
{
Find = true;
//cout << "Search Successful!" << data << endl;
return Find;
}
else if(data > T->data)
{
Search_Data(T->rchild, data);
}
else
{
Search_Data(T->rchild, data);
}
//if (!Find) //这一因为执行递归进程,所以会在这里调用很多次,可以取消在函数中直接判断,而是在函数外部通过该函数的返回值进行判断
//{
// cout << "Cannot fine the number : " << data << "!" << endl;
//}
return Find;
}
void Judge_Search_Data(bool Judge, int data)
{
if (Judge)
{
cout << "Data(" << data << ") in this zone !" << endl;
}
else
{
cout << "Cannot find the Data(" << data << ")" << endl;
}
}
三:数据的排序 (有序读取)
因为数据逻辑结构存的特殊性,使用二叉树的中序遍历可以直接将数据从小到大进行输出:
void Traverse_Middle(BinS_Tree T)
{
if (!T)
{
return;
}
else
{
Traverse_Middle(T->lchild);
cout << T->data << endl;
Traverse_Middle(T->rchild);
}
}
从大到小更改左右子树递归的顺序即可:
void Traverse_Middle(BinS_Tree T)
{
if (!T)
{
return;
}
else
{
Traverse_Middle(T->rchild);
cout << T->data << endl;
Traverse_Middle(T->lchild);
}
}
四:删除
这张图的五个圈分别代表删除数据时遇到的的五种情况:叶子、只有左子树、只有右子树、左右子树都有和根节点
五:源码(测试用)
#include <bits/stdc++.h>
using namespace std;
typedef struct node
{
int data;
struct node *lchild, *rchild;
}*BinS_Tree,BinS_Tree_Node;
bool Search_Data(BinS_Tree T, int data)
{
bool Find = false;
if (!T)
return false;
if (T->data == data)
{
Find = true;
//cout << "Search Successful!" << data << endl;
return Find;
}
else if(data > T->data)
{
Search_Data(T->rchild, data);
}
else
{
Search_Data(T->rchild, data);
}
//if (!Find) //这一因为执行递归进程,所以会在这里调用很多次,可以取消在函数中直接判断,而是在函数外部通过该函数的返回值进行判断
//{
// cout << "Cannot fine the number : " << data << "!" << endl;
//}
return Find;
}
void Judge_Search_Data(bool Judge, int data)
{
if (Judge)
{
cout << "Data(" << data << ") in this zone !" << endl;
}
else
{
cout << "Cannot find the Data(" << data << ")" << endl;
}
}
void Search_MinData(BinS_Tree T)
{
if (!T)
return;
if (T->lchild == NULL)
{
cout << "The MinData is : " << T->data << endl;
}
else
{
Search_MinData(T->lchild);
}
}
void Search_MaxData(BinS_Tree T)
{
if (!T)
return;
if (T->rchild == NULL)
{
cout << "The MaxData is : " << T->data << endl;
}
else
{
Search_MinData(T->rchild);
}
}
void BinS_Tree_Insert(BinS_Tree *T, int data)
{
if (*T == NULL)
{
BinS_Tree r = (BinS_Tree)malloc(sizeof(BinS_Tree_Node));
r->data = data; r->lchild = NULL; r->rchild = NULL;
*T = r;
return;
}
else if (data < (*T)->data)
{
BinS_Tree_Insert(&((*T)->lchild),data);
}
else
{
BinS_Tree_Insert(&((*T)->rchild),data);
}
}
void Traverse_Middle(BinS_Tree T)
{
if (!T)
{
return;
}
else
{
Traverse_Middle(T->lchild);
cout << T->data << endl;
Traverse_Middle(T->rchild);
}
}
int main()
{
BinS_Tree T,root;
T = NULL;
root = NULL;
srand(unsigned(time(NULL)));
for (int i = 0; i < 10; i++)
{
if (i == 0)
{
BinS_Tree_Insert(&T, rand() % 100);
root = T;
}
else
{
T = root;
BinS_Tree_Insert(&T, rand() % 100);
}
}
Traverse_Middle(T);
int data = rand() % 10;
bool Judge = Search_Data(T, data);
Judge_Search_Data(Judge,data);
Search_MinData(T);
Search_MaxData(T);
return 0;
}
****************************************************************************************************************************************
最快的脚步不是跨越,而是继续,最慢的步伐不是小步,而是徘徊。
****************************************************************************************************************************************