2-3树

这几天学习和实现了《数据结构(c语言版)》(李建中等人翻译的那本)里介绍的2-3树!

说实在,我若过一段时间来看这里的代码,估计我也看不懂了,不过结合书和书里的笔记,我想我还看得懂。

对以下代码有兴趣的学者,应该结合那本书来看吧!!!

大概说下:

插入:

a:待插入点,是2节点的,就往这里插入即可。

b:  待插入点,是3节点的,拆分这个节点。(小值留下,中值待定,大值放入新节点)。同时还得分这个被split的节点是左中右节点来分别处理。

删除:

....看书吧,情况分为7种或8种........

#include <stdio.h>
#include <limits.h>
#include <stdlib.h>

//INT_MAX
#define NODE_SIZE 100
typedef struct two_three *two_three_ptr;
typedef int element;
struct two_three{
	element data_l,data_r;
	two_three_ptr left_child,middle_child,right_child;
};

two_three_ptr node[NODE_SIZE];//for insert
int nodetop=0;

two_three_ptr nodedel[NODE_SIZE];//for delete
int nodedeltop=0;

int compare(two_three_ptr t,element x);
void pushnode(two_three_ptr t,two_three_ptr *n,int *top);
two_three_ptr popnode(two_three_ptr *n,int *top);
two_three_ptr search23(two_three_ptr t,element x);//search
void insert23(two_three_ptr *t,element y);//insert
void new_root(two_three_ptr *t,element y,two_three_ptr q);//新的根节点
two_three_ptr find_node(two_three_ptr t,element y,two_three_ptr *n,int *top);//关键字在否
void put_in(two_three_ptr p,element y,two_three_ptr q);
void split(two_three_ptr p,element *y,two_three_ptr *q);

void delete23(two_three_ptr *t,element y);//delete
two_three_ptr change(two_three_ptr d,element y);//交换节点
void deleteleaf(two_three_ptr *t,two_three_ptr d,element y);//删除叶子d节点上的y元素
void deleteone(two_three_ptr *t,two_three_ptr d);

void a_rotate(two_three_ptr *t,two_three_ptr p,two_three_ptr s);
void b_rotate(two_three_ptr *t,two_three_ptr p,two_three_ptr s);
void c_rotate(two_three_ptr *t,two_three_ptr p,two_three_ptr s);
void a_merge(two_three_ptr *t,two_three_ptr p,two_three_ptr s);
void b_merge(two_three_ptr *t,two_three_ptr p,two_three_ptr s);
void c_merge(two_three_ptr *t,two_three_ptr p,two_three_ptr s);
void d_merge(two_three_ptr *t,two_three_ptr p,two_three_ptr s);
void e_merge(two_three_ptr *t,two_three_ptr p,two_three_ptr s);

two_three_ptr search23(two_three_ptr t,element x)//search
{
	int i=0;
	while(t)
	{
		++i;
		switch( compare(t,x) )
		{
			case 1:t=t->left_child;break;
			case 2:t=t->middle_child;break;
			case 3:t=t->right_child;break;
			case 4:{printf("%d层",i); return t;}
			default:
			 fprintf(stderr,"have a error in search23\n");
		}
	}

	return NULL;
}

void insert23(two_three_ptr *t,element y)//insert
{//y是元素, p是栈上的节点,q是新节点
	two_three_ptr q,p;
		if( !(*t) )//tree is empty
		new_root(t,y,NULL);
		else{
			p=find_node(*t,y,node,&nodetop);//关键字在否
			if(!p)
			{
				fprintf(stderr,"the key is currently in the tree\n");
				exit(1);
			}
			q=NULL;
			while(1)
			{
				if(p->data_r == INT_MAX)
				{//2 node
					put_in(p,y,q);
					break;
				}
				else{
					split(p,&y,&q);
					if(p == *t)
					{//split the root
						new_root(t,y,q);
						break;
					}
					else
						p=popnode(node,&nodetop);//remote a node from stack
				}
			}
		}
}

int compare(two_three_ptr t,element x)//查找元素在哪里
{
	if (x < t->data_l)
		return 1;
	else if(x == t->data_l)
		return 4;
	else if(x > t->data_l && x < t->data_r)
		return 2;
	else if(x == t->data_r)
		return 4;
	else if(x > t->data_r)
		return 3;
  return 0;
}
void new_root(two_three_ptr *t,element y,two_three_ptr q)//新的根节点
{
	two_three_ptr n=(two_three_ptr)calloc(1,sizeof(two_three));
	n->data_l=y;
	n->data_r=INT_MAX;

	n->left_child=*t;
	n->middle_child=q;
	n->right_child=NULL;

	*t=n;
}
two_three_ptr find_node(two_three_ptr t,element y,two_three_ptr *n,int *top)//关键字在否
{
	while(t)
	{
		pushnode(t,n,top);
		switch( compare(t,y) )
		{
			case 1:t=t->left_child;break;
			case 2:t=t->middle_child;break;
			case 3:t=t->right_child;break;
			case 4:return NULL;//有这个关键字了,返回NULL
		}
	}
	return n[--(*top)];//返回关键字应该插入的地方
}
void put_in(two_three_ptr p,element y,two_three_ptr q)
{
	if (y < p->data_l)
	{
		p->right_child=p->middle_child;
		p->middle_child=q;

		p->data_r=p->data_l;
		p->data_l=y;
	}
	else  //y>p->data_l
	{
		p->data_r=y;
		p->right_child=q;
	}
}

void split(two_three_ptr p,element *y,two_three_ptr *q)
{
	//分为 小值(左孩子过来),中值(中孩子过来的),大值(右孩子过来的)
	element temp;
	two_three_ptr n=(two_three_ptr)calloc(1,sizeof(two_three));
	if (*y < p->data_l)//小值(左孩子过来),
	{
		n->data_l=p->data_r;		

		n->left_child=p->middle_child;
		n->middle_child=p->right_child;

		temp=p->data_l;
		p->data_l=*y;

		p->middle_child=*q;		

		*y=temp;
	}
	else if (*y > p->data_l && *y < p->data_r)//中值(中孩子过来的)
	{
		n->data_l=p->data_r;

		n->left_child=*q;
		n->middle_child=p->right_child;

	}
	else if (*y > p->data_r)//大值(右孩子过来的)
	{
		n->data_l=*y;

		n->left_child=p->right_child;
		n->middle_child=*q;

		*y=p->data_r;

	}
	*q=n;
	p->data_r=INT_MAX;
	p->right_child=NULL;

	n->data_r=INT_MAX;

}
void pushnode(two_three_ptr t,two_three_ptr *n,int *top)
{
	if (*top == NODE_SIZE)
	{
		printf("error :nodetop is too high");
	}
	n[(*top)++]=t;//++的优先级高于 *  ;这里一开始错了我
}
two_three_ptr popnode(two_three_ptr *n,int *top)
{
	if (*top == 0)
	{
		printf("error :nodetop is less zero");
	}
	return n[--(*top)];
}

void delete23(two_three_ptr *t,element y)//delete
{
	two_three_ptr temp;
	if(find_node(*t,y,nodedel,&nodedeltop) == NULL)
	{//存在
		temp=popnode(nodedel,&nodedeltop);
		if (temp->left_child == NULL){//是叶子节点
			deleteleaf(t,temp,y);
		}
		else{//非叶子节点,这里找左子树的最大值来做替换
			pushnode(temp,nodedel,&nodedeltop);
			temp=change(temp,y);
			deleteleaf(t,temp,y);
		}
	}
	else{//不存在
			printf("element is not exist\n");
	}
}
void deleteleaf(two_three_ptr *t,two_three_ptr d,element y)//删除叶子d节点上的y元素
{
	if (d->data_r == y)//两个值的最右值
	{
		d->data_r=INT_MAX;
	}
	else if (d->data_l == y && d->data_r !=INT_MAX )//两个值的最左值
	{
		d->data_l=d->data_r;
		d->data_r=INT_MAX;
	}
	else//一个节点的,删除后要旋转或合并,大头啊!!!
	{
		deleteone(t,d);
	}

}
void deleteone(two_three_ptr *t,two_three_ptr d)
{
	d->data_l=INT_MAX;

	while(d->data_l == INT_MAX)
	{
		if (d == *t)
		{
			*t=d->left_child;
			break;
		}

		two_three_ptr parent=popnode(nodedel,&nodedeltop);
		if (parent->left_child==d && parent->middle_child->data_r != INT_MAX)//a旋转
			a_rotate(t,parent,d);
		else if (parent->middle_child==d && parent->left_child->data_r != INT_MAX)//b旋转
			b_rotate(t,parent,d);
		else if (parent->right_child==d && parent->middle_child->data_r != INT_MAX)//c旋转
			c_rotate(t,parent,d);

		else if (parent->left_child==d &&  parent->data_r == INT_MAX && parent->middle_child->data_r == INT_MAX)//a合并
			a_merge(t,parent,d);
		else if (parent->left_child==d &&  parent->data_r != INT_MAX &&  parent->middle_child->data_r == INT_MAX)//b合并
			b_merge(t,parent,d);

		else if (parent->middle_child==d &&  parent->data_r == INT_MAX &&  parent->left_child->data_r == INT_MAX)//c合并
			c_merge(t,parent,d);
		else if (parent->middle_child==d &&  parent->data_r != INT_MAX &&  parent->left_child->data_r == INT_MAX)//d合并
			d_merge(t,parent,d);

		else if (parent->right_child==d && parent->middle_child->data_r == INT_MAX)//e合并
			e_merge(t,parent,d);

		d=parent;
	}

}
void a_rotate(two_three_ptr *t,two_three_ptr p,two_three_ptr s)
{
	s->data_l=p->data_l;
	p->data_l=p->middle_child->data_l;
	p->middle_child->data_l=p->middle_child->data_r;
	p->middle_child->data_r=INT_MAX;

	s->middle_child=p->middle_child->left_child;
	p->middle_child->left_child=p->middle_child->middle_child;
	p->middle_child->middle_child=p->middle_child->right_child;
	p->middle_child->right_child=NULL;
}
void b_rotate(two_three_ptr *t,two_three_ptr p,two_three_ptr s)
{
	s->data_l=p->data_l;
	p->data_l=p->left_child->data_r;
	p->left_child->data_r=INT_MAX;

	s->middle_child=s->left_child;
	s->left_child=p->left_child->right_child;
	p->left_child->right_child=NULL;
}
void c_rotate(two_three_ptr *t,two_three_ptr p,two_three_ptr s)
{
	s->data_l=p->data_r;
	p->data_r=p->middle_child->data_r;
	p->middle_child->data_r=INT_MAX;
}
void a_merge(two_three_ptr *t,two_three_ptr p,two_three_ptr s)
{
	s->data_l=p->data_l;
	s->data_r=p->middle_child->data_l;
	p->data_l=INT_MAX;

	s->middle_child=p->middle_child->left_child;
	s->right_child=p->middle_child->middle_child;
	free(p->middle_child);
	p->middle_child=NULL;

}
void b_merge(two_three_ptr *t,two_three_ptr p,two_three_ptr s)
{
	s->data_l=p->data_l;
	s->data_r=p->middle_child->data_l;
	p->data_l=p->data_r;
	p->data_r=INT_MAX;

	s->middle_child=p->middle_child->left_child;
	s->right_child=p->middle_child->middle_child;
	free(p->middle_child);
	p->middle_child=p->right_child;
	p->right_child=NULL;
}
void c_merge(two_three_ptr *t,two_three_ptr p,two_three_ptr s)
{
	p->left_child->data_r=p->data_l;
	p->data_l=INT_MAX;

	p->left_child->right_child=s->left_child;
	free(s);
	p->middle_child=NULL;
}
void d_merge(two_three_ptr *t,two_three_ptr p,two_three_ptr s)
{
	p->left_child->data_r=p->data_l;
	p->data_l=p->data_r;
	p->data_r=INT_MAX;

	p->left_child->right_child=s->left_child;
	p->middle_child=p->right_child;
	free(s);
	p->right_child=NULL;
}
void e_merge(two_three_ptr *t,two_three_ptr p,two_three_ptr s)
{
	p->middle_child->data_r=p->data_r;
	p->data_r=INT_MAX;

	p->middle_child->right_child=s->left_child;
	free(s);
	p->right_child=NULL;
}

two_three_ptr change(two_three_ptr d,element y)//交换节点
{
	two_three_ptr temp;
	int i=0;
	element te;
   if (d->data_l==y)//左值
   		temp=d->left_child;
   else//右值
   {
   		temp=d->middle_child;
   		i=1;
   }
	pushnode(temp,nodedel,&nodedeltop);

   	while(temp)
   	{

   		if (temp->data_r != INT_MAX && temp->right_child==NULL) //(a,INT_MAX)[x,0,0,]
   		{
   			te=temp->data_r;
   			temp->data_r=y;
   			break;
   		}
   		else if (temp->data_r != INT_MAX && temp->right_child !=NULL)
   		{
   			temp=temp->right_child;
   			pushnode(temp,nodedel,&nodedeltop);
   			continue;
   		}
   		else if (temp->data_r == INT_MAX && temp->middle_child ==NULL)
   		{
   			te=temp->data_l;
   			temp->data_l=y;
   			break;
   		}
   		else if (temp->data_r == INT_MAX && temp->middle_child !=NULL)
   		{
   			temp=temp->middle_child;
   			pushnode(temp,nodedel,&nodedeltop);
   			continue;
   		}
   	}

   	if (i==0)
	   d->data_l=te;
	else
	   d->data_r=te;
	popnode(nodedel,&nodedeltop);//pop掉这个temp
   	return temp;
}

int main(int argc, char const *argv[])
{
	two_three_ptr t=NULL;
	insert23(&t,10);
	insert23(&t,40);
	insert23(&t,80);
	insert23(&t,20);
	insert23(&t,70);
	insert23(&t,30);

	printf("%d  %d\n", search23(t,70),search23(t,80));

	insert23(&t,60);
	insert23(&t,15);

	printf("%d  %d\n", search23(t,10),search23(t,15));

	insert23(&t,35);
	printf("%d  %d\n", search23(t,35),search23(t,30));

	two_three_ptr e=search23(t,40);
	two_three_ptr f=search23(t,70);
	printf("%d  %d\n", e,f);
/*
---------------  40, MAX
               /    /
-----------20,MAX     70, MAX
          /  /       /    /
---10,MAX  30,MAX  60,MAX 80,MAX
*/

///-----------------------------

	printf("\n");
	delete23(&t,15);
	delete23(&t,30);
	insert23(&t,9);//(10,15)-->(9,10)
	insert23(&t,36);//(30,35)-->(35,36)
	printf("%d  %d\n", search23(t,9),search23(t,10));
	printf("%d  %d\n", search23(t,35),search23(t,36));

//arotate
	delete23(&t,9);
	delete23(&t,10);
	insert23(&t,21);
	printf("%d  %d\n", search23(t,20),search23(t,21));

//brotate
	delete23(&t,36);
	insert23(&t,22);
	printf("%d  %d\n", search23(t,22),search23(t,35));

//crotate
	insert23(&t,30);
	insert23(&t,25);
	delete23(&t,35);
	printf("%d  %d\n", search23(t,21),search23(t,25));

//amerge
printf("amerge\n");
two_three_ptr t1=NULL;
	insert23(&t1,10);
	insert23(&t1,20);
	insert23(&t1,40);
	delete23(&t1,10);
	printf("%d  %d\n", search23(t1,20),search23(t1,40));

//bmerge
printf("bmerge\n");
	delete23(&t,20);
	printf("%d  %d\n", search23(t,21),search23(t,22));

//cmerge
printf("cmerge\n");
two_three_ptr t2=NULL;
	insert23(&t2,10);
	insert23(&t2,20);
	insert23(&t2,40);
	delete23(&t2,40);
	printf("%d  %d\n", search23(t2,10),search23(t2,20));

//dmerge
	insert23(&t,26);
	insert23(&t,27);
	delete23(&t,22);
	delete23(&t,26);
	printf("%d  %d\n", search23(t,21),search23(t,25));
//cmerge和dmerge是可以合并的,c按照d的方法来即可

//emerge
	insert23(&t,28);
	insert23(&t,29);
	delete23(&t,30);
	printf("%d  %d\n", search23(t,28),search23(t,29));	

	return 0;

}
时间: 2024-08-29 03:14:02

2-3树的相关文章

HDU 6203 ping ping ping [LCA,贪心,DFS序,BIT(树状数组)]

题目链接:[http://acm.hdu.edu.cn/showproblem.php?pid=6203] 题意 :给出一棵树,如果(a,b)路径上有坏点,那么(a,b)之间不联通,给出一些不联通的点对,然后判断最少有多少个坏点. 题解 :求每个点对的LCA,然后根据LCA的深度排序.从LCA最深的点对开始,如果a或者b点已经有点被标记了,那么continue,否者标记(a,b)LCA的子树每个顶点加1. #include<Bits/stdc++.h> using namespace std;

HDU 5542 The Battle of Chibi dp+树状数组

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5542 题意:给你n个数,求其中上升子序列长度为m的个数 可以考虑用dp[i][j]表示以a[i]结尾的长度为j的上升子序列有多少 裸的dp是o(n2m) 所以需要优化 我们可以发现dp的第3维是找比它小的数,那么就可以用树状数组来找 这样就可以降低复杂度 #include<iostream> #include<cstdio> #include<cstring> #include

【树4】二叉树的遍历

简介 遍历二叉树就是按照某种顺序,将树中的结点都枚举一遍,且每个结点仅仅访问一次.因为树不是线性的结构,遍历不像线性表那样简单,因此他的遍历需要特点的算法来完成. 从某种角度讲,对二叉树的遍历就是将树形结构转换为线性结构的操作. 二叉树的遍历方法主要有如下几种: 先序遍历:先访问root结点,再先序遍历左子树,再先序遍历右子树. 中序遍历:先中序遍历左子树,再访问root结点,再中序遍历右子树. 后序遍历:先后序遍历左子树,再后序遍历右子树,再访问root结点. 层遍历:从上到下,从左到右,一层

关于左偏树的一些东东

大概所有的预备知识这里都有https://baike.baidu.com/item/%E5%B7%A6%E5%81%8F%E6%A0%91/2181887?fr=aladdin 例题1:洛谷 P3377 [模板]左偏树(可并堆) 383通过 1.2K提交 题目提供者HansBug 站长团 标签 难度提高+/省选- 时空限制1s / 128MB 提交 讨论 题解 最新讨论更多讨论 加了路径压缩就WA,路过dal… 左偏树用指针写会MLE吗..… m,n写反了也可以过,数据有… 哪位大神有pbds库

ZJOI 2008 树的统计

ZJOI2008 树的统计 题目描述 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w. 我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身 输入输出格式 输入格式: 输入文件的第一行为一个整数n,表示节点的个数. 接下来n – 1行,每行2个整数

luoguP2590 [ZJOI2008]树的统计 [树链剖分] [TLE的LCT]

题目描述 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w. 我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身 输入输出格式 输入格式: 输入文件的第一行为一个整数n,表示节点的个数. 接下来n – 1行,每行2个整数a和b,表示节点a和节点b之

(POJ 3067) Japan (慢慢熟悉的树状数组)

Japan Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 29295   Accepted: 7902 Description Japan plans to welcome the ACM ICPC World Finals and a lot of roads must be built for the venue. Japan is tall island with N cities on the East coas

[poj2104]可持久化线段树入门题(主席树)

解题关键:离线求区间第k小,主席树的经典裸题: 对主席树的理解:主席树维护的是一段序列中某个数字出现的次数,所以需要预先离散化,最好使用vector的erase和unique函数,很方便:如果求整段序列的第k小,我们会想到离散化二分和线段树的做法, 而主席树只是保存了序列的前缀和,排序之后,对序列的前缀分别做线段树,具有差分的性质,因此可以求任意区间的第k小,如果主席树维护索引,只需要求出某个数字在主席树中的位置,即为sort之后v中的索引:若要求第k大,建树时反向排序即可 1 #include

【BZOJ 3551】[ONTAK2010] Peaks加强版 Kruskal重构树+树上倍增+主席树

这题真刺激...... I.关于Kruskal重构树,我只能开门了,不过补充一下那玩意还是一棵满二叉树.(看一下内容之前请先进门坐一坐) II.原来只是用树上倍增求Lca,但其实树上倍增是一种方法,Lca只是他的一种应用,他可以搞各种树上问题,树上倍增一般都会用到f数组. |||.我们跑出来dfs序就能在他的上面进行主席树了. IV.别忘了离散. V.他可能不连通,我一开始想到了,但是我觉得出题人可能会是好(S)人(B),但是...... #include <cstdio> #include

【BZOJ4942】[Noi2017]整数 线段树+DFS(卡过)

[BZOJ4942][Noi2017]整数 题目描述去uoj 题解:如果只有加法,那么直接暴力即可...(因为1的数量最多nlogn个) 先考虑加法,比较显然的做法就是将A二进制分解成log位,然后依次更新这log位,如果最高位依然有进位,那么找到最高位后面的第一个0,将中间的所有1变成0,那个0变成1.这个显然要用到线段树,但是复杂度是nlog2n的,肯定过不去. 于是我在考场上yy了一下,这log位是连续的,我们每次都要花费log的时间去修改一个岂不是很浪费?我们可以先在线段树上找到这段区间