二叉搜索树的基本操作

定义:只要这棵树中每个节点的左孩子都小于这个节点,右孩子都大于这个节点,那么这棵树就是一个二叉搜索树。


性质

(01) 若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 
(02) 任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 
(03) 任意节点的左、右子树也分别为二叉查找树; 
(04) 没有键值相等的节点(no duplicate nodes);



首先给出头文件 

#ifndef __BSTREE_H__
#define __BSTREE_H__
 
#include<stdio.h>
#include<assert.h>
#include<malloc.h>

typedef int DataType;
typedef struct BSTreeNode
{
  DataType data;
  struct BSTreeNode *Left;
  struct BSTreeNode *Right;
}BSTreeNode ,*PBSTreeNode;

//初始化
void BSTreeNodeInit(PBSTreeNode* pp);

//插入
void InsertBSTreeNode(PBSTreeNode* pp,DataType data);



//获得一个新的节点
PBSTreeNode BuyBSTreeNode(DataType data);

//删除搜索二叉树节点
void  DeleteBSTreeNode(PBSTreeNode * pp,DataType data);

//递归法查找节点
int  FindBSTree(PBSTreeNode pp,DataType data);

//递归法插入
void RecInsertBSTree(PBSTreeNode* pp,DataType data);

//递归法删除
void RecDeleteBSTree(PBSTreeNode* pp,DataType data);
#endif //__BSTREE_H__

搜索二叉树的创建,我们直接通过给初始化好的树节点指针域插入即可

所以我们先来初始化一个树节点指针域

//初始化
void BSTreeNodeInit(PBSTreeNode* pp)
{
  assert(pp);
  *pp=NULL;
}

要插入节点就必须要创建一个节点

//获得一个新的节点
PBSTreeNode BuyBSTreeNode(DataType data)
{
  PBSTreeNode ret;
  ret=(PBSTreeNode)malloc(sizeof(BSTreeNode));
  if(ret==NULL)
  {
    return NULL;
  }
  ret->data=data;
  ret->Left=NULL;
  ret->Right=NULL;
  return ret;
}


下面只要进行从插入就可以了,只不过有有一定规则

实际就是搜索二叉树的性质,大于根节点进入右子树,小于根节点进入左子树 ,来看看代码

//插入
void InsertBSTreeNode(PBSTreeNode * pp,DataType data)
{
  PBSTreeNode parent;
  PBSTreeNode pCur;
  assert(pp);
  if(*pp==NULL)//空树,直接赋给根指针
  {
	 *pp =BuyBSTreeNode(data);
   }
  pCur=*pp;
  while(pCur)//寻找插入点
  {
	  if(data>pCur->data)
	  {
		  parent=pCur;//将将要插入的节点的双亲节点标记起来
		  pCur=pCur->Right;
	  }
	  else if (data<pCur->data)
	  {
		  parent=pCur; //同上
		  pCur=pCur->Left;
	  }
	  else //找到了
	  {
	    return ;
	  }
  }
  if(data>parent->data)//判断将要插入的节点是左子树还是右子树
  {
	  parent->Right=BuyBSTreeNode(data);
  }
  else
  {
	  parent->Left=BuyBSTreeNode(data);
  }
}

通过不断地插入,就可以创建一个搜索二叉树

然后还必须实现删除这棵树的节点的功能

分析删除节点可能遇到的情况




                                                           

    情况1:根节点                                            情况1:不是根

                                                                                         

情况2:根节点                                                                                                                    情况2:不是根节点


                                         


     情况3:不是根节点                                                                    情况3:是根节点



情况4:左右孩子都在

下面来看看代码

//删除搜索二叉树节点
void  DeleteBSTreeNode(PBSTreeNode * pp,DataType data)
{
  PBSTreeNode pCur;
  PBSTreeNode parent;
  PBSTreeNode pDel;

  assert(pp);
  pCur=*pp;
   while(pCur)//找到待删除的节点
  {
	  if(data>pCur->data)
	  {
		  parent=pCur;
		  pCur=pCur->Right;
	  }
	  else if (data<pCur->data)
	  {
		  parent=pCur;
		  pCur=pCur->Left;
	  }
	  else 
	  {
	    break ;
	  }
  }
  if(pCur==NULL)//说明就没有该节点
  {
    return ;
  }

   //右孩子为空,包含两种情况,叶子结点和只有左孩子
   if(pCur->Right==NULL)
   {
	   if(pCur==*pp)//是根节点
	   {
	     
		 *pp=pCur->Left;
         
	   }
	   else//不是根节点
	   {
	     //是父亲节点的左孩子
		   if(parent->Left==pCur)
		   {
			   parent->Left=pCur->Left;
			   
		   }
		   //是父亲节点的右孩子
		   else
		   {
			   parent->Right=pCur->Left;
			  
		   }
	   }
   }
   //只有右孩子,
   else if (pCur->Left==NULL)
   {
      if(pCur==*pp)//是根节点
	   {
	     
		 *pp=pCur->Right;
         
	   }
	   else//不是根节点
	   {
	     //是父亲节点的左孩子
		   if(parent->Left==pCur)
		   {
			   parent->Left=pCur->Right;
			  
		   }
		   //是父亲节点的右孩子
		   else
		   {
			   parent->Right=pCur->Right;
			  
		   }
	   }
   }
   else
   {
     //左右孩子都存在,方法是找到一个替代的节点,将该节点的值交给待删节点,后删掉替代节点
      
        
		pDel=pCur->Left;
		parent=pCur;//处理不能进入循环的情况
		
		while(pDel->Right)//寻找待删节点的左子树中最大值,也就是一直顺着右找
		{
		  parent=pCur;
		  pCur=pCur->Right;
		}
		pCur->data=pDel->data;//将最大值交给待删节点
		
		if(pDel==parent->Left)//是父亲节点的左孩子
		{
			parent->Left=pDel->Left;		  
		}
		else//是父亲节点的右孩子
		{
			parent->Right=pDel->Left;
		}
		pCur=pDel;
   }
   free(pCur);
}

下面再来说说递归法解决这些问题

第一个是递归法查找节点是否存在

个人觉得这是一种单线的递归,而遍历二叉树那种遍历是双线的递归

//递归法查找节点
int  FindBSTree(PBSTreeNode pp,DataType data)
{
  
  if(pp==NULL)
  {
    return 0;
  }
  if(data==pp->data)
  {
    return 1;
  }
  if(data>pp->data)
  {
	  return FindBSTree(pp->Right,data);
  }
  else
	  
  {
	  return FindBSTree(pp->Left,data);
  }

}
//递归法插入
void RecInsertBSTree(PBSTreeNode* pp,DataType data)
{
	assert(pp);
  if(*pp==NULL)
  {
    *pp=BuyBSTreeNode(data);
  }
  else
  {
		 if(data<(*pp)->data)
	     {
		  RecInsertBSTree((&(*pp)->Left),data);
	      }
	     else
	     {
		  RecInsertBSTree((&(*pp)->Right),data);
	     }

  }
}
//递归法删除
void RecDeleteBSTree(PBSTreeNode* pp,DataType data)
{
  PBSTreeNode pDel;

	//1,先找出待删除节点
  if(*pp==NULL)
  {
     return ;
  }
  if(data>(*pp)->data)
  {
	   RecDeleteBSTree(&(*pp)->Right,data);
	   return;
  }
  else if(data<(*pp)->data)
  {
	   RecDeleteBSTree(&(*pp)->Left,data);
	   return;
  }
  else//进入这个条件说明找到了
  {
     //和之前一样,分4种情况,我们选择将叶子节点和有右孩子一起处理
      pDel=*pp;
	  if(pDel->Left==NULL)//叶子和只有右
	  {
        (*pp)=pDel->Right;
		free(pDel);
	  }
	  else if(pDel->Right==NULL)//只有左
	  {
		  *pp=pDel->Left;
		  free(pDel);
	  }
	  else//左右都有
	  {
		  pDel=pDel->Left;//进入左
		  while(pDel->Right)//找最大值()替代节点
		  {
			  pDel=pDel->Right;
		  }
		  (*pp)->data=pDel->data;//赋值
		   RecDeleteBSTree(&pDel,pDel->data);//删除代替节点
		   return;
	  }


  }
  
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值