二叉查找树的其他操作:
(1)判断一个二叉树是否为二叉查找树;
1)分析:
二叉查找树的中序序列为递增序列,所以对一个二叉树进行中序遍历,如果始终保持当前节点的中序前驱节点pre的值小于当前节点的值,则是二叉查找树,否则不是。
2)代码实现:
DataType pre=0;//pre为全局变量,保持的是当前节点的中序前序的值,初始值为一个很小的值。
int isBST(BSTNode* t){
int judge1,judge2;
if(t==NULL) return 1;
else {
judge1=isBST(t->lchild);
if(judeg1==0 || pre>=t->data)
return 0;
pre=t->data;//更新前驱为当前节点
judeg2=isBST(b->rchild);
return judge2;
}
}
或者:
/*
目的:
判断以t为根节点的二叉树是否是二叉查找树,如果是则judge=1,否则judge=0;
注意:
judge,pre均为引用型参数;
pre为当前子树根结点t的中序前驱;
调用时:
t=root,pre=NULL,judge=1;
*/
void isBST(BSTNode* t ,BSTNode* & pre , int & judge){
if(t!=NULL && judge==1){
isBST(t->lchild,pre,judge);//递归左子树判断;
if(NULL==pre) {
pre=t;
judge=1;
}
else {
if(pre->data<t->data) {
pre=t;
judge=1;
}
else judge=0;
}
if(judge) isBST(t->rchild,pre,judge);
}
}
——-
(2)二叉查找树的每个节点中含有四个字段,分别为data,count,lchild,rchild;
count表示相同关键码的节点个数;当向二叉树中插入一个 节点时,如果已经存在则相应的count+1,
否则,插入新节点,并且count=1;
写出插入算法;
/*
在以t为根节点的二叉查找树中插入值为x的节点;
注意:
t,father为引用型参数;
father为插入的值为x的节点 父节点。
*/
void insert(BSTNode* &t ,BSTNode*& father, DataType x){
BSTNode* pnode=t;
//查找值为x的节点pnode,
//如果查找到,则pnode非空,father为其父节点,count++;
//如果没有找到,则pnode==NULL,father为值很靠近x的叶子节点。
while(pnode!=NULL){
if(pnode->data!=x){
father=pnode;
if(x<pnode->data)
pnode=pnode->lchild;
else
pnode=pnode->rchild;
}
else{
pnode->count++;
return ;
}
}
BSTNode* newNode=new BSTNode;//创建一个新节点
newNode->data=x;
newNode->count=1;
newNode->lchild=newNode->rchild=NULL;
if(father==NULL) //即:根节点t==null
t=newNode;
else if(x<father->data)
father->lchild=newNode;
else
father->rchild=newNode;
}
—-
(3)二叉查找树可以对n个元素进行排序:
1.将n个不同值的元素A[n]插入到二叉排序树中;
2.中序遍历,然后将元素存入到数组A中;
3.删除二叉查找树中的最大值;
代码实现:
1:略;
2:/*
中序遍历以t为根节点的二叉查找树,结果存在数组A[n]中,
n为排序后的数组长度。
注:初始时调用n的值为0;
n为引用型参数
*/
void inorderTraversal(BSTNode* t , DataType A[], int & n){
if(t){
inorderTraversal(t->lchild,A,n);
A[n++]=t->data;
inorderTraversal(t->rchild,A,n);
}
}
3:/*
目的:删除二叉查找树中的最大值节点;成功则返回1,否则返回0.
最大值节点是最右节点;
注:root为引用型参数
*/
int deleteMax(BSTNode* & root){
BSTNode* pnode=root;//
BSTNode* father=NULL;//father为pnode的父节点,pnode为father的右孩子。
if(NULL==root) return 0;
while(pnode->rchild!=NULL){
father=pnode;
pnode=pnode->rchild;
}//循环结束时,pnode为最右节点,没有右孩子,pnode为father的右孩子。
if(NULL==father)//原二叉查找树没有右子树
{
root=root->lchild;
delete pnode;
}
else {
father->rchild=pnode->lchild;
delete pnode;
}
return 1;
}
——
(4)已知一个递增的数组A[N],以哪个元素为根节点生成二叉查找树,使得树的平衡性最好?
1)分析:
以递增数组的居中的元素为根节点,按照折半查找的生成方法构造二叉查找树,生存的二叉查找树的平衡性比较好。
2)代码实现:
/*
目的:以一个递增的序列生成一个平衡性较好的二叉查找树;
注:root为引用型参数;
low,high分别为有序序列的上界和下界;初始值分别为0,n-1;n为数组长度。
array为递增的序列;
*/
void createBST(BSTNode* & root, int low ,int high ,DataType []array){
if(low>high) root=NULL;
else {
int mid=(high-low)/2+low;
root=new BSTNode;//创建根节点
root->data=array[mid];
createBST(root->lchild,low,mid-1,array);
createBST(root->rchild,mid+1,high,array)
}
}
——–
(5)求二叉查找树中某个节点p的层次;
1.方法一:层次遍历
2.方法二:利用二叉查找树的特性:
/*
在二叉查找树root中查找节点pnode的层次,如果找到则返回层次,否则返回0;
规定:根节点的层次为1;
*/
int level_count(BSTNode* root , BSTNode* pnode){
int level=0;
BSTNode* tempNode=root;
if(tempNode!=NULL){
level++;//非空,则根结点对应的层次为1;
while(tempNode!=NULL && tempNode->data!=pnode->data){
if(pnode->data<tempNode->data)
tempNode=tempNode->lchild;
else tempNode=tempNode->rchild;
level++;
}
if(tempNode==NULL) level=0;//没找到pnode,则level=0;
}
return level;
}
——
(6)判定一个给定的关键码序列是否为二叉查找树的查找序列:
1)分析:
由二叉查找树,查找路径的特点:
1。查找路径只可能沿着某个节点逐层向下,不可能往上回溯;
2.查找范围在关键码上下波动,且不断接近关键码;
3.在关键码左子树的查找序列小于关键码,为递增数组;
在关键码右子树的查找序列大于关键码,为递减数组;
举例:
给定一个值60,在二叉查找树上查找关键值为60的节点时,访问的关键码序列为S={20,30,90,80,40,50,70,60}.将S分为两个序列,S1为小于等于查找值60的数据,所以S1={20,30,40,50,60};
S2为大于查找值的数据,所以S2={90,80,70}.
因为S1中数据为递增,且每个元素小于等于待查数据,S2为递减数据,且每个数据大于待查数据,所以,S为查找序列。
2)代码实现:
#define Maxsize 20
typedef struct { //待认定的查找序列
DataType eleArray[Maxsize];
int len;//序列中实际的数据个数
}Sequence;
/*
将序列S划分为两个序列s1,s2;
注:s,s1,s2为引用型参数;
*/
void devision(Sequence &s ,Sequence &s1, Sequence & s2){
int i=0,i1=0,i2=0;
do{
while(i+1<=s.len-1 && s.eleArray[i]<s.eleArray[i+1])
s1.eleArray[i1++]=s.eleArray[i];//将s中有递增趋势的元素放到s1中;
while(i+1<=s.len-1 && s.eleArray[i]>s.eleArray[i+1])
s2.eleArray[i2++]=s.eleArray[i];//将s中有递减趋势的元素放到s2中;
}while(i+1<=s.len-1)//因为循环内i+1为下标
//上例中,s1={20,30,40,50},s2={90,80,70};
s1.len=i1;
s2.len=i2;
}
/*
判断s1是否为递增序列,且所有元素小于x;s2是否为递减序列,且所有元素大于x
*/
int judge(Sequence& s1, Sequence & s2, int x){
int flag=1;
int i=0;
while(flag && i+1<=s1.len-1){
if(s1.eleArray[i]>s1.eleArray[i+1] || s1.eleArray[i]>x)
flag=0;
else i++;
}
i=0;
while(flag && i+1<=s2.len-1){
if(s2.eleArray[i]<s2.eleArray[i+1] || s2.eleArray[i]<x )
flag=0;
else i++;
}
return flag;
}
/*判断是否为查找序列*/
int isBSTsearchSequence(Sequence& s,int x){
Sequence s1,s2;
division(s,s1,s2);
return judge(s1,s2,x);
}
——-
(7)删除二叉查找树中值小于等于x的所有节点;
1)分析:
1.若节点pnode的值data<=x,则删除pnode以及pnode的左子树,用pnode的右子树代替pnode,
然后重复此操作,直至pnode->data>x;
2.若节点pnode->data>x,则沿着pnode的左分支搜索,直至pnode->data<=x,然后回到1删除。
2)代码实现:
/*
后序遍历,删除以p为根节点子树。
*/
void deleteSubTree(BSTNode* p){
if(p){
deleteSubTree(p->lchild);//删除左子树;
deleteSubTree(p->rchild);//删除右子树
delete p;
}
}
/*
删除小于等于x的节点
*/
void delete_LQ_x(BSTNode* & root, DataType x){
BSTNode* pnode=root,*father=NULL;
BSTNode* tempNode;
while(pnode!=NULL && pnode->data<=x){
tempNode=pnode;
pnode=pnode->rchild;//用右子树取代当前节点
deleteSubTree(tempNode->lchild);//将pnode的左子树删除
delete tempNode;
if(father!=NULL) father->lchild=pnode;
//因为father节点为大于x的,pnode作为father的左孩子被删除后,
// father的lchild就找不到了。所以需更新。
if(pnode->data>x){//用右子树替换后的pnode的值如果大于x
while(pnode!=NULL && pnode->data>x){
father=pnode;
pnode=pnode->lchild;
}
}
}
}
——-