二叉搜索树算法:
1、直接输入搜索序列,构造出类似于折半搜索的判定树那样的树形结构,
就能很快实现搜索,这就是二叉搜索树。
2、二叉搜索树是一种动态的搜索结构,输入元素的关键码序列不同的话
会有不同形态的二叉搜索树。
3、二叉搜索树的定义:
二叉搜索树或者是一颗空树,或者是具有下列性质的二叉树。
a)每个结点都有一个作为搜索依据的关键码,所有结点的关键码各不相同
b)左子树上的所有结点的关键码都小于根结点的关键码。
c)右子树上的所有结点的关键码都大于根结点的关键码。
d)左子树和右子树也都是二叉搜索树。
由第四条可以推断出,二叉搜索树的定义也是递归的。
二叉搜索树常用来表示字典结构。
二叉搜索树的抽象类型定义:
#include<iostream>
using namespace std;
//二叉搜索树的结点表示
struct BinSearchNode
{
int key; //结点的关键码
BinSearchNode *lSearchTree; //左子树
BinSearchNode *rSearchTree; //右子树
BinSearchNode()
{
lSearchTree=NULL;
rSearchTree=NULL;
}
};
//二叉搜索树的类定义
class BinSearchTree
{
public:
//构造函数和析构函数
BinSearchTree()
{
bsnroot=NULL;
}
~BinSearchTree()
{
}
//二叉搜索树的关键算法,引用形参和非引用形参
void InsertSearchNode(BinSearchNode *&bsn, int data); //插入结点
void DeleteSearchNode(int key,BinSearchNode *&bsn); //删除结点
BinSearchNode * SearchBinaryTreeCurrent(int key,BinSearchNode *&bsn); //搜索当前结点
void MidTravel(BinSearchNode *bsn); //中序遍历输出
BinSearchNode *MinSearch(BinSearchNode *&bsn);//寻找中序下的第一个结点指针
BinSearchNode *ReturnSearchRoot() //返回二叉搜索树的根结点
{
return bsnroot;
}
private:
BinSearchNode *bsnroot; //二叉搜索树的根结点
};
二叉搜索树插入结点递归算法:
1、如果该结点为空,则该结点为空结点,则把这个值赋值给根结点。
2、如果不为空,则和父节点的键值比较,如果小于根结点,则递归建立左子树。
3、如果大于父结点,则递归建立右子树。
4、如果等于父结点,则报错。
void BinSearchTree::InsertSearchNode(BinSearchNode *&bsn, int data)
{
if(bsn==NULL)
{
//错误一:忘记了新建结点,分配存储空间
bsn=new BinSearchNode; //新建结点
if(bsn==NULL)cout<<"新建新结点出错"<<endl;
else
{
bsn->key=data;
}
}
else
{
if(data<bsn->key) //bsn
{
InsertSearchNode(bsn->lSearchTree,data);
}
else if(data>bsn->key)
{
InsertSearchNode(bsn->rSearchTree,data);
}
else
{
cout<<"非法结点"<<endl;
}
}
}
中序遍历输出递归算法:
void BinSearchTree::MidTravel(BinSearchNode *bsn)
{
//if(bsn==NULL) //这样写是错的,因为每次指针为空的时候都会打印这句话
//{
//cout<<"这是一颗空的二叉搜索树"<<endl;
//}
if(bsn!=NULL)
{
MidTravel(bsn->lSearchTree);
cout<<bsn->key<<" "; //找到第一个结点指针
MidTravel(bsn->rSearchTree);
}
}
二叉搜索树的搜索算法:
1、从根结点开始,如果根结点为空,则返回空
2、如果小于根结点的值,则递归搜索左子树
3、如果大于根结点的值,则递归搜索右子树
4、否则找到了该结点,返回真
BinSearchNode* BinSearchTree::SearchBinaryTreeCurrent(int key,BinSearchNode *&bsn)
{
if(bsn==NULL)
return false;
else if(bsn->key>key)
{
SearchBinaryTreeCurrent(key,bsn->lSearchTree);
}
else if(bsn->key<key)
{
SearchBinaryTreeCurrent(key,bsn->rSearchTree);
}
else
return bsn;
}
二叉搜索树的删除结点算法:
删除算法中需要将因删除结点而断开的二叉链表重新连接起来,同时确保二叉树
性质不会失去,还要防止重新链接后的树的高度不会增加。
规则:右子树为空,左子女填补;左子树为空,右子女填补;左子树和右子树
都不为空,则寻找中序下的第一个结点,关键码最小的结点。如果是第二小,
则右子树中有小于根结点的结点,失去了二叉搜索树的性质。
1、搜索定位到该键值对应的指针处。
2、判断该该指针的右子树为空,则将该结点赋值给一个临时指针,然后将左子树覆盖这个指针,删除临时指针。
3、如果左子树为空,则用右子女代替。
4、如果左子树和右子树都不为,则搜索该结点的右子树中搜索中序下的第一个结点,
赋值给该结点,再处理该中序结点的删除问题。:以删除的结点值的键值为键值,在当前结点的右子树中递归搜索删除该结点。
5、如果左右子树都为空,则直接删除。
void BinSearchTree::DeleteSearchNode(int key,BinSearchNode *&bsn)
{
//错误:current这个本地指针不是引用型形参,修改它的的情况未知,诀窍,只有引用型形参才能这样用
if(key>bsn->key)DeleteSearchNode(key,bsn->rSearchTree);
else if(key<bsn->key)DeleteSearchNode(key,bsn->lSearchTree);
else
{
BinSearchNode *p=NULL;
if(bsn->lSearchTree!=NULL&&bsn->rSearchTree!=NULL)
{
//下列写法不对
//要删除结点有两个子树
/*p=bsn;
//1、找到最小的键值
//bsn=bsn->rSearchTree; 这样写难道有错?
bsn=bsn->rSearchTree;
while(bsn->lSearchTree!=NULL)bsn=bsn->lSearchTree;
p->key=bsn->key;
//2、递归删除
DeleteSearchNode(bsn->key,bsn);*/
p=bsn->rSearchTree; //在右子树中寻找中序下的第一个结点
while(p->lSearchTree!=NULL)
p=p->lSearchTree; //第一个左子树
bsn->key=p->key; //用该结点值取代根结点数据
DeleteSearchNode(bsn->key,bsn->rSearchTree);
//:以删除的结点值的键值为键值,在当前结点的右子树中递归搜索删除该结点。
}
else
{
//引用型指针参数自动带动相关结点的修改
p=bsn;
//被删除结点有一个子树
if(bsn->lSearchTree==NULL)
bsn=bsn->rSearchTree;
else
bsn=bsn->lSearchTree;
delete p;
}
}
}
/*
寻找中序下的第一个结点指针:
*/
BinSearchNode* BinSearchTree::MinSearch(BinSearchNode *&bsn)
{
if(bsn!=NULL)
{
MinSearch(bsn->lSearchTree);
return bsn;
MinSearch(bsn->rSearchTree);
}
}
二叉搜素树是一种重要的搜索结果,下一节将构造一颗更优的二叉搜索树。