2-3树的基本操作实现

本文介绍了2-3树的概念,这是一种插入和删除操作时间复杂性为O(logn)的数据结构。2-3树的内部节点度数为2或3,分为2结点和3结点。文章重点讨论了2-3树的插入和删除操作,包括结点拆分、数据转移和结点合并等,并提供了相关操作的代码实现。

            通过引入结点度大于2的查找树,可以得到一种插入算法和删除算法都比AVL树简单的树结构,且这些算法的时间复杂性是O(logn)。这种树结构称为2-3树。2-3树的名字反映了2-3树具有如下性质:一棵2-3树中每个内部结点的度或者是2,或者是3。其中度为2的结点称为2结点,度为3的结点称为3结点。

定义:一棵2-3树(2-3 Tree)是一棵查找树,该查找树或者为空,或者满足如下性质:

1,每个内部结点或者是一个2结点,或者是一个3结点。一个2结点存放一个元素,而一个3结点存放两个元素。

2,令lchild和mchild表示2结点的两个儿子,datal表示该节点存放的元素,且datal.key是该元素的关键字。以lchild为根的子树中所有结点的关键字都小于datal.key,而以mchild为根的子树中所有结点的关键字都大于datal.key。

3,零lchild,mchild和rchild表示3结点的三个儿子,datal和datar表示该节点存放的左右两个元素,且datal.key < datar.key。以lchild为根的子树的所有结点的关键字都小于datal.key,以mchild为根的子树的所有结点的关键子都大于datal.key而小于datar.key,而以rchild为根的子树中所有结点的关键字都大于datar.key。

4,所有外部结点位于同一层。

        2-3树的查询操作不用细说,实现比较容易,重点在于2-3树的插入和删除操作,2-3树的插入操作涉及结点拆分,删除操作涉及数据的转移(或者称为旋转吧)以及结点合并(三种情况的旋转以及三种情况的合并,详细见REF[1]的2-3树章节)等等操作。


具体的插入和删除的原理可以可以参考文章《2-3树删除和插入操作的小结》,后面的代码主要是对REF[1]中的算法的实现:

代码:

#include <iostream>
#include <stack>

using namespace std;

typedef struct Tree23Node * Tree23;

typedef struct Tree23Node {
	int datal;
	int datar;
	Tree23 lchild,mchild,rchild;
} Tree23Node;

#define  INT_MAX 0x3f3f3f3f

stack<Tree23> s;

int compare(int x, Tree23 t)
{
	if (x < t->datal)
		return 1;
	else if (x > t->datar)
		return 3;
	else if ( x < t->datar && x > t->datal)
		return 2;
	else 
		return 4; 
}

Tree23 createNode(int key)
{
	Tree23 t = new Tree23Node;
	t->datal = key;
	t->datar = INT_MAX;
	t->lchild = t->mchild = t->rchild = NULL;
	return t;
} 
void newRoot(Tree23 *root,int key,Tree23 midSub)
{
	Tree23 t = createNode(key);
	t->lchild = *root;
	t->mchild = midSub;
	*root = t;		
}

bool isleaf(Tree23 root)
{
	if (root && root->datal < INT_MAX && root->lchild == NULL && 
		root->mchild == NULL && root->rchild == NULL)
		return true;
	return false;
}

Tree23 findNode(Tree23 root, int key)
{
	Tree23 t = NULL;
	while (root){
		if (!isleaf(root))
			s.push(root);
		if (isleaf(root))
			t = root;
		switch (compare(key,root)) {
			case 1:	root = root->lchild;
					break;
			case 2:	root = root->mchild;
					break;
			case 3: root = root->rchild;
					break;
			case 4: return NULL;
		}
	}
	return t;
}

void put(Tree23 *root, int key,Tree23 q)
{
	if (key < (*root)->datal){
		(*root)->datar = (*root)->datal;
		(*root)->datal = key;
		(*root)->rchild = (*root)->mchild;
		(*root)->mchild = q;
	}
	else {
		(*root)->datar = key;
		(*root)->rchild = q;
	}
} 

void split(Tree23 p,int *key,Tree23 *q)
{
	Tree23 t = createNode(INT_MAX);
	 
	if (*key < p->datal) {
		t->datal = p->datar;
		/*swap *key and p->datal */
		p->datar = *key;
		*key = p->datal;
		p->datal = p->datar;
		/* set p->datar to non sense */
		p->datar = INT_MAX; 
	}
	else if (*key > p->datar) {
		t->datal = *key;
		*key = p->datar;
		p->datar = INT_MAX;
	}
	else {
		t->datal = p->datar;
		p->datar = INT_MAX;
	}
	t->lchild = p->rchild;
	p->rchild = NULL;
	t->mchild = *q;
	*q = t;
}

Tree23 del()
{
	if (!s.empty()){
		Tree23 t = s.top();
		s.pop();
		return t;
	}
	return NULL;
}

void insert23(Tree23 *root,int key)
{
	Tree23 p,q,temp;
	
	if (*root == NULL) {
		/* tree is empty */
		newRoot(root,key,NULL);
	}
	else {
		/* insert into an empty tree */
		p = findNode(*root,key);
		if (p == NULL) {
			cout<<"The key is currently in the tree."<<endl;
			return;
		}
		q = NULL;
		for(;;) {
			if (p->datar == INT_MAX) {
				/* two sub node */
				put(&p,key,q);
				break;
			} 
			else {
				/* three sub node */
				split(p,&key,&q);
				if ( p == *root) {
					/* split the root */
					newRoot(root,key,q);
					break;
				}
				else 
					/* remove a node from stack */
					p = del();
			}
		}
	}
}

void visit(Tree23 T)
{
	if (T->datar < INT_MAX) {
		cout<<"("<<T->datal<<","<<T->datar<<") ";
	} 
	else if (T->datal < INT_MAX) {
		cout<<"("<<T->datal<<",) "; 
	}
	else cout<<"(,) "; 
} 
void inOrder(Tree23 T)
{
	if(T)
	{ 
		visit(T);
		//cout<<endl;
		if (T->lchild == NULL)
			return;
		cout<<"(";
		inOrder(T->lchild);
		cout<<",";
		inOrder(T->mchild);
		cout<<",";
		inOrder(T->rchild); 
		cout<<")";
	} 

}

Tree23 search23(Tree23 root,int key)
{
	while (root) {
		s.push(root);
		switch (compare(key,root)) {
			case 1:	root = root->lchild;
					break;
			case 2: root = root->mchild;
					break;
			case 3: root = root->rchild;
					break;
			case 4: return root;
		}
	} 
	return NULL;
}
Tree23 min23(Tree23 root)
{
	while(root->lchild){
		s.push(root);
		root = root->lchild;
	}
	s.push(root);
	return root;
}

void deletex(Tree23 t,int key)
{
	/* delete key from node t */
	if(key == t->datal){
		/* delete first key */
		if(t->datar < INT_MAX){
			/* three sub node*/
			t->datal = t->datar;
			t->datar = INT_MAX;
		}
		else
			/* two sub node */
			t->datal = INT_MAX;
	}
	else
		/* delete second key */
		t->datar = INT_MAX;
}

void leftRotate(Tree23 &p,Tree23 &q,Tree23 &r)
{
	p->datal = r->datal;
	r->datal = q->datal;
	q->datal = q->datar;
	q->datar = INT_MAX;
	
	p->mchild = q->lchild;
	q->lchild = q->mchild;
	q->mchild = q->rchild;
	q->rchild = NULL;
}

void leftCombine(Tree23 &p,Tree23 &q,Tree23 &r) 
{
	p->datal = r->datal;
	p->datar = q->datal;
	p->mchild = q->lchild;
	p->rchild = q->mchild;
	delete q;
	if (r->datar == INT_MAX){
		/* r is two sub node*/
		r->datal = INT_MAX;
		r->mchild = NULL;
	}
	else{
		r->datal = r->datar;
		r->datar = INT_MAX;
		r->mchild = r->rchild;
		r->rchild = NULL; 
	}
} 


void middleRotate(Tree23 &p,Tree23 &q,Tree23 &r)
{
	p->datal = r->datal;
	r->datal = q->datar;
	q->datar = INT_MAX;
	p->mchild = q->rchild;
	q->rchild = NULL;
}

void middleCombine(Tree23 &p, Tree23 &q, Tree23 &r)
{
	q->datar = r->datal;
	q->rchild = p->lchild;
	delete p;
	if(r->datar < INT_MAX) {
		r->datal = r->datar;
		r->datar = INT_MAX;
		r->mchild = r->rchild;
		r->rchild = NULL;
	}
	else {
		r->datal = INT_MAX;
		r->mchild = NULL;
	}
	
}

void rightRotate(Tree23 &p,Tree23 &q,Tree23 &r)
{
	p->datal = r->datar;
	r->datar = q->datar;
	q->datar = INT_MAX;
	p->mchild = q->rchild;
	q->rchild = NULL;
}

void rightCombine(Tree23 &p,Tree23 &q,Tree23 &r)
{
	q->datar = r->datar;
	r->datar = INT_MAX;
	q->rchild = p->lchild;
	delete p;
	r->rchild = NULL;
}
bool delete23(Tree23 *root, int key)
{
	Tree23 t = search23(*root,key);
	Tree23 p;
	Tree23 r ;
	Tree23 q = NULL;
	if (t == NULL)
		return false;
	else{
		if (!isleaf(t)){
			if (t->datal == key){
				p = min23(t->mchild);
				t->datal = p->datal;
				key = p->datal;
			}
			else{
				p = min23(t->rchild);
				t->datar = p->datal;
				key = p->datal;
			}
			
		}
		else
			p = t;
		
		deletex(p,key);
		del();
		for(;;){
			if (p->datal == INT_MAX && p->datar == INT_MAX){
				r = del();
				if (r == NULL)
					break;
				if (r->lchild == p){
					/* */
					q = r->mchild;
					if (q->datar < INT_MAX){
						/* rotate when p is the left child of r */
						leftRotate(p,q,r);
					}
					else{
						/* combine when p is the left child of r*/
						leftCombine(p,q,r);
					}
				}
				else if (r->mchild == p) {
					q = r->lchild;
					if (q->datar < INT_MAX){
						middleRotate(p,q,r);
					}
					else{
						middleCombine(p,q,r);
					}
					
				}
				else {
					q = r->mchild;
					if (q->datar < INT_MAX){
						rightRotate(p,q,r);
					}
					else{
						rightCombine(p,q,r);
					}
				}
				p = r;
			}
			else 
				break;
			
		}
		if (p->datal == INT_MAX){
			*root = p->lchild;
			delete p;
		}	
		
	}
	
}
int main()
{
	Tree23 tree = NULL;
	for(int i = 0; i < 11; i++){
		insert23(&tree,i);
		inOrder(tree);
		cout<<endl;
		cout<<"-----------------------------------------"<<endl;
	}
	insert23(&tree,8);
	inOrder(tree);
	cout<<endl; 
	cout<<"--------------------------------------------"<<endl;
	
	while(!s.empty())
		s.pop();
	delete23(&tree,10);
	inOrder(tree);
	cout<<endl;
	
	cout<<"--------------------------------------------"<<endl;
	
	while(!s.empty())
		s.pop();
	delete23(&tree,9);
	inOrder(tree);
	cout<<endl;
	
	cout<<"--------------------------------------------"<<endl;
	
	while(!s.empty())
		s.pop();
	delete23(&tree,8);
	inOrder(tree);
	cout<<endl;
	
	cout<<"--------------------------------------------"<<endl;
	
	while(!s.empty())
		s.pop();
	delete23(&tree,7);
	inOrder(tree);
	cout<<endl;
	
	cout<<"--------------------------------------------"<<endl;
	
	while(!s.empty())
		s.pop();
	delete23(&tree,6);
	inOrder(tree);
	cout<<endl;
	
	cout<<"--------------------------------------------"<<endl;
	
	for(int i = 5;i >= 0; i--){
		while(!s.empty())
		s.pop();
		delete23(&tree,i);
		inOrder(tree);
		cout<<endl;
	
		cout<<"--------------------------------------------"<<endl;
		
	}
} 

测试结果:

Key  =   0  inserted:
(0,) 
---------------------------------------------------------------------
Key  =   1  inserted:
(0,1) 
---------------------------------------------------------------------
Key  =   2  inserted:
(1,) ((0,) ,(2,) ,)
---------------------------------------------------------------------
Key  =   3  inserted:
(1,) ((0,) ,(2,3) ,)
---------------------------------------------------------------------
Key  =   4  inserted:
(1,3) ((0,) ,(2,) ,(4,) )
---------------------------------------------------------------------
Key  =   5  inserted:
(1,3) ((0,) ,(2,) ,(4,5) )
---------------------------------------------------------------------
Key  =   6  inserted:
(3,) ((1,) ((0,) ,(2,) ,),(5,) ((4,) ,(6,) ,),)
---------------------------------------------------------------------
Key  =   7  inserted:
(3,) ((1,) ((0,) ,(2,) ,),(5,) ((4,) ,(6,7) ,),)
---------------------------------------------------------------------
Key  =   8  inserted:
(3,) ((1,) ((0,) ,(2,) ,),(5,7) ((4,) ,(6,) ,(8,) ),)
---------------------------------------------------------------------
Key  =   9  inserted:
(3,) ((1,) ((0,) ,(2,) ,),(5,7) ((4,) ,(6,) ,(8,9) ),)
---------------------------------------------------------------------
Key  =   10  inserted:
(3,7) ((1,) ((0,) ,(2,) ,),(5,) ((4,) ,(6,) ,),(9,) ((8,) ,(10,) ,))
---------------------------------------------------------------------
The key is currently in the tree.
Key  =   8  inserted:
(3,7) ((1,) ((0,) ,(2,) ,),(5,) ((4,) ,(6,) ,),(9,) ((8,) ,(10,) ,))
--------------------------------------------------------------------------
Key  =   10  deleted:
(3,) ((1,) ((0,) ,(2,) ,),(5,7) ((4,) ,(6,) ,(8,9) ),)
--------------------------------------------------------------------------
Key  =   9  deleted:
(3,) ((1,) ((0,) ,(2,) ,),(5,7) ((4,) ,(6,) ,(8,) ),)
--------------------------------------------------------------------------
Key  =   8  deleted:
(3,) ((1,) ((0,) ,(2,) ,),(5,) ((4,) ,(6,7) ,),)
--------------------------------------------------------------------------
Key  =   7  deleted:
(3,) ((1,) ((0,) ,(2,) ,),(5,) ((4,) ,(6,) ,),)
----------------------------------------------------------------------------
Key  =   6  deleted:
(1,3) ((0,) ,(2,) ,(4,5) )
---------------------------------------------------------------------------
Key  =   5  deleted:
(1,3) ((0,) ,(2,) ,(4,) )
---------------------------------------------------------------------------
Key  =   4  deleted:
(1,) ((0,) ,(2,3) ,)
---------------------------------------------------------------------------
Key  =   3  deleted:
(1,) ((0,) ,(2,) ,)
---------------------------------------------------------------------------
Key  =   2  deleted:
(0,1) 
---------------------------------------------------------------------------
Key  =   1  deleted:
(0,) 
---------------------------------------------------------------------------
Key  =   0  deleted:

---------------------------------------------------------------------------


REF:

1,数据结构(C语言版) Ellis Horowitz等

2,http://blog.youkuaiyun.com/sumoyu/article/category/1054287

3,http://www.bkjia.com/Pythonjc/815204.html

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值