紅黑樹的一個C++實現

本來只是想實現一個紅黑樹,但是在實現過程中發現一個操作和我參考的一篇博客有出入,所以把我實現的紅黑樹放上來,一方面供紅黑樹的初學者參考,更重要的是想請高人指點一下我的疏漏之處。
程序使用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.這是一篇名爲原創實爲求助的博客,請高人輕噴。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章