二叉搜索树概念:打劫:大的站右边,小的站左边,不大不小站中间。
也就是任何结点,左子树上的值均小于根结点的值,且根结点值小于所有右子树上的值。
分为递归实现和非递归实现。我不太清楚两种方案分别的优势,希望各位大佬给指点一下。
头文件↓
#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;
}