红黑树、二叉搜索树的实现和性能比较
问题描述: 实现红黑树、二叉搜索树相关算法:插入(红黑树涉及树的调整:左旋、右旋等),删除,搜索(指定Key值节点)。
另外,红黑树实现计算树黑高的算法。
实验要求:
1).插入测试,输入 8,11,17,15,6,1,22,25,27,建立红黑树,按照红黑树信息输出方式 输出整棵红黑树以及黑高。
2).删除测试,删除1)中红黑树中Key=15的节点,按照 红黑树信息输出方式 输出调整后的整棵红黑树以及黑高。
3).随机产生300,000个不同自然数Key值(1-300,000,每个数出现一次,出现顺序随机),建立红黑树,查找Key=15000的节点,输出查找花费时间。
用上面的数据,建立二叉搜索树,查找Key=15000的节点,输出查找花费时间。
4). 重复3-5次3)中操作,求各自平均时间。
5). 在1)-4)的红黑树算法基础上修改完成P307 14.1-4算法 OS_Key_Rank(T,k). 输入 1,2,3,4,5,6,7,8 建树, k=6, 输出OS_Key_Rank的返回值。
文档要点:总结红黑树和二叉搜索树在查找上的性能分析,描述此类算法的应用。
三、实验过程及程序运行结果分析
1.插入8,11,17,15,6,1,22,25,27,建立红黑树,按照 红黑树信息输出方式输出的红黑树的形状如下图所示,红黑树的黑高度为:2
2. 删除1)中红黑树中Key=15的节点,按照红黑树信息输出方式输出调整后的整棵红黑树如下图所示,黑高度仍为2。
3. 随机产生300,000个不同自然数Key值(1-300,000,每个数出现一次,出现顺序随机),建立红黑树,查找Key=15000的节点,输出查找花费时间,下图为红黑树查找节点所花费的时间,由于红黑树查找节点的时间复杂度为红黑树的高,而红黑树的高不超过2lg(n+1),所以搜索时间非常短。
程序中先后5次建立红黑树和二叉查找树,计算每次的搜索时间,并且分别打印红黑树的黑高度和二叉查找树的高度。最后打印出5次查找的平均时间,结果显示红黑树的查找性能要优于二叉查找树。
程序运行结果如下图所示:每次建立的红黑树黑高度都为12,而二叉查找树的高度不稳定,每次都不一样
4. 建立OS_RBTree树,完成OS_Key_Rank(T,k).算法,下图为输入1,2,3,4,5,6,7,8 建树所建立的带size域的红黑树,当 k=6时, OS_Key_Rank的返回值为6,程序结果如下图所示:
四、实验总结
由于二叉树对某个元素的搜索是与该元素的距离树根结点的高度来决定的,而红黑树的高度不会超过2lg(n+1),因此可以在O(logn)时间内做查找,插入和删除,时间非常快,而二叉查找树通常情况不是一个平衡的二叉树,最坏情况下,树的高度可以达到n,因此查找的时间为O(n)。
如果在实际应用中,遇到了对时间性能要求非常高的查找时,这时候可以考虑运用红黑树,比如Linux内核管理中的虚拟存储器的管理,STL的中map和set等都是用红黑树实现的。
附录:c++源码实现
其中test.txt中的内容是一串数字:8 11 17 15 6 1 22 25 27
main.cpp
#include <iostream>
#include <windows.h>
#include "RedBlackFinal.h"
#include "BSTree.h"
#include "Function.h"
#include "OS_RBTree.h"
using namespace std;
int main()
{
RBTree<int> rbtree;
const string fileName = "test.txt";
rbtree.BuildTree(fileName);
rbtree.PrintFormat(rbtree.GetRoot(),0);
cout << endl << "The black height of this RBTree is " << rbtree.GetBlackHeight() << endl << endl;
rbtree.Delete(15);
cout << "delete the node whose value is 15:" << endl;
rbtree.PrintFormat(rbtree.GetRoot(),0);
cout << endl << "The black height of this RBTree is " << rbtree.GetBlackHeight() << endl << endl;
const int TIMES = 5;
RBTree<int> tree1[TIMES]; //红黑树
BSTree<int> tree2[TIMES]; //二叉搜索树
LARGE_INTEGER litmp;
LONGLONG start=0,end=0;
double dfMinus, dfFreq, dfTim;
QueryPerformanceFrequency(&litmp);
dfFreq = (double)litmp.QuadPart;// 获得计数器的时钟频率
srand((unsigned)time(0));
double sumTime1,sumTime2;
sumTime1 = sumTime2 = 0.0;
const string name = "data.txt";
int key = 15000;
for(int i=0; i<TIMES; ++i)
{
BuildRandFile(name); //生成300000个随机数,保存到文件中
tree1[i].BuildTree(name);
tree2[i].BuildTree(name);
QueryPerformanceCounter(&litmp);
start = litmp.QuadPart; // 获得初始值
tree1[i].IsGetNode(key); //查找键值为Key的节点
QueryPerformanceCounter(&litmp);
end = litmp.QuadPart; //获得中止值
dfMinus = (double)(end-start);
dfTim = dfMinus / dfFreq; // 获得对应的时间为秒
sumTime1 += dfTim * 1000;
cout << "The black height of this RBTree[" << i << "] is " << tree1[i].GetBlackHeight() << endl << endl;
QueryPerformanceCounter(&litmp);
start = litmp.QuadPart; // 获得初始值
tree2[i].IsGetNode(key); //查找键值为Key的节点
QueryPerformanceCounter(&litmp);
end = litmp.QuadPart; //获得中止值
dfMinus = (double)(end-start);
dfTim = dfMinus / dfFreq; // 获得对应的时间为秒
sumTime2 += dfTim * 1000;
cout << "The black height of this BSTree[" << i << "] is " << tree2[i].GetHeight() << endl << endl;
}
cout << "The average of search time of RBTree is " << sumTime1 / TIMES << "ms" << endl;
cout << "The average of search time of BSTree is " << sumTime2 / TIMES << "ms" << endl;
cout << endl;
OS_RBTree<int> osTree;
for(int i=1;i<=8;++i)
osTree.Insert(i);
osTree.PrintFormat(osTree.GetRoot(),0);
cout << endl;
cout << "the rank value is " << osTree.OS_Key_Rank(6) << endl;
return 0;
}
RedBlack.h
#ifndef REDBLACKFINAL_H
#define REDBLACKFINAL_H
#include <iostream>
#include <stack>
#include <fstream>
#include <string>
using std::string;
using std::cin;
using std::cout;
using std::endl;
using std::stack;
using std::ifstream;
using std::ofstream;
template <typename KEY>
class RBTree
{
class Node ; //节点定义
public:
RBTree();
~RBTree();
void Insert(KEY key);
void Delete(KEY key);
void InOrder();
void PrintFormat(Node*,int);
void BuildTree(const string &name);
int GetBlackHeight();
ifstream& input(ifstream&);
Node* GetRoot()
{
return root;
}
inline Node* GetNode(KEY key)
{
return FindKey(key);
}
inline bool IsGetNode(KEY key);
bool Empty()
{
return root == nullNode;
}
private:
enum NodeColor {RED,BLACK}; //节点颜色,枚举类型
Node *root,*nullNode;
void LeftRotate(Node *node); //左旋
void RightRotate(Node *node); //右旋
void InsertFixup(Node *node);