用c++实现自定义红黑树(带有插入功能,左旋转,右旋转)
作者:互联网
**********************************头文件实现***************************
#ifndef REABLACKTREE_REDBLACKTREE_H #define REABLACKTREE_REDBLACKTREE_H #include <arpa/nameser.h> template <class T> class rbtree; template <class T> class rbtreenode; template <class T> class rbtreenode { friend class rbtree<T>; public: rbtreenode(const T& a=T(),rbtreenode<T>* lt=NULL, rbtreenode<T>* ri=NULL, int c=rbtree<T>::black):data(a),leftnode(lt),rightnode(ri),color(c){ std::cout<<"进入红黑树节点构造函数"<<std::endl; }; public: T data; rbtreenode<T>* leftnode; rbtreenode<T>* rightnode; int color; //表示节点颜色 }; template <class T> class rbtree { public: enum {red,black}; rbtree(const T &neginf); ~rbtree(); typedef rbtreenode<T> node; void insert(const T& a); void rotatewithleftchild(node* & k2);//带着左孩子,向右转 向右转节点设为k2,向左转节点设置为k1 void rotatewithrightchild(node* & k1);//带着右孩子,向左转 void doublerotateleftchild(node* &k3);//由于上面两种旋转均为单旋转,单旋转有一定缺陷,故引入双旋转 双旋转向右转 void doublerotaterightchild(node* &k1);//双旋转向左转 //需要处理有两个红色孩子的节点 //插入节点后,处理红色的父亲节点 void handlereorient(T &item); rbtreenode<T>* rbrotate(T &item,node *parent); //**********注意单旋转,双旋转(两次单旋转的叠加)传入参数k1,k2,k3,k4的不同,依次为从左到右的节点。**************8 //注意c++中引用不能返回为空 故此在此处可加上自定义引用类型 T find(); T findmax();//最右边的叶子节点 T findmin();//最左边的叶子节点 bool isempty(); void makeempty(); public: node *header;//指向节点的头指针 node *nullnode;//空节点 node *current;//指向当前节点 node *parent;//指向当前节点的的父节点 node *grand;//祖父节点; node *grandgrand;//曾祖父节点 void reclaimmemory(node *t); //用递归函数设计 }; template <class T> rbtree<T>::rbtree(const T &neginf) { std::cout<<"进入红黑树构造函数"<<std::endl; nullnode=new node(); nullnode->leftnode=nullnode->rightnode=nullnode; header=new node(neginf); header->rightnode=header->leftnode=nullnode; } template <class T> rbtree<T>::~rbtree() { std::cout<<"进入红黑树析构函数"<<std::endl; delete nullnode; delete header; } template <class T> void rbtree<T>::insert(const T &a) { current=parent=grand=grandgrand=header; nullnode->data=a; while (current->data!=a)//二叉搜索树都不能重复 { grandgrand=grand;//红黑树最主要的是平衡,在平衡阶段会用到这几个节点 grand=parent; parent=current; current=a<current->data ?current->leftnode:current->rightnode; //若在查找的过程中一个节点的孩子都是红色的,需要做处理 if (current->leftnode->color==red&¤t->rightnode->color==red) { handlereorient(a);//处理 } } if (current!=nullnode) throw "插入时遇到重复的节点抛出异常";//判断当前的节点是否为空节点,不为空则抛出异常,为空不执行 current=new node(a,nullnode,nullnode);//current指向将新建立的节点,以及将current的parent的节点根据数据的大小, // 用parent指向对像的左指针,或者右指针指向current if (a<parent->data) { parent->leftnode=current; } else if (a>parent->data) { parent->rightnode=current; } //**********************insert函数中以上代码类似于二叉查找树,可以插入节点,但是不会自动平衡************* //自动平衡->红黑树 //自动平衡需要用到向左,向右旋转 //规定新插入的节点都用红色表示 handlereorient(a);//新插入节点是红色的,而它的父节点是红色的 } //***************************单旋转与双旋转***************************** //单旋转,向右转 template <class T>//向右转 void rbtree<T>::rotatewithleftchild(node* &k2) { //定义k1 node* k1=k2->leftnode; k2->leftnode=k1->rightnode;//横向移动 k1->rightnode=k2; k2=k1;//替换根 } //单旋转,向左转 template <class T>//向左转 void rbtree<T>::rotatewithrightchild(node *&k1) { node* k2=k1->rightnode; k1->rightnode=k2->leftnode;//横向移动 k2->leftnode=k1; k1=k2; } //双旋转,向右转 template <class T> void rbtree<T>::doublerotateleftchild(rbtree<T>::node *&k3) { rotatewithrightchild(k3->leftnode);//k3左节点先向左转 rotatewithleftchild(k3);//k3节点,向右转 } //双旋转,向左转 template <class T> void rbtree<T>::doublerotaterightchild(rbtree<T>::node *&k1) { rotatewithleftchild(k1->rightnode);//节点的右儿子向右转 rotatewithrightchild(k1);//此节点在向左转 } //通用旋转函数 template <class T> rbtreenode<T>* rbtree<T>::rbrotate(T &item, rbtree<T>::node *parent) { //分为四种情况 if(item<parent->data) { if (item<parent->leftnode->data) { rotatewithleftchild(parent->leftnode); } else{ rotatewithrightchild(parent->leftnode); } return parent->leftnode; } else if (item>parent->data) { if (item<parent->rightnode->data) { rotatewithleftchild(parent->rightnode); } else { rotatewithrightchild(parent->rightnode); } return parent->rightnode; } } //处理一个节点的两个子节点都是红色的,以及两个红色的节点相链接问题 template <class T> void rbtree<T>::handlereorient(T &item) { //改变颜色 一个黑色节点有两红色的儿子 current->color=red; current->leftnode->color=black; //处理一个节点的两个儿子节点都为红色,将这个节点变为红色,儿子节点都变为黑色 current->rightnode->color=black; if(parent->color==red)//处理当前节点和当前节点的父亲节点都为红色 { grand->color=red; if (item<grand->data!=item<parent->data)//判断新插入的节点是否是内部孙子 { parent=rbrotate(item,grand); } current=rbrotate(item,grandgrand); //再加一次旋转,若是外部孙子,则只执行这次旋转,而内部孙子则进行上次旋转加本轮旋转(双旋转) current->color=black; } header->rightnode->color=black;//根节点必须是黑色的 //单旋转 //双旋转 } //红黑树新的功能 //是否为空 template <class T> bool rbtree<T>::isempty() { return header->rightnode==nullnode; } //清空 template <class T> void rbtree<T>::makeempty() { reclaimMemory(header->rightnode);//从根节点开始清除 header->rightnode=nullnode; } //清除函数 template <class T> void rbtree<T>::reclaimmemory(rbtree<T>::node *t) { if(t!=t->leftnode) { reclaimmemory(t->leftnode); reclaimmemory(t->rightnode); delete t; } } #endif //REABLACKTREE_REDBLACKTREE_H
************************************.cpp文件实现****************************
#include <iostream> #include "redblacktree.h" #include <vector> using namespace std; //红黑树:高级的二叉查找树 //平衡树和非平衡树 //红黑树特征:节点1都有颜色,插入和删除节点的时候要遵守红黑规则 //红黑规则: //1.每一个节点不是红色就是黑色 //2.根总是黑色。 //3.如果节点是红色的,则它的子节点必须是黑社的,(不予许两个红色相连,但允许两个黑色相连) //4.从根到叶节点的每条路径,必须包含相同数目的黑色节点。 //当插入和删除节点后,不满足红黑规则,则要修正,修正方法 //1.改变节点的颜色 //2.旋转 注意:(当面临两个红节点相连接的时候)当新插入的节点是外部孙子,使用单旋转,若是内部孙子,则使用双旋转 void test_rbtree_insert() //没有动态平衡的红黑树 { std::cout << "测试自己写的红黑树" << std::endl; const int neginf=-99999; rbtree<int> myredblacktree(neginf); myredblacktree.insert(30); myredblacktree.insert(15); myredblacktree.insert(70); myredblacktree.insert(20); cout<<myredblacktree.header->data<<endl; cout<<"-------"<<endl; cout<<myredblacktree.header->rightnode->data<<endl; cout<<myredblacktree.header->rightnode->rightnode->data<<endl; cout<<"向右转"<<endl; //测试向右转函数 myredblacktree.rotatewithleftchild(myredblacktree.header->rightnode);//传入节点为30,设为转向函数的根节点 cout<<myredblacktree.header->rightnode->data<<endl; cout<<myredblacktree.header->rightnode->rightnode->data<<endl; cout<<myredblacktree.header->rightnode->rightnode->leftnode->data<<endl; cout<<myredblacktree.header->rightnode->rightnode->rightnode->data<<endl; } void test_rbtree() //有动态平衡红黑树插入 { } int main() { return 0; }
标签:node,parent,自定义,c++,旋转,current,rbtree,rightnode,节点 来源: https://blog.csdn.net/weixin_41874599/article/details/94436828