前有2-3树,2-3-4树的概念不用多讲,相比2-3树,2-3-4树只需从根结点到叶结点进行一趟扫描,就能完成树的插入操作和删除操作。对2-3树而言,完成这样的操作需要从根结点向下进行一趟扫描,然后再从叶子结点到根结点进行一趟扫描。2-3-4树在插入操作的自顶向下的单趟扫描中,不断对4结点进行拆分,这样确保要插入的叶结点是一个2结点或者3结点。在删除操作的自顶下乡扫描中,可以看成是插入时的逆过程,在定位最终可以替换删除的叶结点的扫描过程中,不断对树进行重建。定义参照文章《2-3树的基本操作实现》中2-3树的定义,性质同2-3树。详见REF[1]的相关内容。
2-3-4 树是红黑树的一种等同,这意味着它们是等价的数据结构。换句话说,对于每个 2-3-4 树,都存在着至少一个数据元素是相同次序的红黑树。在 2-3-4 树上的插入和删除操作也等价于在红黑树中的颜色翻转和旋转。这使得它成为理解红黑树背后的逻辑的重要工具。
代码:
#include <iostream>
#include <iomanip>
#include <assert.h>
using namespace std;
#define INT_MAX 0x3fffffff
typedef struct Tree234Node * Tree234;
typedef struct Tree234Node
{
int datal;
int datam;
int datar;
Tree234 lchild,mlchild,mrchild,rchild;
} Tree234Node;
typedef enum { two_node,three_node
} node_typde;
typedef enum {EQ,leaf,goleft,mleft,mright,goright
} compare_type;
void newroot(Tree234 *t,int key)
{
/* create a new 2-3-4 tree ,only one data contained */
*t = new Tree234Node;
(*t)->datal = key;
(*t)->datam = (*t)->datar = INT_MAX;
(*t)->lchild = (*t)->rchild = (*t)->mlchild = (*t)->mrchild = NULL;
}
bool isfournode(Tree234 t)
{
/* true returned if node t is four node otherwise false */
assert(t != NULL);
if (t->datar != INT_MAX)
return true;
return false;
}
void splitRoot(Tree234 *t)
{
/* create two new node p and q as lchild and mlchild of *t */
Tree234 p,q;
newroot(&p,(*t)->datal);
newroot(&q,(*t)->datar);
p->lchild = (*t)->lchild;
p->mlchild = (*t)->mlchild;
q->lchild = (*t)->mrchild;
q->mlchild = (*t)->rchild;
/* do some clear job for *t */
(*t)->datal = (*t)->datam;
(*t)->datam = (*t)->datar = INT_MAX;
(*t)->lchild = p;
(*t)->mlchild = q;
(*t)->mrchild = (*t)->rchild = NULL;
}
node_typde typeOfNode(Tree234 t)
{
if (t->datar == INT_MAX) {
if (t->datam != INT_MAX) {
return three_node;
}
else if (t->datal != INT_MAX) {
return two_node;
}
else
;
}
}
void splitChildOf2(Tree234 *p,Tree234 *r)
{
Tree234 q;
newroot(&q,(*p)->datar);
q->lchild = (*p)->mrchild;
q->mlchild = (*p)->rchild;
(*p)->mrchild = (*p)->rchild = NULL;
if (*p == (*r)->lchild) {
/* *p is the goleft child of *r */
(*r)->datam = (*r)->datal;
(*r)->datal = (*p)->datam;
(*r)->mrchild = (*r)->mlchild;
(*r)->mlchild = q;
}
else {
/* *p is the mlchild of *r */
(*r)->datam = (*p)->datam;
(*r)->mrchild = q;
}
(*p)->datam = (*p)->datar = INT_MAX;
}
void splitChildOf3(Tree234 *p,Tree234 *r)
{
Tree234 q;
newroot(&q,(*p)->datar);
q->lchild = (*p)->mrchild;
q->mlchild = (*p)->rchild;
(*p)->mrchild = (*p)->rchild = NULL;
(*p)->datar = INT_MAX;
if(*p == (*r)->lchild) {
/* *p is the lchild of *r */
(*r)->datar = (*r)->datam;
(*r)->datam = (*r)->datal;
(*r)->datal = (*p)->datam;
(*r)->rchild = (*r)->mrchild;
(*r)->mrchild = (*r)->mlchild;
(*r)->mlchild = q;
}
else if (*p == (*r)->mlchild) {
/* *p is mlchild of *r */
(*r)->datar = (*r)->datam;
(*r)->datam = (*p)->datam;
(*r)->rchild = (*r)->mrchild;
(*r)->mrchild = q;
}
else {
/* *p is the mrchild of *r */
(*r)->datar = (*p)->datam;
(*r)->rchild = q;
}
(*p)->datam = INT_MAX;
}
bool isleaf(Tree234 t)
{
if (t && t->lchild == NULL && t->mlchild == NULL && t->mrchild == NULL &&
t->rchild == NULL)
return true;
else
return false;
}
compare_type compare(int key, Tree234 t)
{
if (isleaf(t))
return leaf;
if (key < t->datal)
return goleft;
else if (key > t->datar)
return goright;
else if (key < t->datar && key > t->datam)
return mright;
else if(key < t->datam && key > t->datal)
return mleft;
else
return EQ;
}
void putin(Tree234 *t,int key)
{
/* insert key into a leaf node the leaf node is 2 node or 3 node */
assert(*t != NULL);
if (key < (*t)->datal) {
(*t)->datar = (*t)->datam;
(*t)->datam = (*t)->datal;
(*t)->datal = key;
}
else if (key < (*t)->datam) {
(*t)->datar = (*t)->datam;
(*t)->datam = key;
}
else {
(*t)->datar = key;
}
}
void insert234(Tree234 *root, int key)
{
/* insert key into a 2-3-4 tree root */
Tree234 p,r;
if (*root == NULL) {
newroot(root,key);
}
else {
if (isfournode(*root))
splitRoot(root);
p = *root;
r = NULL;
for (;;) {
if (isfournode(p)) {
if (typeOfNode(r) == two_node)
splitChildOf2(&p,&r);
else
splitChildOf3(&p,&r);
p = r;
}
r = p;
switch (compare(key,p)) {
case EQ: cout<<"Key = "<<key<<\
" is already in the 2-3-4 tree"<<endl;
return;
case leaf : putin(&p,key);
return;
case goleft: p = p->lchild;
break;
case mleft: p = p->mlchild;
break;
case mright: p = p->mrchild;
break;
case goright: p = p->rchild;
}
}
}
}
int childPos(Tree234 p,Tree234 q)
{
/* p is parent of q */
if (p->lchild == q)
return 1;
if (p->mlchild == q)
return 2;
if (p->mrchild == q)
return 3;
if (p->rchild == q)
return 4;
}
void combineRoot(Tree234 *p,Tree234 *q)
{
/* q is 2-node and p is 2-node
and the nearest sibling r is 2-node
p is parent of q */
Tree234 t =NULL;
if (*q == (*p)->lchild){
/* q is the lchild of p*/
t = (*p)->mlchild;
/* set data member */
(*p)->datam = (*p)->datal;
(*p)->datal = (*q)->datal;
(*p)->datar = t->datal;
/* set the sub tree link */
(*p)->lchild = (*q)->lchild;
(*p)->mlchild = (*q)->mlchild;
(*p)->mrchild = t->lchild;
(*p)->rchild = t->mlchild;
}
else{
t = (*p)->lchild;
/*set data member*/
(*p)->datam = (*p)->datal;
(*p)->datal = t->datal;
(*p)->datar = (*q)->datal;
/* set sub tree link*/
(*p)->lchild = t->lchild;
(*p)->rchild = t->mlchild;
(*p)->mrchild = (*q)->lchild;
(*p)->rchild = (*q)->mlchild;
}
delete (*q);
delete t;
*q = NULL;
}
void combineX22(Tree234 *p,Tree234 *q, Tree234 *t,int pos)
{
/* p is parent of q and t and t is by the right
side of q, p is 4-node */
if (pos == 1) {
/* q and t are at the left side */
(*q)->datam = (*p)->datal;
(*q)->datar = (*t)->datal;
(*p)->datal = (*p)->datam;
(*p)->datam = (*p)->datar;
(*p)->datar = INT_MAX;
/* sub tree link*/
(*q)->mrchild = (*t)->lchild;
(*q)->rchild = (*t)->mlchild;
delete (*t);
(*p)->mlchild = (*p)->mrchild;
(*p)->mrchild = (*p)->rchild;
(*p)->rchild = NULL;
}
else if (pos == 2) {
/* q and t in the midddle */
/*data member*/
(*q)->datam = (*p)->datam;
(*q)->datar = (*t)->datal;
(*p)->datam = (*p)->datar;
(*p)->datar = INT_MAX;
/*sub tree link*/
(*q)->mrchild = (*t)->lchild;
(*q)->rchild = (*t)->mlchild;
(*p)->mrchild = (*p)->rchild;
(*p)->rchild = NULL;
delete (*t);
}
else {
/* q and t are on the right side*/
/*data member*/
(*q)->datam = (*p)->datar;
(*q)->datar = (*t)->datal;
(*p)->datar = INT_MAX;
/*sub tree link*/
(*q)->mrchild = (*t)->lchild;
(*q)->rchild = (*t)->mlchild;
(*p)->rchild = NULL;
delete (*t);
}
}
void combineX234(Tree234 *p, Tree234 *q,Tree234 *t,int pos)
{
switch (pos) {
case 1: /*q and t on the left side*/
/*data move*/
(*q)->datam = (*p)->datal;
(*p)->datal = (*t)->datal;
break;
case 2: /* q and t are in the middle */
/*data move*/
(*q)->datam = (*p)->datam;
(*p)->datam = (*t)->datal;
break;
case 3: /* q and t are on the right side*/
/*data move*/
(*q)->datam = (*p)->datar;
(*p)->datar = (*t)->datal;
break;
}
/*data move*/
(*t)->datal = (*t)->datam;
(*t)->datam = (*t)->datar;
(*t)->datar = INT_MAX;
/*sub tree link redirection*/
(*q)->mrchild = (*t)->lchild;
(*t)->lchild = (*t)->mlchild;
(*t)->mlchild = (*t)->mrchild;
(*t)->mrchild = (*t)->rchild;
(*t)->rchild = NULL;
}
Tree234 goDown(Tree234 p,int key)
{
/* child link according key */
if (key > p->datar)
return p->rchild;
if (key < p->datal)
return p->lchild;
if (key > p->datal && key < p->datam)
return p->mlchild;
if (key > p->datam && key < p->datar)
return p->mrchild;
return p;
}
Tree234 goLeftmost(Tree234 p)
{
assert(p != NULL);
if (p->lchild)
return p->lchild;
}
bool keyIn(Tree234 t,int key)
{
assert(t != NULL);
if (key == t->datal || key == t->datam || key == t->datar)
return true;
return false;
}
bool deletex(Tree234 t,int key)
{
/*delete key in leaf node t*/
if (key == t->datar){
t->datar = INT_MAX;
return true;
}
else if (key == t->datam) {
t->datam = t->datar;
t->datar = INT_MAX;
return true;
}
else if (key == t->datal) {
t->datal = t->datam;
t->datam = t->datar;
t->datar = INT_MAX;
return true;
}
else {
cout<<"Key = "<<key<<" is not in 2-3-4 tree."<<endl;
return false;
}
}
bool delete234(Tree234 *root, int key)
{
/*delete a key from the 2-3-4 tree root*/
Tree234 p,q,t,r;
Tree234 target;
bool isRoot = false;
bool flag = false;
int pos;
if (isleaf(*root)){
if (deletex(*root,key)){
if ((*root)->datal == INT_MAX){
delete *root;
*root = NULL;
}
return true;
}
}
else{
p = *root;
for (;;) {
if (isleaf(p))
break;
if (keyIn(p,key)){
target = p;
flag = true;
if (key == p->datal ){
pos = 1;
q = p->mlchild;
}
else if (key == p->datam){
pos = 2;
q = p->mrchild;
}
else if (key == p->datar){
pos = 3;
q = p->rchild;
}
}
else if (!flag) {
q = goDown(p,key);
}
else{
q = p->lchild;
}
if (typeOfNode(q) != two_node){
p = q;
continue;
}
else {
isRoot = false;
switch (childPos(p,q)) {
case 1: t = p->mlchild;
if (typeOfNode(t) == two_node){
if (typeOfNode(p) == two_node){
isRoot = true;
combineRoot(&p,&q);
}
else
combineX22(&p,&q,&t,1);
}
else
combineX234(&p,&q,&t,1);
if (isRoot)
q = p;
break;
case 2: t = p->lchild;
r = t;
t = q;
q = r;
if (typeOfNode(q) == two_node) {
if (typeOfNode(p) == two_node){
isRoot = true;
combineRoot(&p,&q);
}
else
combineX22(&p,&q,&t,1);
}
else
combineX234(&p,&q,&t,1);
if (isRoot)
q = p;
break;
case 3: t = p->mlchild;
r = t;
t = q;
q = r;
if (typeOfNode(q) == two_node) {
combineX22(&p,&q,&t,2);
}
else
combineX234(&p,&q,&t,2);
break;
case 4: t = p->mrchild;
r = t;
t = q;
q = r;
if (typeOfNode(q) == two_node) {
combineX22(&p,&q,&t,3);
}
else
combineX234(&p,&q,&t,3);
break;
}
p = q;
if (keyIn(p,key)){
target = p;
flag = true;
if (key == p->datal ){
pos = 1;
}
else if (key == p->datam){
pos = 2;
}
else if (key == p->datar){
pos = 3;
}
}
}
}
if (flag){
switch (pos) {
case 1: target->datal = p->datal;
break;
case 2: target->datam = p->datal;
break;
case 3: target->datar = p->datal;
break;
}
return deletex(p,p->datal);
}
else {
return deletex(p,p->datal);
}
}
}
void visit(Tree234 t)
{
if (t->datar != INT_MAX) {
cout<<"("<<t->datal<<","<<t->datam<<","<<t->datar<<")";
}
else if (t->datam != INT_MAX) {
cout<<"("<<t->datal<<","<<t->datam<<",)";
}
else
cout<<"("<<t->datal<<",,)";
}
void trav(Tree234 t)
{
if(t) {
visit(t);
if (t->lchild == NULL)
return;
cout<<"(";
trav(t->lchild);
cout<<",";
trav(t->mlchild);
cout<<",";
trav(t->mrchild);
cout<<",";
trav(t->rchild);
cout<<")";
}
}
int main()
{
Tree234 T = NULL;
int i;
for(i = 0; i < 12; i++){
insert234(&T,i);
cout<<"Key = "<<i<<" inserted :"<<endl;
trav(T);
cout<<endl<<"----------------------------------------"
"--------------------------"<<endl;
}
int a[12] = {7,6,8,4,3,2,1,0,5,9,10,11};
for (i = 0;i < 12; i++){
delete234(&T,a[i]);
cout<<"Key = "<<a[i]<<" deleted :"<<endl;
trav(T);
cout<<endl<<"----------------------------------------"
"--------------------------"<<endl;
}
}
(初实现版本,后面有时间再优化吧~哎)
测试输出:
Key = 0 inserted :
(0,,)
------------------------------------------------------------------
Key = 1 inserted :
(0,1,)
------------------------------------------------------------------
Key = 2 inserted :
(0,1,2)
------------------------------------------------------------------
Key = 3 inserted :
(1,,)((0,,),(2,3,),,)
------------------------------------------------------------------
Key = 4 inserted :
(1,,)((0,,),(2,3,4),,)
------------------------------------------------------------------
Key = 5 inserted :
(1,3,)((0,,),(2,,),(4,5,),)
------------------------------------------------------------------
Key = 6 inserted :
(1,3,)((0,,),(2,,),(4,5,6),)
------------------------------------------------------------------
Key = 7 inserted :
(1,3,5)((0,,),(2,,),(4,,),(6,7,))
------------------------------------------------------------------
Key = 8 inserted :
(3,,)((1,,)((0,,),(2,,),,),(5,,)((4,,),(6,7,8),,),,)
------------------------------------------------------------------
Key = 9 inserted :
(3,,)((1,,)((0,,),(2,,),,),(5,7,)((4,,),(6,,),(8,9,),),,)
------------------------------------------------------------------
Key = 10 inserted :
(3,,)((1,,)((0,,),(2,,),,),(5,7,)((4,,),(6,,),(8,9,10),),,)
------------------------------------------------------------------
Key = 11 inserted :
(3,,)((1,,)((0,,),(2,,),,),(5,7,9)((4,,),(6,,),(8,,),(10,11,)),,)
------------------------------------------------------------------
Key = 7 deleted :
(3,,)((1,,)((0,,),(2,,),,),(5,9,)((4,,),(6,8,),(10,11,),),,)
------------------------------------------------------------------
Key = 6 deleted :
(3,,)((1,,)((0,,),(2,,),,),(5,9,)((4,,),(8,,),(10,11,),),,)
------------------------------------------------------------------
Key = 8 deleted :
(3,,)((1,,)((0,,),(2,,),,),(9,,)((4,5,),(10,11,),,),,)
------------------------------------------------------------------
Key = 4 deleted :
(1,3,9)((0,,),(2,,),(5,,),(10,11,))
------------------------------------------------------------------
Key = 3 deleted :
(1,9,)((0,,),(2,5,),(10,11,),)
------------------------------------------------------------------
Key = 2 deleted :
(1,9,)((0,,),(5,,),(10,11,),)
------------------------------------------------------------------
Key = 1 deleted :
(9,,)((0,5,),(10,11,),,)
------------------------------------------------------------------
Key = 0 deleted :
(9,,)((5,,),(10,11,),,)
------------------------------------------------------------------
Key = 5 deleted :
(10,,)((9,,),(11,,),,)
------------------------------------------------------------------
Key = 9 deleted :
(10,11,)
------------------------------------------------------------------
Key = 10 deleted :
(11,,)
------------------------------------------------------------------
Key = 11 deleted :
------------------------------------------------------------------
REF:
1,数据结构(C语言版) Ellis Horowitz等