2-3树的实现初探

前篇文章(2-3树的实现分析)已经分析了2-3树的遍历(traverse),检索(retrieve),插入(insert)和删除(delete)的算法,经过三天的努力,我在分析的基础上采用回溯的方式实现了2-3树,由于还在初级阶段,肯定会出现不少的问题,请多赐教。但经过测试,运行还算正确。下面是代码实现:

2-3树的异常处理类

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // two_three_tree_exception.h //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #ifndef TWO_THREE_TREE_EXCEPTION_H_ #define TWO_THREE_TREE_EXCEPTION_H_ #include<stdexcept> #include<string> class TTTException :public std::logic_error { public: TTTException(const std::string &message="") :std::logic_error(message.c_str()) {} }; #endif


2-3树的item类,每个节点的数据的存储在这里,包含了一个关键字keyword和相关的值 tel。

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // two_three_tree_item.h //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #ifndef TWO_THREE_TREE_ITEM_H_ #define TWO_THREE_TREE_ITEM_H_ #include<string> typedef std::string KeyType; class ItemType { public: ItemType(){} ItemType(const KeyType &_key,const std::string &_tel) :keyword(_key),tel(_tel) {} //get key word keyword; const KeyType & getKey()const { return keyword; } //set value tel; void setTel(const std::string &_tel) { tel=_tel; } //get value tel; std::string getTel()const { return tel; } private: KeyType keyword; std::string tel; }; #endif

2-3树的节点类,实现树的完整连接,其中包含两个item,三个孩子:左孩子,中孩子,右孩子

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // two_three_tree_node.h //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #ifndef TWO_THREE_TREE_NODE_H_ #define TWO_THREE_TREE_NODE_H_ #include"two_three_tree_item.h" class Node { private: Node(ItemType &_item,Node *_leftPtr,Node*_middlePtr) :fItem(_item),LeftPtr(_leftPtr) ,MiddlePtr(_middlePtr),RightPtr(NULL) {Nitems=1;} //当节点中的item项数为1时,调用此函数重新整合节点 void reSet(ItemType &_item,Node *_leftPtr, Node*_middlePtr) { Node *tempL=_leftPtr,*tempM=_middlePtr; fItem=_item; LeftPtr=tempL; MiddlePtr=tempM; RightPtr=NULL; setNumb(1); } //当节点中的item项数为2时,调用此函数重新整合节点 void reSet( ItemType &_fitem,ItemType &_litem,Node *_leftPtr,Node *_middlePtr,Node *_rightPtr) { ItemType tempfi=_fitem,templi=_litem; Node *tempL=_leftPtr,*tempM=_middlePtr,*tempR=_rightPtr; LeftPtr=tempL; MiddlePtr=tempM; RightPtr=tempR; fItem=tempfi; lItem=templi; setNumb(2); } //设置节点中item的数目 void setNumb(int n) { Nitems=n; } //清空当前节点中的孩子和item(items) void clear() { LeftPtr=MiddlePtr=RightPtr=NULL; setNumb(0); } ItemType fItem,lItem; Node *LeftPtr,*MiddlePtr,*RightPtr; int Nitems; friend class ttTree; }; #endif

2-3树实现的头文件

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // two_three_tree.h //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #ifndef TWO_THREE_TREE_H_ #define TWO_THREE_TREE_H_ #include"two_three_tree_exception.h" #include"two_three_tree_node.h" typedef void (*FuncT)(ItemType &_item); class ttTree { public: //默认构造函数 ttTree(); //复制构造函数 ttTree(ttTree &_tree); //析构函数 virtual ~ttTree(); virtual bool empty()const; //检索 virtual void retrieve(const KeyType &_keyword,ItemType &_item)throw(TTTException); //遍历 virtual void traverse(FuncT visit); //插入 virtual void insert(const ItemType & newitem) throw(TTTException); //删除 virtual void remove(const KeyType &keyword) throw(TTTException); //赋值操作符重载 virtual ttTree &operator=(ttTree &oldtree)throw(TTTException); protected: bool insertTree(Node *&treePtr,Node *&tempPtr,ItemType &tempItem)throw(TTTException); bool removeTree(Node *&treePtr,Node *&tempPtr,const KeyType &_key) throw(TTTException); void retrieveTree(Node * &treePtr,const KeyType &_key,ItemType &_item)throw(TTTException); void traverseTree(Node *&treePtr,FuncT visit); //复制构造函数 void copyTree(Node *&newtree, Node* &oldtree)throw(TTTException); void destroy(Node *&treePtr); //在插入的情况下,当当前的item数大于2时,调用此函数维护2-3的原有属性 bool insertMaintain(Node *&treePtr,Node *&tempPtr,ItemType &tempItem,char ch)throw(TTTException); //在删除的情况下,当当前的item数小于1时,调用此函数维护2-3的原有属性 bool removeMaintain(Node *&treePtr,Node *&tempPtr,char ch); //寻找当前节点treeptr中项目的中序后继, int processLeft(Node *&treePtr,Node*&tempPtr,ItemType &replace); //当前的节点treePtr中item数目为2时返回true,否侧返回false bool twoItem(Node *&treePtr)const; //当前的节点treePtr中的item数目为1时返回true,否则返回false bool oneItem(Node *&treePtr)const; //判断当前节点treePtr是否为根节点,如是则返回true,否则返回false bool isRoot(Node *&treePtr)const; //判断当前节点treePtr是否为叶节点,若是则返回true,否则返回false bool isLeaf(Node *&treePtr)const; //判断当前节点treePtr中是否存在与关键字_key相等的项 //若存在则返回true,否则返回false bool equal(Node*&treePtr,const KeyType & _key)const; //按项中关键字的大小重新排序first,middle,last,使其满足 //first.getkey()<=middle.getKey()<=last.getkey() void sort(ItemType &first,ItemType &middle,ItemType &last); private: Node *root; }; #endif


2-3树的现实文件

#include<cstddef> #include<cassert> #include"two_three_tree.h" using namespace std; ttTree::ttTree():root(NULL) { } ttTree::ttTree(ttTree &_tree) { copyTree(root,_tree.root); } ttTree::~ttTree() { destroy(root); } bool ttTree::empty()const { return root==NULL; } void ttTree::retrieve(const KeyType &_keyword,ItemType &_item) throw(TTTException) { try{ retrieveTree(root,_keyword,_item); }catch(TTTException &e) { throw; } } void ttTree::traverse(FuncT visit) { traverseTree(root,visit); } void ttTree::insert(const ItemType &newitem) throw(TTTException) { Node *inPtr=NULL; //point to a new creating Node, and deliver new node to //last time insertTree function called ItemType inItem=newitem; // contain the "internal" item value that canot be cotained in this // node try{ bool ok=insertTree(root,inPtr,inItem); if(!ok) throw TTTException("TTTException :insert newitem failed !"); }catch(TTTException &e) { throw; } } void ttTree::remove(const KeyType &keyword) throw(TTTException) { Node *rePtr=NULL; //point to the empty node's child try{ bool ok=removeTree(root,rePtr,keyword); if(!ok) throw TTTException("TTTException :remove item failed !"); }catch(TTTException &e) { throw; } } ttTree &ttTree::operator=(ttTree &oldtree)throw(TTTException) { try{ if(this==&oldtree) return *this; else { destroy(root); copyTree(root,oldtree.root); } }catch(TTTException &e) { throw; } } bool ttTree::insertTree(Node *&treePtr,Node *&tempPtr, ItemType &tempItem)throw(TTTException) { if(empty()) { treePtr=new Node(tempItem,NULL,NULL); if(treePtr==NULL) throw TTTException("TTTException :allocate memory failed !"); return true; } else if(isLeaf(treePtr)) { try{ return insertMaintain(treePtr,tempPtr,tempItem,'F'); }catch(TTTException &e) { throw; } } else if((tempItem.getKey())<(treePtr->fItem.getKey())) { bool success=insertTree(treePtr->LeftPtr,tempPtr,tempItem); if(success) return true; else { try{ return insertMaintain(treePtr,tempPtr,tempItem,'L'); }catch(TTTException &e) { throw; } } } else if(twoItem(treePtr)&&(tempItem.getKey()>=treePtr->lItem.getKey())) { bool success=insertTree(treePtr->RightPtr,tempPtr,tempItem); if(success) return true; else { try{ return insertMaintain(treePtr,tempPtr,tempItem,'R'); }catch(TTTException &e) { throw; } } } else { bool success=insertTree(treePtr->MiddlePtr,tempPtr,tempItem); if(success) return true; else { try{ return insertMaintain(treePtr,tempPtr,tempItem,'M'); }catch(TTTException &e) { throw; } } } } bool ttTree::removeTree(Node *&treePtr,Node *&tempPtr,const KeyType &_key) throw(TTTException) { if(empty()) throw TTTException("TTTException :two three tree is empty !"); else if(isLeaf(treePtr)&&(!equal(treePtr,_key))) throw TTTException("TTTException :item contian keyword not exist !"); else if(equal(treePtr,_key)) { ItemType replace; if(treePtr->fItem.getKey()==_key) { int placeok=processLeft(treePtr->MiddlePtr,tempPtr,replace); treePtr->fItem=replace; if(placeok==0) return true; else if(placeok==1) { return removeMaintain(treePtr,tempPtr,'M'); } else { if(twoItem(treePtr)) { treePtr->reSet(treePtr->lItem,NULL,NULL); return true; } return false; } } else { int placeok=processLeft(treePtr->RightPtr,tempPtr,replace); //must deal with solution that treePtr is a leaf treePtr->lItem=replace; if(placeok==0) return true; else if(placeok==1) { return removeMaintain(treePtr,tempPtr,'R'); } else { treePtr->reSet(treePtr->fItem,NULL,NULL); return true; } } } else if(_key<(treePtr->fItem.getKey())) { bool success=removeTree(treePtr->LeftPtr,tempPtr,_key); if(success) return true; else { return removeMaintain(treePtr,tempPtr,'L'); } } else if(twoItem(treePtr)&&(_key>=(treePtr->lItem.getKey()))) { bool success=removeTree(treePtr->RightPtr,tempPtr,_key); if(success) return true; else return removeMaintain(treePtr,tempPtr,'R'); } else { bool success=removeTree(treePtr->MiddlePtr,tempPtr,_key); if(success) return true; else return removeMaintain(treePtr,tempPtr,'R'); } } int ttTree::processLeft(Node *&treePtr,Node *&tempPtr,ItemType &replace) { if(treePtr==NULL) return 2; else if(isLeaf(treePtr)) { replace=treePtr->fItem; if(twoItem(treePtr)) { treePtr->reSet(treePtr->lItem,NULL,NULL); return 0; } tempPtr=NULL; return 1; } else { int result=processLeft(treePtr->LeftPtr,tempPtr,replace); if(result==0) return 0; else if(result==1) { bool placeok=removeMaintain(treePtr,tempPtr,'L'); if(placeok) return 0; else return 1; } } } void ttTree::retrieveTree(Node * &treePtr,const KeyType &_key, ItemType &_item) throw(TTTException) { if(empty()) throw TTTException("TTTException:empty two three tree !"); else if(isLeaf(treePtr)&&(!equal(treePtr,_key))) throw TTTException("TTTException :the item whose key word equal to _key not exist !"); else if(equal(treePtr,_key)) { if(treePtr->fItem.getKey()==_key) _item=treePtr->fItem; else _item=treePtr->lItem; } else if(_key<(treePtr->fItem.getKey())) retrieveTree(treePtr->LeftPtr,_key,_item); else if(twoItem(treePtr)&&(_key>=treePtr->lItem.getKey())) retrieveTree(treePtr->RightPtr,_key,_item); else retrieveTree(treePtr->MiddlePtr,_key,_item); } void ttTree::traverseTree(Node *&treePtr,FuncT visit) { if(treePtr!=NULL) { traverseTree(treePtr->LeftPtr,visit); visit(treePtr->fItem); traverseTree(treePtr->MiddlePtr,visit); if(twoItem(treePtr)) { visit(treePtr->lItem); traverseTree(treePtr->RightPtr,visit); } } } void ttTree::copyTree(Node *&newtree,Node * &oldtree) throw(TTTException) { if(oldtree!=NULL) { newtree= new Node(oldtree->fItem,NULL,NULL); if(newtree==NULL) throw TTTException("TTTException :allocate memory failed !"); if(twoItem(oldtree)) { newtree->reSet(oldtree->fItem,oldtree->lItem, NULL,NULL,NULL); } copyTree(newtree->LeftPtr,oldtree->LeftPtr); copyTree(newtree->MiddlePtr,oldtree->MiddlePtr); if(twoItem(oldtree)) copyTree(newtree->RightPtr,oldtree->RightPtr); } } void ttTree::destroy(Node *&treePtr) { if(treePtr!=NULL) { destroy(treePtr->LeftPtr); destroy(treePtr->MiddlePtr); if(twoItem(treePtr))//may be left out destroy(treePtr->RightPtr); delete treePtr; treePtr=NULL; } } bool ttTree::twoItem(Node *&treePtr)const { if(treePtr->Nitems==2) return true; else return false; } bool ttTree::oneItem(Node *&treePtr)const { if(treePtr->Nitems==1) return true; else return false; } bool ttTree::isRoot(Node *&treePtr)const { if((root!=NULL)&&(root==treePtr)) return true; else return false; } bool ttTree::isLeaf(Node *&treePtr)const { if((treePtr->LeftPtr==NULL)&&(treePtr->MiddlePtr==NULL) &&(treePtr->RightPtr==NULL)) return true; else return false; } bool ttTree::equal(Node *&treePtr,const KeyType &_key)const { if(treePtr->fItem.getKey()==_key) return true; else if(twoItem(treePtr)&&(treePtr->lItem.getKey()==_key)) return true; else return false; } void ttTree::sort(ItemType &first,ItemType &middle,ItemType &last) { ItemType temp; if(first.getKey()<middle.getKey()) { if(first.getKey()<last.getKey()) { if(middle.getKey()>=last.getKey()) { temp=middle; middle=last; last=temp; } } else { temp=last; last=middle; middle=first; first=temp; } } else { if(middle.getKey()<last.getKey()) { if(first.getKey()<last.getKey()) { temp=middle; middle=first; first=temp; } else { temp=middle; middle=last; last=first; first=temp; } } else { temp=last; last=first; first=temp; } } } bool ttTree::removeMaintain(Node *&treePtr,Node *&tempPtr,char ch) { if(ch=='R')//R for ptr1 relative to ptr2's position is right { if(twoItem(treePtr->MiddlePtr)) { treePtr->RightPtr->reSet(treePtr->lItem,treePtr->MiddlePtr->RightPtr,tempPtr); treePtr->reSet(treePtr->fItem,treePtr->MiddlePtr->lItem,treePtr->LeftPtr,treePtr->MiddlePtr,treePtr->RightPtr); treePtr->MiddlePtr->reSet(treePtr->MiddlePtr->fItem,treePtr->MiddlePtr->LeftPtr,treePtr->MiddlePtr->MiddlePtr); return true; } else { treePtr->MiddlePtr->reSet(treePtr->MiddlePtr->fItem,treePtr->lItem,treePtr->MiddlePtr->LeftPtr,treePtr->MiddlePtr->MiddlePtr,tempPtr); treePtr->RightPtr->clear();//clear function ---- delete treePtr->RightPtr; treePtr->RightPtr=NULL; treePtr->reSet(treePtr->fItem,treePtr->LeftPtr,treePtr->MiddlePtr); return true; } } else if(ch=='M') { if(twoItem(treePtr->LeftPtr))// function --------------- { treePtr->MiddlePtr->reSet(treePtr->fItem,treePtr->LeftPtr->RightPtr,tempPtr); treePtr->reSet(treePtr->LeftPtr->lItem,treePtr->lItem,treePtr->LeftPtr,treePtr->MiddlePtr,treePtr->RightPtr); treePtr->LeftPtr->reSet(treePtr->LeftPtr->fItem,treePtr->LeftPtr->LeftPtr,treePtr->LeftPtr->MiddlePtr); return true; } else { treePtr->LeftPtr->reSet(treePtr->LeftPtr->fItem,treePtr->fItem,treePtr->LeftPtr->LeftPtr,treePtr->LeftPtr->MiddlePtr,tempPtr); treePtr->MiddlePtr->clear(); delete treePtr->MiddlePtr; treePtr->MiddlePtr=NULL; if(oneItem(treePtr)) { treePtr->setNumb(0); tempPtr=treePtr->LeftPtr; if(isRoot(treePtr)) { treePtr->clear(); delete treePtr; treePtr=tempPtr; return true; } return false; } else { treePtr->reSet(treePtr->lItem,treePtr->LeftPtr,treePtr->RightPtr); return true; } } } else if(ch=='L')//L for ptr1 relative to ptr2's position is left { if(twoItem(treePtr->MiddlePtr)) { treePtr->LeftPtr->reSet(treePtr->fItem,tempPtr,treePtr->MiddlePtr->LeftPtr); treePtr->reSet(treePtr->MiddlePtr->fItem,treePtr->lItem,treePtr->LeftPtr,treePtr->MiddlePtr,treePtr->RightPtr); treePtr->MiddlePtr->reSet(treePtr->MiddlePtr->lItem,treePtr->MiddlePtr->MiddlePtr,treePtr->MiddlePtr->RightPtr); return true; } else { treePtr->MiddlePtr->reSet(treePtr->fItem,treePtr->MiddlePtr->lItem,tempPtr,treePtr->MiddlePtr->LeftPtr,treePtr->MiddlePtr->MiddlePtr); treePtr->LeftPtr->clear(); delete treePtr->LeftPtr; treePtr->LeftPtr=NULL; if(oneItem(treePtr)) { treePtr->setNumb(0); tempPtr=treePtr->MiddlePtr; if(isRoot(treePtr)) { treePtr->clear(); delete treePtr; treePtr=tempPtr; return true; } return false; } else { treePtr->reSet(treePtr->lItem,treePtr->MiddlePtr,treePtr->RightPtr); return true; } } } } bool ttTree::insertMaintain(Node *&treePtr,Node *&tempPtr, ItemType &tempItem,char ch) throw(TTTException) { if(ch=='L') { if(twoItem(treePtr)) { ItemType tranItem=treePtr->fItem; Node *tranPtr=new Node(tempItem,tempPtr,treePtr->LeftPtr); if(tranPtr==NULL) throw TTTException("TTTException :allocate memory failed !"); treePtr->reSet(treePtr->lItem,treePtr->MiddlePtr,treePtr->RightPtr); tempItem=tranItem; tempPtr=tranPtr; if(isRoot(treePtr)) { Node *tempRoot=new Node(tempItem,tempPtr,treePtr); if(tempRoot==NULL) throw TTTException("TTTException :allocate memory failed !"); root=tempRoot; return true; } return false; } else { treePtr->reSet(tempItem,treePtr->fItem,tempPtr,treePtr->LeftPtr,treePtr->MiddlePtr); return true; } } else if(ch=='M') { if(twoItem(treePtr)) { Node *tranPtr=new Node(treePtr->fItem,treePtr->LeftPtr,tempPtr); if(tranPtr==NULL) throw TTTException("TTTEexception :allocate memory failed !"); treePtr->reSet(treePtr->lItem,treePtr->MiddlePtr,treePtr->RightPtr); tempPtr=tranPtr; if(isRoot(treePtr)) { Node *tempRoot=new Node(tempItem,tempPtr,treePtr); if(tempRoot==NULL) throw TTTException("TTTException :allocate memory failed !"); root=tempRoot; return true; } return false; } else { treePtr->reSet(treePtr->fItem,tempItem,treePtr->LeftPtr, tempPtr,treePtr->MiddlePtr); return true; } } else if(ch=='R') { ItemType tranItem=treePtr->lItem; Node *tranPtr=new Node(treePtr->fItem,treePtr->LeftPtr,treePtr->MiddlePtr); if(tranPtr==NULL) throw TTTException("TTTException :allocate memory failed !"); treePtr->reSet(tempItem,tempPtr,treePtr->RightPtr); tempItem=tranItem; tempPtr=tranPtr; if(isRoot(treePtr)) { Node *tempRoot=new Node(tempItem,tempPtr,treePtr); if(tempRoot==NULL) throw TTTException("TTTException :allocate memory failed !"); root=tempRoot; return true; } return false; } else { if(twoItem(treePtr)) { sort(treePtr->fItem,tempItem,treePtr->lItem); Node *tranPtr=new Node(treePtr->fItem,NULL,NULL); if(tranPtr==NULL) throw TTTException("TTTException :allocate memory failed !"); treePtr->reSet(treePtr->lItem,NULL,NULL); tempPtr=tranPtr; if(isRoot(treePtr)) { Node *tempRoot=new Node(tempItem,tempPtr,treePtr); if(tempRoot==NULL) throw TTTException("TTTException :allocate memory failed !"); root=tempRoot; return true; } return false; } else { ItemType tranItem; if(treePtr->fItem.getKey()>tempItem.getKey()) { tranItem=treePtr->fItem; treePtr->fItem=tempItem; tempItem=tranItem; } treePtr->reSet(treePtr->fItem,tempItem,NULL,NULL,NULL); return true; } } }

2-3树的简单的测试程序

#include<iostream> #include<cstdlib> #include<string> #include<ctime> #include"two_three_tree.h" using namespace std; void display(ItemType &_item); int main() { srand(time(0)); ttTree atree,btree; ItemType aitem; string thekey,thetel; try{ for(int i=0;i<20;i++) { for(int j=0;j<7;j++) { thekey=thekey+char(rand()%26+'a'); thetel=thetel+char(rand()%10+'0'); } atree.insert(ItemType(thekey,thetel)); thekey.clear(); thetel.clear(); } cout<<"the item in atree :"<<endl; atree.traverse(display); cout<<"traverse over !"<<endl; cout<<"calling operator= function :"<<endl; btree=atree; cout<<"the item in btree :"<<endl; btree.traverse(display); cout<<"traverse over !"<<endl; }catch(TTTException &e) { cout<<e.what()<<endl; } return 0; } void display(ItemType &_item) { cout<<"the information :"<<_item.getKey()<<'\t'<<_item.getTel()<<endl; }

有兴趣的可以自己测试一下。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值