2-3树的实现

#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<memory.h>
#define NUM(p) (p==NULL?0:p->num)
#define GETP(p) (p==NULL?NULL:p->parent)
#define GETR(p) (p==NULL?NULL:p->rightNode)
#define GETL(p) (p==NULL?NULL:p->leftNode)
#define GETM(p) (p==NULL?NULL:p->midNode)
#define nil NULL;
#define null NULL;

/**
*title:2-3Tree
*time:2019-3-23 11:04:04 
*author:SrV-330
*
*/
//树结点
typedef struct TreeNode{
	int value[3];//存储值的数组  含有三个元素
	int num;
	struct TreeNode* rightNode;	//指向右结点
	struct TreeNode* leftNode;     //指向左结点     //3树结构会有三个结点
	struct TreeNode* midNode;      //指向中间结点 
	struct TreeNode* tmpNode;  //作为四结点的缓存结点 
	struct TreeNode* parent;     //指向双亲结点

}tn,*ptn;
//修复
void fixup(ptn p,ptn *root);
ptn createTreeNode(int value);//创建一个树结点
//交换
void change(int* a,int* b);
//插入一个结点
ptn insertTreeNode(ptn p,ptn* rootp){
	ptn pn;
	ptn move=p;
	
	ptn movep=p;

	int value =0;
	for(fflush(stdin);scanf("%d",&value)!=1;fflush(stdin),value=0);//输入1表示终止
	if(value==-1)return null;// 如果value值等于-1  那么这个函数返回null

	ptn tr=GETR(move);//如果p=move不为空 那么tr指向rightNode结点
	ptn tl=GETL(move);//下面是同样的道理  tl指向leftNode 
	ptn tm=GETM(move);//tm=midNode
	while(!(!tr&&!tl&&!tm)){//如果这三个指针不全为空
		if(NUM(move)==1){//根据7行代码可知   如果move不是空  那么NUM(move)=move->num  此时move是一个二树
			if(value<move->value[0]){//如果输入的value值小于value[0]
				movep=move;
				move=move->leftNode;//将move的左指针指赋值给move
			}else {
				movep=move;
				move=move->rightNode;//否则就是将右指针赋值给move
			}
			
		}else if(NUM(move)==2){//如果move的num值等于2  此时move是一个3树
			if(value<move->value[0]){
				movep=move;
				move=move->leftNode;
			}else if(value>move->value[1]){
				movep=move;
				move=move->rightNode;
			}else {
				movep=move;
				move=move->midNode;
			}
			
		}
		
		tm=GETM(move);
		tr=GETR(move);
		tl=GETL(move);
	}
	
	if(NUM(move)==1){//如果原先是一个2树 那么增加一个结点后  num++  然后将加入的值放value[num]数组中去
		move->value[move->num]=value;
		move->num++;
		//交换一个左右的顺序
		if(move->value[0]>move->value[1])
		change(&(move->value[0]),&(move->value[1]));
	//这一步是调整一下位置关系
		fixup(move,rootp);
		return move;
	}else if(NUM(move)==2){//这种情况本来是3树
		move->value[move->num]=value;
		move->num++;
		//将value[]数组中元素按照从小到大的顺序排列
		if(move->value[1]>move->value[2])
		change(&(move->value[1]),&(move->value[2]));
		if(move->value[0]>move->value[1])
		change(&(move->value[0]),&(move->value[1]));
		fixup(move,rootp);
		return move;	
		
	}else{
		//如果move指针为空 那么就新创建一个指针
		pn=createTreeNode(value);
		pn->parent=p;//p就是pn的双亲结点
		fixup(pn,rootp);
		return pn;
		
	}
	
	
	
	
}
//创建一个树结点
ptn createTreeNode(int value){
	//分配空间
	ptn pn=(ptn)malloc(sizeof(tn));
	pn->num=0;
	pn->value[pn->num]=value;//将传入参数value赋值给数组对应num位置的值
	pn->num++;//num++数递增
	//将结构体中定义的结点全部指向空
	pn->leftNode=null;
	pn->rightNode=null;
	pn->midNode=null;
	pn->tmpNode=null;
	pn->parent=null;
	return pn;
}
//输出这个树的信息
void printTree(ptn root,int deep){
	if(NUM(root)==0) return;//如果输入的root是一个空树  直接退出
	deep++;//将这个树的深度递增
	printTree(root->rightNode,deep);//遍历右指针
	
	if(NUM(root)==2){
		for(int j=0;j<deep;j++){
			printf(" ");
		}
		printf("%d\n",root->value[1]);//如果root中num的值为2,则输出数组中value[1]的值
	}
	printTree(root->midNode,deep);//输入这个树的中间结点的信息
	for(int j=0;j<deep;j++){
		printf(" ");
	}
	printf("%d\n",root->value[0]);//输出数组value(0)的值
	printTree(root->leftNode,deep);//再遍历左结点
	//这是一个23 树 只有两个值 分别存储在value[0]和value[1]中
	
}
	//交换a,b  在给value数组排序的时候将会用到
void change(int *a,int *b){
	int t=(*a);
	(*a)=(*b);
	(*b)=t;
}
void fixup(ptn p,ptn *root){
	ptn move=p;
	ptn movep=GETP(p);//movep指向p的双亲结点
	if(!p) return;//如果是一棵空树  直接返回
	if(NUM(move)==3&&!movep){//如果move=p不为空 且没有双亲结点  其实就是根结点
		ptn b=createTreeNode(move->value[1]);//用value[1]中存储的值 创建一个新的结点
		ptn c=createTreeNode(move->value[2]);//value[2]中保存的值创建一个新的结点
		move->num=1;//将move的num值降到1
		b->leftNode=move;//将move变成b结点左孩子
		b->rightNode=c;//c变成b结点的右孩子  
		//这个两个结点的双亲结点都是p
		move->parent=b;
		c->parent=b;
		
		c->rightNode=move->rightNode;
		c->leftNode=move->tmpNode;
		move->rightNode=move->midNode;
		move->midNode=null;
		move->tmpNode=null;
		
		(*root)=b;
		
		
			
	}else if(NUM(move)==3&&NUM(movep)==1&&GETL(movep)==move){
		movep->value[movep->num]=move->value[1];
		(movep->num)++;
		change(&(movep->value[0]),&(movep->value[1]));
		ptn c=createTreeNode(move->value[2]);
		c->parent=movep;
		movep->midNode=c;
		move->num=1;
		
		c->rightNode=move->rightNode;
		move->rightNode=move->midNode;
		
		c->leftNode=move->tmpNode;
		move->tmpNode=null;
		move->midNode=null;
		
		
		
	}else if(NUM(move)==3&&NUM(movep)==1&&GETR(movep)==move){
		
		movep->value[movep->num]=move->value[1];
		movep->num++;
		
		ptn d=createTreeNode(move->value[2]);
		d->parent=movep;
		movep->rightNode=d;
		move->num=1;
		movep->midNode=move;
		
		d->rightNode=move->rightNode;
		move->rightNode=move->midNode;
		d->leftNode=move->tmpNode;
		move->tmpNode=null;
		move->midNode=null;
		
		
		
	}else if(NUM(move)==3&&NUM(movep)==2&&GETL(movep)==move){
		
		movep->value[movep->num]=move->value[1];
		movep->num++;
		change(&(movep->value[0]),&(movep->value[2]));
		change(&(movep->value[1]),&(movep->value[2]));
		ptn c=createTreeNode(move->value[2]);
		c->parent=movep;
		movep->midNode=c;
		move->num=1;
		
		c->rightNode=move->rightNode;
		move->rightNode=move->midNode;
		c->leftNode=move->tmpNode;
		move->midNode=null;
		move->tmpNode=null;
		
		fixup(movep,root);
	}else if(NUM(move)==3&&NUM(movep)==2&&GETM(movep)==move){
		
		movep->value[movep->num]=move->value[1];
		movep->num++;
		change(&(movep->value[1]),&(movep->value[2]));
		ptn d=createTreeNode(move->value[2]);
		d->parent=movep;
		movep->tmpNode=d;
		move->num=1;
		
		
		d->rightNode=move->rightNode;
		move->rightNode=move->midNode;
		d->leftNode=move->tmpNode;
		move->midNode=null;
		move->tmpNode=null;
		
		fixup(movep,root);
	}else if(NUM(move)==3&&NUM(movep)==2&&GETR(movep)==move){
		movep->value[movep->num]=move->value[1];
		movep->num++;
		change(&(movep->value[1]),&(movep->value[2]));
		ptn c=createTreeNode(move->value[2]);
		c->parent=movep;
		movep->tmpNode=c;
		move->num=1;
		
		
		c->leftNode=move->leftNode;
		move->leftNode=move->tmpNode;
		c->rightNode=move->midNode;
		move->midNode=null;
		move->tmpNode=null;
		
		fixup(movep,root);
		
	}else{
		return;
	}
	
}
//销毁树  释放每个结点指向的空间  也用到了递归的思想
void dropTree(ptn root){
	if(!root) return;
	if(root->leftNode){
		free(root->leftNode);
	}
	if(root->rightNode){
		free(root->rightNode);
	}
	if(root->midNode){
		
		free(root->midNode);
	}
	if(root->tmpNode){
		free(root->tmpNode);
	}
	free(root);
	root=null;
}
main(){
	
	ptn root=null;
	ptn* rootp=null; //双亲结点
	ptn node=null;
	
	node=insertTreeNode(root,rootp);
	root=node;
	rootp=&root;
	do{
		node=insertTreeNode(root,rootp);	
	}while(node!=NULL);
	
	printTree(root,0);
	dropTree(root);
	
	
	
}


对于2-3树的具体实现过程 比较抽象 这里附上代码方便以后调用添加链接描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值