本来只是想实现一个红黑树,但是在实现过程中发现一个操作和我参考的一篇博客有出入,所以把我实现的红黑树放上来,一方面供红黑树的初学者参考,更重要的是想请高人指点一下我的疏漏之处。
程序使用easyx显示,vs2017平台。
笔者参考博客的地址:https://www.cnblogs.com/skywang12345/p/3245399.html
程序运行效果图:
头文件:
#ifndef BTREE
#define BTREE
#include
#include
#include
#include<graphics.h>
typedef int Tdata;
using namespace std;
int pow2(int n);
class tree
{
protected:
vector data;//数据向量
vector father;//父节点指示
vector lson;//左子树指示
vector rson;//右子树指示
stack unused;//未使用的空间
int itemNum;
const int maxItem;
int findLoc(Tdata d, int loc);//搜索新节点可能的插入位置
int findLeft(int loc);//搜索前趋
int findRight(int loc);//搜索后继
public:
tree();
tree(int max);
virtual ~tree();
int ItemNum();//返回现在树中的项目数量
int treeWidth();//返回树的宽度
int physicalTreeWidth(int loc);//返回树显示所需宽度
int treeHeight();//返回树高度
int searchData(Tdata d) { return searchData(d, lson[0]); }//搜索指定的数据,若失败,返回-1, 否则返回数据所在的位置
int searchData(Tdata d, int loc);
virtual int add(Tdata odata);//添加指定数据,返回添加位置,若数据已经存在,则返回-1
virtual int cut(Tdata odata);//删除指定数据,返回数据的后继,若不存在,则返回-1。
void print();//打印树
virtual void print(int n, int loc);
virtual void print(int height, pair<int, int> coor, int loc);//使用easyx打印树
};
class RBtree :public tree
{
private:
vector flag;//节点颜色指示
enum { ered = 1, eblack = 2 ,unknown = 0};
public:
RBtree();
RBtree(int max);
~RBtree();
void Rrotate(int loc);//将X变成一个左节点
void Lrotate(int loc);//将X变成一个右节点
stack getPath(Tdata data);//获取从根节点到指定数据的路径
int addSituation(int loc);//判断添加新节点后应如何操作
bool isBlack(int loc) { return (loc == -1 || flag[loc] == eblack); }//判断节点是否为黑色
bool isRed(int loc) { return (loc != -1 && flag[loc] == ered); }//判断节点是否为红色
virtual int add(Tdata odata);
virtual int cut(Tdata odata);
virtual void print(int ,pair<int ,int>, int loc);
};
#endif
二叉树的实现:
#include"BinaryTree.h"
#include<assert.h>
#include
#include
tree::tree(): maxItem(100)
{
itemNum = 0;
data.resize(maxItem);
father.resize(maxItem);
lson.resize(maxItem);
rson.resize(maxItem);
lson[0] = -1;
rson[0] = -1;
father[0] = -1;
for (int i = 1; i < maxItem; i++)//0作根节点的父节点,不使用。
{
unused.push(i);
father[i] = -1;
lson[i] = -1;
rson[i] = -1;
}
}
tree::tree(int max):maxItem(max)
{
itemNum = 0;
data.resize(maxItem);
father.resize(maxItem);
lson.resize(maxItem);
rson.resize(maxItem);
lson[0] = -1;
father[0] = -1;
rson[0] = -1;
for (int i = 1; i < maxItem; i++)//0作根节点的父节点,不使用。
{
unused.push(i);
father[i] = -1;
lson[i] = -1;
rson[i] = -1;
}
}
tree::~tree()
{
}
int tree::ItemNum()
{
return itemNum;
}
int tree::physicalTreeWidth(int loc)
{
if (itemNum == 0)
return 0;
if (loc == -1)
return 0;
return (1 + physicalTreeWidth(lson[loc]) + physicalTreeWidth(rson[loc]));
}
int tree::treeHeight()
{
if (itemNum == 0)
return 0;
queue<pair<int, int>> n;
pair<int, int> fnode, snode, dwidth;//dwidth.first为深度,dwidth.second为宽度
int height = 0;
dwidth.first = 1;
dwidth.second = 1;
fnode.first = 1;
fnode.second = lson[0];
n.push(fnode);
while (n.size() != 0)
{
fnode = n.front();
n.pop();
//cout << "depth: " << fnode.first << " data: " << data[fnode.second] << endl;
if (dwidth.first == fnode.first)//如果现在节点和上一个节点是同一深度
{
dwidth.second++;
}
else
{
dwidth.first++;
dwidth.second = 1;
if (dwidth.first > height)//更新深度
height = dwidth.first;
}
if (lson[fnode.second] != -1)
{
snode.first = fnode.first + 1;
snode.second = lson[fnode.second];
n.push(snode);
}
if (rson[fnode.second] != -1)
{
snode.first = fnode.first + 1;
snode.second = rson[fnode.second];
n.push(snode);
}
}
return height;
}
int tree::treeWidth()
{
if (itemNum == 0)
return 0;
queue<pair<int, int>> n;
pair<int, int> fnode, snode, dwidth;
int width = 0;
dwidth.first = 1;
dwidth.second = 1;
fnode.first = 1;
fnode.second = lson[0];
n.push(fnode);
while (n.size() != 0)
{
fnode = n.front();
if (dwidth.first == fnode.first)//如果现在节点和上一个节点是同一深度
{
dwidth.second++;
}
else
{
if (dwidth.second > width)//更新深度
width = dwidth.second;
dwidth.first++;
dwidth.second = 1;
}
n.pop();
if (lson[fnode.second] != -1)
{
snode.first = fnode.first + 1;
snode.second = lson[fnode.second];
n.push(snode);
}
if (rson[fnode.second] != -1)
{
snode.first = fnode.first + 1;
snode.second = rson[fnode.second];
n.push(snode);
}
}
return width;
}
int tree::add(Tdata odata)
{
if (searchData(odata) != -1)//数据已经在树中
return -1;
if (itemNum == 0)
{
itemNum++;
int top = unused.top();
data[top] = odata;
unused.pop();
lson[0] = top;
father[top] = 0;
lson[top] = -1;
rson[top] = -1;
return top;
}
else if (itemNum == maxItem)
return -1;
else
{
int loc = findLoc(odata, lson[0]);//loc为插入数据的父节点
if (loc == -1)//树满
return -1;
else
{
itemNum++;
int top = unused.top();
unused.pop();
data[top] = odata;
father[top] = loc;
if (odata > data[loc])
rson[loc] = top;
else
lson[loc] = top;
return top;
}
}
}
int tree::findLoc(Tdata d, int loc)
{
if (d == data[loc])
return -1;
else if (d > data[loc])
{
if (rson[loc] == -1)
return loc;
else
return findLoc(d, rson[loc]);
}
else
{
if (lson[loc] == -1)
return loc;
else
return findLoc(d, lson[loc]);
}
}
int tree::findRight(int loc)
{
int son = rson[loc];
while (lson[son] != -1)
{
son = lson[son];
}
return son;
}
int tree::findLeft(int loc)
{
int son = lson[loc];
while (rson[son] != -1)
{
son = rson[son];
}
return son;
}
int tree::searchData(Tdata d, int loc)
{
if (loc == -1)
return -1;
if (d == data[loc])
return loc;
else if (d > data[loc])
{
return searchData(d, rson[loc]);
}
else
{
return searchData(d, lson[loc]);
}
}
int tree::cut(Tdata odata)
{
int dloc = searchData(odata);
if (dloc == -1)//数据不在树中
return -1;
else
{
int cn = findRight(dloc);//查找后继
if (cn == -1)//无后继,说明所有当前子树所有节点都小于等于根节点,dloc无右子树
{
unused.push(dloc);//空间回收
if (dloc == lson[father[dloc]])
lson[father[dloc]] = lson[dloc];
else
rson[father[dloc]] = lson[dloc];
return -1;
}
else//存在后趋,则删除后继,且在中序下,后继只可能存在右节点
{
data[dloc] = data[cn];
unused.push(cn);
int nfather = father[cn];
if (cn == lson[nfather])//cn是左子树
lson[nfather] = rson[cn];
else if (cn == rson[nfather])
rson[nfather] = rson[cn];
return cn;
}
}
}
void tree::print(int height, pair<int, int> coor, int loc)//coor为父节点坐标,coor.first为X坐标,coor.second为Y坐标
{
if (loc == -1)
return;
char b[4];
int widthgap = 35;
int heightgap = 100;
if (lson[loc] != -1)//显示左孩子
{
setfillcolor(RED);//节点颜色
fillcircle(coor.first - widthgap * pow2(height - 1), coor.second + heightgap, 25);
sprintf_s(b, "%d\0", data[lson[loc]]);
RECT r = { coor.first - widthgap * pow2(height - 1) - 20, coor.second + heightgap - 15,
coor.first - widthgap * pow2(height - 1) + 20, coor.second + heightgap + 15 };
drawtext(b, &r, DT_CENTER);
line(coor.first - 15, coor.second + 20, coor.first - widthgap * pow2(height - 1) + 15, coor.second + heightgap - 20);
}
if (rson[loc] != -1)//显示右孩子
{
setfillcolor(BLACK);//节点颜色
fillcircle(coor.first + widthgap * pow2(height - 1), coor.second + heightgap, 25);
sprintf_s(b, "%d\0", data[rson[loc]]);
RECT r = { coor.first + widthgap * pow2(height - 1) - 20, coor.second + heightgap - 15,
coor.first + widthgap * pow2(height - 1) + 20, coor.second + heightgap + 15 };
drawtext(b, &r, DT_CENTER);
line(coor.first + 15, coor.second + 20, coor.first + widthgap * pow2(height - 1) - 15, coor.second + heightgap - 20);
}
print(height - 1, pair<int, int>(coor.first - widthgap * pow2(height - 1), coor.second + heightgap), lson[loc]);//递归打印左子树
print(height - 1, pair<int, int>(coor.first + widthgap * pow2(height - 1), coor.second + heightgap), rson[loc]);//递归打印右子树
}
void tree::print()
{
print(0, lson[0]);
for (int i = 0; i < maxItem; i++)
cout << i << " \t";
cout << endl;
for (int i = 0; i < maxItem; i++)
cout << data[i] << " \t";
cout << endl;
for (int i = 0; i < maxItem; i++)
cout << lson[i] << " \t";
cout << endl;
for (int i = 0; i < maxItem; i++)
cout << rson[i] << " \t";
cout << endl;
for (int i = 0; i < maxItem; i++)
cout << father[i] << " \t";
cout << endl;
}
void tree::print(int n, int loc)
{
if (loc == 0 || loc == -1)
return;
for (int i = 0; i < n; i++)
cout << " ";
cout << data[loc] << endl;
print(n + 1, lson[loc]);
print(n + 1, rson[loc]);
}
int pow2(int n)
{
int t = 1;
for (int i = 0; i < n; i++)
t *= 2;
return t;
}
红黑树的实现:
#include"BinaryTree.h"
RBtree::RBtree()
{
flag.resize(maxItem);
for (int i = 0; i < maxItem; i++)
flag[i] = eblack;
}
RBtree::RBtree(int max) :tree(max)
{
flag.resize(maxItem);
for (int i = 0; i < maxItem; i++)
flag[i] = eblack;
}
RBtree::~RBtree()
{
}
void RBtree::Rrotate(int loc)
{
if (lson[loc] == -1)
return;
else
{
int s, f;
if (lson[father[loc]] == loc)//X为左节点
{
//链接X的左节点
s = lson[loc];
f = father[loc];
lson[f] = s;
father[s] = f;
//链接X左节点的右节点
s = rson[lson[loc]];
f = loc;
lson[f] = s;
if (s != -1)
father[s] = f;
//链接X
f = lson[father[loc]];
s = loc;
rson[f] = s;
father[s] = f;
}
else//X为右节点
{
//链接X的左节点
s = lson[loc];
f = father[loc];
rson[f] = s;
father[s] = f;
//链接X左节点的右节点
s = rson[lson[loc]];
f = loc;
lson[f] = s;
if (s != -1)
father[s] = f;
//链接X
f = rson[father[loc]];
s = loc;
rson[f] = s;
father[s] = f;
}
}
}
void RBtree::Lrotate(int loc)
{
if (rson[loc] == -1)
return;
else
{
int s, f;
if (lson[father[loc]] == loc)//X为左节点
{
//链接X的右节点
s = rson[loc];
f = father[loc];
lson[f] = s;
father[s] = f;
//链接X右节点的左节点
s = lson[rson[loc]];
f = loc;
rson[f] = s;
if (s != -1)
father[s] = f;
//链接X
f = lson[father[loc]];
s = loc;
lson[f] = s;
father[s] = f;
}
else//X为右节点
{
//链接X的右节点
s = rson[loc];
f = father[loc];
rson[f] = s;
father[s] = f;
//链接X右节点的左节点
s = lson[rson[loc]];
f = loc;
rson[f] = s;
if (s != -1)
father[s] = f;
//链接X
f = rson[father[loc]];
s = loc;
lson[f] = s;
father[s] = f;
}
}
}
stack RBtree::getPath(Tdata odata)
{
int tmp = lson[0];
stack s;
while (tmp != -1)
{
s.push(tmp);
if (odata == data[tmp])
return s;
else
{
if (odata > data[tmp])
tmp = rson[tmp];
else if (odata < data[tmp])
tmp = lson[tmp];
}
}
s.push(-1);
return s;
}
int RBtree::addSituation(int loc)
{
if (flag[father[loc]] == eblack)//不需要处理
return 0;
if (father[loc] == lson[0])//父节点为根节点,则直接将根节点置为黑色
return 1;
int grandfather = father[father[loc]];
if (isRed(grandfather) && isRed(grandfather))//爷爷节点的孩子均为红色
return 2;
else //爷爷节点的孩子一个是红色,一个是黑色
{
if (father[loc] == lson[grandfather])//父节点为爷爷节点的左孩子
return 3;
else //父节点为爷爷节点的右孩子
return 4;
}
}
int RBtree::add(Tdata odata)
{
//cout << "RBtree add: " << odata << endl;
int loc = tree::add(odata);
if (loc == -1)
return -1;
else
{
flag[loc] = ered;
int floc = loc;
while (floc != lson[0])
{
int lgrandfather = father[father[floc]];
int lfather = father[floc];
switch (addSituation(floc))
{
case 0:
return loc;
case 1:
flag[lson[0]] = eblack;
return loc;
case 2:
flag[lgrandfather] = ered;
flag[lson[lgrandfather]] = eblack;
flag[rson[lgrandfather]] = eblack;
return loc;
case 3:
if (lson[lfather] == floc)//当前节点为左孩子
{
Rrotate(lgrandfather);
flag[floc] = eblack;
flag[lfather] = ered;
flag[lgrandfather] = eblack;
floc = lfather;
break;
}
else //当前节点为右孩子
{
Lrotate(lfather);
floc = lfather;
break;
}
case 4:
if (lson[lfather] == floc)//当前节点为左孩子
{
Rrotate(lfather);
floc = lfather;
break;
}
else //当前节点为右孩子
{
Lrotate(lgrandfather);
flag[floc] = eblack;
flag[lfather] = ered;
flag[lgrandfather] = eblack;
floc = lfather;
break;
}
}
}
flag[lson[0]] = eblack;
return loc;
}
}
int RBtree::cut(Tdata odata)
{
int loc = tree::cut(odata);
if (loc == -1)
return -1;
else
{
}
}
void RBtree::print(int height, pair<int, int> coor, int loc)
{
if (loc == -1)
return;
char b[4];
int widthgap = 35;
int heightgap = 100;
if (lson[loc] != -1)//显示左孩子
{
if(isRed(lson[loc]))
setfillcolor(RED);//节点颜色红色
else
setfillcolor(BLACK);//节点颜色黑色
fillcircle(coor.first - widthgap * pow2(height - 1), coor.second + heightgap, 25);
sprintf_s(b, "%d\0", data[lson[loc]]);
RECT r = { coor.first - widthgap * pow2(height - 1) - 20, coor.second + heightgap - 15,
coor.first - widthgap * pow2(height - 1) + 20, coor.second + heightgap + 15 };
drawtext(b, &r, DT_CENTER);
line(coor.first - 15, coor.second + 20, coor.first - widthgap * pow2(height - 1) + 15, coor.second + heightgap - 20);
}
if (rson[loc] != -1)//显示右孩子
{
if (isRed(rson[loc]))
setfillcolor(RED);//节点颜色红色
else
setfillcolor(BLACK);//节点颜色黑色
fillcircle(coor.first + widthgap * pow2(height - 1), coor.second + heightgap, 25);
sprintf_s(b, "%d\0", data[rson[loc]]);
RECT r = { coor.first + widthgap * pow2(height - 1) - 20, coor.second + heightgap - 15,
coor.first + widthgap * pow2(height - 1) + 20, coor.second + heightgap + 15 };
drawtext(b, &r, DT_CENTER);
line(coor.first + 15, coor.second + 20, coor.first + widthgap * pow2(height - 1) - 15, coor.second + heightgap - 20);
}
print(height - 1, pair<int, int>(coor.first - widthgap * pow2(height - 1), coor.second + heightgap), lson[loc]);//递归打印左子树
print(height - 1, pair<int, int>(coor.first + widthgap * pow2(height - 1), coor.second + heightgap), rson[loc]);//递归打印右子树
}
测试文件:
#include"BinaryTree.h"
#include<windows.h>
#include
#include
void main()
{
int height = 6; //最大树深度
int widthgap = 35; //节点之间的横向的距离
int heightgap = 100; //节点之间纵向的距离
float asp = 0.57; //缩放系数
HWND h = initgraph(asp * widthgap * pow2(height) + 60, asp * heightgap * height * 2);
setaspectratio(asp, asp); //设置缩放系数
setbkcolor(GREEN); //背景颜色绿色
setbkmode(TRANSPARENT); //字体背景透明
cleardevice(); //清屏
settextcolor(WHITE); //字体颜色白色
settextstyle(28, 0, “楷体”);
RBtree t(21); //树最大节点数为20
srand(1000);
for (int i = 0; i < 15; i++)
t.add(rand()%300);
char s[10];
MOUSEMSG msg;
int data;
while(1)
if(MouseHit())
{
msg = GetMouseMsg();
if (msg.mkLButton)//左旋
{
FlushMouseMsgBuffer();
stringstream ss;
InputBox(s, 10, "请输入数据进行左旋:");
string num(s);
ss << num;
ss >> data;
t.Lrotate(t.searchData(data));
}
if (msg.mkRButton)//右旋
{
FlushMouseMsgBuffer();
stringstream ss;
InputBox(s, 10, "请输入数据进行右旋:");
string num(s);
ss << num;
ss >> data;
t.Rrotate(t.searchData(data));
}
if (msg.mkMButton)
{
FlushMouseMsgBuffer();
stringstream ss;
InputBox(s, 10, "请输入数据进行添加:");
string num(s);
ss << num;
ss >> data;
t.add(data);
}
cleardevice();
t.print(height, pair<int, int>(widthgap * pow2(height), 0), 0);
}
system("pause");
}
想问的问题:
case 3:
if (lson[lfather] == floc)//当前节点为左孩子
{
Rrotate(lgrandfather);
flag[floc] = eblack;
flag[lfather] = ered;
flag[lgrandfather] = eblack;
floc = lfather;
break;
}
else //当前节点为右孩子
{
Lrotate(lfather);
floc = lfather;
break;
}
case 4:
if (lson[lfather] == floc)//当前节点为左孩子
{
Rrotate(lfather);
floc = lfather;
break;
}
else //当前节点为右孩子
{
Lrotate(lgrandfather);
flag[floc] = eblack;
flag[lfather] = ered;
flag[lgrandfather] = eblack;
floc = lfather;
break;
}
这段代码对应上文提到的博主的添加操作中的case3,但是我感觉那位博主的操作不太可行,进行了一点修改。那位博主是把父节点作子树根节点之后把原来的子节点和祖父节点改为红色,把原来的父节点改成黑色,我觉得应该是把原来的父节点改成红色,原来的子节点和祖父节点为黑色。
p.s.删除的代码还没写,若那位老哥有需要请回复,我再把删除的代码加上。提醒一下,我参考的那篇博客已经有实现代码了,不过楼主没试过,不知道能不能用。
p.p.s.这是一篇名为原创实为求助的博客,请高人轻喷。