二叉查找树的其他操作



二叉查找树的其他操作:

(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;
    }
   }
 }

}

——-

    原文作者:二叉查找树
    原文地址: https://blog.csdn.net/legend050709/article/details/38847103
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞