二叉搜索树及其相关操作

二叉搜索树概念:打劫:大的站右边,小的站左边,不大不小站中间。

也就是任何结点,左子树上的值均小于根结点的值,且根结点值小于所有右子树上的值。

分为递归实现和非递归实现。我不太清楚两种方案分别的优势,希望各位大佬给指点一下。

 头文件↓

#ifndef BINARY_H
#define BINARY_H
#define ElementType int
typedef struct node{//声明二叉树节点结构体 
	ElementType value;
	struct node *lchild,*rchild;
}Tnode;
typedef Tnode Tree;
#endif
/*递归实现*/ 
Tree *Insert(Tree *pTree,ElementType value);//插入节点 
Tree *Dele(Tree *pTree,ElementType value);//删除节点 
Tree *FindMax(Tree *pTree);//寻找最大值节点 

/*非递归实现*/
void insert(Tree **pTree,ElementType value);//插入节点 
void dele(Tree **pTree,ElementType value); //删除节点

void Traversal(Tree *pTree);//遍历验证

递归实现插入和删除↓ 

/*递归实现各项操作*/ 
#include <stdio.h>
#include <stdlib.h>
#include "binarytree.h"
Tree *Insert(Tree *pTree,ElementType value){//传入形参是一级指针,无法修改实参,需要返回值
	Tree *pT=pTree;
	if(!pT){                                //空树插入结点
		pT=(Tree *)malloc(sizeof(Tnode));
		pT->value=value;
		pT->lchild=pT->rchild=NULL;
	}else if(value<pT->value){              //插入值小于树根值
		pT->lchild=Insert(pT->lchild,value);//递归插入左子树
	}else if(value>pT->value){              //插入值大约树根值
		pT->rchild=Insert(pT->rchild,value);//递归插入右子树
	}
	return pT;                              //将新结点地址返回到调用函数
}
Tree *Dele(Tree *pTree,ElementType value){  //传入形参是一级指针,无法修改实参,需要返回值
	Tree *pT=pTree;
	if(!pT) printf("数据不存在,删除失败");   
	else{
		if(value==pT->value){               //预删除value等于该结点value
			if(pT->lchild&&pT->rchild){     //该结点左右子树都不为空
				Tree *pTemp=FindMax(pT->lchild);
				pT->value=pTemp->value;     //转换为删除该结点左子树的最大值或右子树的最小值
				pT->lchild=Dele(pT->lchild,pT->value);
			}else if(!pT->lchild){          //该结点左子树为空,右子树直接替换该结点
				pT=pT->rchild;
			}else{                          //该结点右子树为空,左子树直接替换该结点
				pT=pT->lchild;
			}
		}else if(value<pT->value){          //预删除value小于该结点value
			pT->lchild=Dele(pT->lchild,value);//递归到左子树删除
		}else{                              //预删除value大于该结点value
			pT->rchild=Dele(pT->rchild,value);//递归到右子树删除
		}
	}
	return pT;                              //将删除后该位置新结点地址返回到调用函
}
Tree *FindMax(Tree *pTree){                 //查找二叉搜索树的最大值
	while(pTree->rchild){
		pTree=pTree->rchild;
	}
	return pTree;
}
void Traversal(Tree *pTree){                //遍历验证程序结果,可用前中后序遍历分别验证
	if(pTree){
		printf("%d\n",pTree->value);
		if(pTree->lchild) Traversal(pTree->lchild);
		if(pTree->rchild) Traversal(pTree->rchild);
	}
}

非递归实现插入和删除 

/*非递归实现*/
void insert(Tree **pTree,ElementType value){//无返回值,需传入二级指针
	Tree *pT=*pTree;
	Tree *pTemp=(Tnode*)malloc(sizeof(Tnode));//先创建插入节点
	pTemp->lchild=pTemp->rchild=NULL;
	pTemp->value=value;
	if(!pT){
		*pTree=pTemp;                         //空树直接赋值
	}else{
		while(pT){                            //非空树找插入位置
			Tree *parentNode=pT;              //需要找到要插入位置的父节点
			if(value<pT->value){
				pT=pT->lchild;
				if(!pT) parentNode->lchild=pTemp;//此处pT为空说明在父节点的左子树
			}else if(value>pT->value){
				pT=pT->rchild;
				if(!pT) parentNode->rchild=pTemp;//此处pT为空说明在父节点的右子树
			}
		}
	}
}
void dele(Tree **pTree,ElementType value){//删除和插入一样需要找到父节点并赋空相应子树
	Tree *pT=*pTree;
	Tree *parentNode=NULL;
	int flag=0;
	while(pT&&value!=pT->value){          //非空节点且不是预删除节点,查找预删除节点
		parentNode=pT;                    //记录父节点
		if(value<pT->value){
			flag=0;                       //记录预删除节点为父节点的左子树
			pT=pT->lchild;
		}else{
			flag=1;                       //记录预删除节点为父节点的右子树
			pT=pT->rchild;
		}
	}
	if(!pT){
		printf("无此节点,删除失败");
	}else{
		if(pT->lchild&&pT->rchild){       //预删除节点左右子树都不空 
			Tree *p=pT->lchild;		// p记录左子树上的最大值或右子树上的最小值,替换预删除节点 
			parentNode=pT;				  // 定位p的父节点,当pT左子树只有一个节点,父节点为pT
			while(p->rchild){             //查找左子树上的最大值
				parentNode=p;			  //定位p的父节点 
				p=p->rchild;			  //找到pT左子树上的最大值  
			}
			pT->value=p->value;          //替换预删除节点的值,预删除节点变为左子树上的最大值p 
			
			/*预删除节点为最大值则为父节点的右子树,将预删除节点左子树赋给父节点*/
			if(parentNode!=pT) parentNode->rchild=p->lchild;
			else parentNode->lchild=p->rchild;		//
			free(p);//释放预删除节点,删除完成
		}else if(!pT->lchild){           //预删除节点左子树为空,右子树可空可不空
			if(flag==0) parentNode->lchild=pT->rchild;//flag记录预删除节点在父节点的左
			if(flag==1) parentNode->rchild=pT->rchild;//flag记录预删除节点在父节点的右
			free(pT);
		}else if(!pT->rchild){            //预删除节点右子树为空,左子树可空可不空
			if(flag==0) parentNode->lchild=pT->lchild;
			if(flag==1) parentNode->rchild=pT->lchild;
			free(pT);
		}
	}
} 

main函数↓ 

#include <stdio.h>
#include <stdlib.h>
#include "binarytree.h"
/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int main(int argc, char *argv[]){
	Tree *pTree=NULL;
//	pTree=Insert(pTree,5);
//	pTree=Insert(pTree,3);
//	pTree=Insert(pTree,7);
//	pTree=Insert(pTree,1);
//	pTree=Insert(pTree,4);
//	pTree=Insert(pTree,6);
//	pTree=Insert(pTree,8);
//	pTree=Insert(pTree,2);
	insert(&pTree,5);
	insert(&pTree,3);
	insert(&pTree,7);
	insert(&pTree,1);
	insert(&pTree,4);
	insert(&pTree,6);
	insert(&pTree,8);
	insert(&pTree,2);
	
	Traversal(pTree);
//	pTree=Dele(pTree,3);
	dele(&pTree,3);
	Traversal(pTree);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值