题目描述
算法描述
(1)函数名:InOrder(BiNode bt)
输入:BiNode bt
功能:为中序遍历的递归遍历部分,对平衡二叉树完成中序遍历
输出:每个结点的信息
(2)函数名:SearchBST(BiNode bt, int k)
输入:BiNode bt, int k
功能:平衡二叉树查找学号为k的函数
输出:如果查找成功就返回结点,否则返回一个空指针
(3)函数名:InsertBST(BiNode &bt, BiNodes x)
输入:BiNode &bt, BiNodes x
功能:向平衡二叉树中插入结点并且在递归回溯时对每个结点进行判断,看是否符合平衡二叉树,如果不符合就当即调用下边的调整函数。实现二叉树的动态平衡
输出:无
(4)函数名:InsertBST(BiNodes x)
输入:BiNode x
功能:此函数为平衡二叉树类的公有属性函数,通过它来访问私有函数
输出:每个结点的信息
(5)函数名:BiSortTree(BiNodes a[ ], int n)
输入:BiNodes a[ ], int n
功能:通过构造函数来完成构建平衡二叉树
输出:无
(6)函数名:DeleteBST(BiNode p)
输入:BiNode p
功能:删除结点p
输出:无
(7)函数名:Release(BiNode bt)
输入:BiNode bt
功能:通过中序遍历递归释放空间,该函数为平衡二叉树的私有属性函数,通过析构函数的调用而调用
输出:无
(8)函数名:GetDepth()
输入:无
功能:通过该函数来访问私有属性的GetDepth(BiNode &bt)函数,显性调用该函数可以得到整个树的深度
输出:返回整个树的深度
(9)函数名:GetDepth(BiNode &bt)
输入:BiNode &bt
功能:通过递归遍历结点的左右子树,直到结点为空
输出:返回以该节点为根节点的子树的最大深度
(10)函数名:SingRotateLeft(BiNode &bt2)
输入:BiNode &bt2
功能:调整二叉排序树,使其平衡因子在-1到1之间这里是RR型调整
输出:无
(11)函数名:SingRotateRight(BiNode &bt2)
输入:BiNode &bt2
功能:调整二叉排序树,使其平衡因子在-1到1之间
这里是LL型调整
输出:无
(12)函数名:DoubleRotateRL(BiNode &bt3)
输入:BiNode &bt3
功能:调整二叉排序树,使其平衡因子在-1到1之间这里是RL型调整
输出:无
(13)函数名:DoubleRotateLR(BiNode &bt3)
输入:BiNode &bt3
功能:调整二叉排序树,使其平衡因子在-1到1之间 这里是LR型调整
输出:无
(14)函数名:Function_One_sequential_search(BiNodes a[],int n,BiNodes k)
输入:BiNodes a[],int n,BiNodes k
功能:在顺序表中查找结点k
输出:如果结点存在就显示查找成功,反之查找失败
(15)函数名:Function_Two_Binary_Search(int low,int high,int k)
输入:int low,int high,int k
功能:二分查找的递归算法,查找学号为k的结点
输出:如果查找到该结点就返回结点下标,反之返回-1,表示查找失败
(16)函数名:find(int x)
输入:int x
功能:1/在构建哈希表时,此函数通过哈希算法可以在数组中 找到目前还没有存入数据的位置
2/在查找时可以通过哈希算法找到对应值在数组中的位置
输出:需要查找的点的下标
(17)函数名:Menu()
输入:无
功能:完成各个实验要求的功能的展示
输出:每个功能对应的输出
(18)函数名:Function_Three_Block_Search(int key,int a[])
输入:int key,int a[]
功能:快查找
输出:查找成功返回其坐标
(19)函数名:DeleteBST(int k)
输入:int k
功能:删除数据外部调用
输出:无
(20)函数名:GetMinpRchild(BiNode bt)
输入:BiNode bt
功能:查找关键码最小的右节点
输出:最小右节点
(21)函数名:GetMaxpLchild(BiNode bt)
输入:BiNode bt
功能:查找关键码最大的左节点
输出:最大左节点
(22)函数名:SetTable()
输入:无
功能:索引表的建立
输出:无
(23)函数名:show(int n)
输入:int n
功能:计算每种查找的平均查找长度
输出:输出计算结果
流程图
实验结果
输入信息
顺序查找
二分查找
平衡二叉排序树查找
平衡二叉树 插入功能
平衡二叉树删除功能
散列表查找
综合分析
代码
/***************************************************************
实验名称:综合查找
实验时间:2020.11.25
****************************************************************/
#include<iostream>
#include<math.h>
#include<windows.h>
#include<algorithm>
using namespace std;
const int MAX = 1e6+10;
const int N = 200003;
int A[N];//分块排序数组
//索引表
typedef struct
{
int key ;//最大关键字
int start ;//块开始下标
int ends ; // 块结束下标
}Node;
typedef struct
{
Node idx[10];//表项
int len;//表长
}TdxTable;
typedef struct biNode//数据元素结构体
{
int data;//学号
string name;//姓名
string Class;//班级
biNode *lchild, *rchild;
bool operator < (const biNode &W) const
{
return data < W.data;
}
}*BiNode,BiNodes;
BiNodes Basicline[MAX];
BiNodes Hashline[MAX];//哈希数组,用于哈希查找
TdxTable table;
/**********************
平衡二叉树类
功能:完成平衡二叉树的插入,删除,遍历还有查找
**********************/
class BiSortTree
{
public:
BiSortTree(BiNodes a[ ], int n); //建立查找集合a[n]的二叉排序树
~ BiSortTree()
{
Release(root); //析构函数,同二叉链表的析构函数
}
void InOrder( )
{
InOrder(root); //中序遍历二叉树
}
bool InsertBST(BiNodes x);
int GetDepth();
bool DeleteBST(int k); //删除f的左孩子p
BiNode SearchBST(int k)
{
return SearchBST(root, k); //查找值为k的结点
}
private:
void Release(BiNode bt);
int GetDepth(BiNode &bt);
bool InsertBST(BiNode &bt, BiNodes x);
BiNode SearchBST(BiNode bt, int k);
void InOrder(BiNode bt); //中序遍历函数调用
BiNode root; //二叉排序树的根指针
//平衡函数
void SingRotateLeft(BiNode &pK2);//LL
void SingRotateRight(BiNode &pK2);//RR
void DoubleRotateLR(BiNode &pK);//LR
void DoubleRotateRL(BiNode &pK);//RL
//删除时用到的函数
BiNode GetMaxpLchild(BiNode bt);
BiNode GetMinpRchild(BiNode bt);
bool DeleteBST(BiNode &bt,int k);
};
/************************
函数名:InOrder(BiNode bt)
输入:BiNode bt
功能:为中序遍历的递归遍历部分,
对平衡二叉树完成中序遍历
输出:每个结点的信息
*************************/
void BiSortTree :: InOrder(BiNode bt)
{
if (bt == nullptr)
return; //递归调用的结束条件
else
{
InOrder(bt->lchild); //前序递归遍历bt的左子树
cout<<"姓名:" << bt->name << endl;
cout<<"班级:" << bt->Class << endl;
cout<<"学号:" << bt->data << endl;
cout << endl;
InOrder(bt->rchild); //前序递归遍历bt的右子树
}
}
/************************
函数名:SearchBST(BiNode bt, int k)
输入:BiNode bt, int k
功能:平衡二叉树查找学号为k的函数
输出:如果查找成功就返回结点,否则返回一个空指针
*************************/
BiNode BiSortTree :: SearchBST(BiNode bt, int k)
{
if (bt == nullptr) return nullptr;
if (bt->data == k) return bt;
else if (bt->data > k) return SearchBST(bt->lchild, k);
else return SearchBST(bt->rchild, k);
}
/********************
最核心的部分,
因为参数是指针的引用,
在每次插入元素过后,
回溯的时候都会对当前结点的左右子树的深度进行判定。
*********************/
/************************
函数名:InsertBST(BiNode &bt, BiNodes x)
输入:BiNode &bt, BiNodes x
功能:向平衡二叉树中插入结点并且在递归回溯时对每个结点进行判断,
看是否符合平衡二叉树,如果不符合就当即调用下边的调整函数。
实现二叉树的动态平衡
输出:无
*************************/
bool BiSortTree::InsertBST(BiNode &bt, BiNodes x)
{
if (bt == nullptr) //找到插入位置
{
BiNodes *s = new BiNodes;
s->data = x.data;
s->Class = x.Class;
s->name = x.name;
s->lchild = nullptr;
s->rchild = nullptr;
bt = s;
return true;
}
if(x.data > bt->data)
{
InsertBST(bt->rchild,x);
if(GetDepth(bt->rchild)-GetDepth(bt->lchild)==2)
if(GetDepth(bt->rchild->lchild)>GetDepth(bt->rchild->rchild))
DoubleRotateRL(bt);
else SingRotateLeft(bt);
}
if(x.data < bt->data)
{
InsertBST(bt->lchild,x);
if(GetDepth(bt->lchild)-GetDepth(bt->rchild)==2)//????
if(GetDepth(bt->lchild->rchild)>GetDepth(bt->lchild->lchild))
DoubleRotateLR(bt);
else SingRotateRight(bt);
}
}
/************************
函数名:InsertBST(BiNodes x)
输入:BiNode x
功能:此函数为平衡二叉树类的公有属性函数,通过它来访问私有函数
输出:每个结点的信息
*************************/
bool BiSortTree::InsertBST(BiNodes x)
{
if(InsertBST(root,x))return true;
return false;
}
/************************
函数名:BiSortTree(BiNodes a[ ], int n)
输入:BiNodes a[ ], int n
功能:通过构造函数来完成构建平衡二叉树
输出:无
*************************/
BiSortTree::BiSortTree(BiNodes a[ ], int n)
{
root = nullptr;
for (int i = 0; i < n; i++)
InsertBST(root, a[i]);
}
/************************
函数名:GetMaxpLchild(BiNode bt)
输入:BiNode bt
功能:查找关键码最大的左节点
输出:最大左节点
*************************/
BiNode BiSortTree::GetMaxpLchild(BiNode bt)
{
while(bt->rchild)
{
bt=bt->rchild;
}
return bt;
}
/************************
函数名:GetMinpRchild(BiNode bt)
输入:BiNode bt
功能:查找关键码最小的右节点
输出:最小右节点
*************************/
BiNode BiSortTree::GetMinpRchild(BiNode bt)
{
while(bt->lchild) bt = bt->lchild;
return bt;
}
/************************
函数名:DeleteBST(int k)
输入:int k
功能:删除数据外部调用
输出:无
*************************/
bool BiSortTree::DeleteBST(int k )
{
if(!DeleteBST(root,k))
{
return false;
}
return true;
}
/************************
函数名:DeleteBST(BiNode &bt, int k)
输入:BiNode &bt, int k
功能:删除学号为k的结点
输出:1表示删除成功,0表示删除失败
*************************/
bool BiSortTree::DeleteBST(BiNode &bt, int k)
{
if(bt==nullptr) return false;
if(k==bt->data){
if(!bt->lchild&&!bt->rchild)
{
delete bt;
bt = nullptr;
}
else if(bt->lchild){
BiNode pMax = GetMaxpLchild(bt->lchild);
bt->data = pMax->data;
bt->Class = pMax->Class;
bt->name = pMax->name;
DeleteBST(bt->lchild,pMax->data);
if(GetDepth(bt->lchild)-GetDepth(bt->rchild)==2){
if(GetDepth(bt->lchild->rchild)>GetDepth(bt->lchild->lchild))
{
DoubleRotateLR(bt);
}
else
{
SingRotateRight(bt);
}
}
}
else if(bt->rchild)
{
BiNode pMin = GetMinpRchild(bt->rchild);
bt->data = pMin->data;
bt->Class = pMin->Class;
bt->name = pMin->name;
DeleteBST(bt->rchild,pMin->data);
if(GetDepth(bt->rchild)-GetDepth(bt->lchild)==2)
{
if(GetDepth(bt->rchild->lchild)>GetDepth(bt->rchild->rchild))
{
DoubleRotateRL(bt);
}
else SingRotateLeft(bt);
}
}
}
else if(bt->data>k) DeleteBST(bt->lchild,k);
else if(bt->data<k) DeleteBST(bt->rchild,k);
return true;
}
/************************
函数名:Release(BiNode bt)
输入:BiNode bt
功能:通过中序遍历递归释放空间,
该函数为平衡二叉树的私有属性函数,
通过析构函数的调用而调用
输出:无
*************************/
void BiSortTree :: Release(BiNode bt)
{
if (bt == nullptr)
return;
else
{
Release(bt->lchild); //释放左子树
Release(bt->rchild); //释放右子树
delete bt; //释放根结点
}
}
/************************
函数名:GetDepth()
输入:无
功能:通过该函数来访问私有属性的GetDepth(BiNode &bt)
函数,显性调用该函数可以得到整个树的深度
输出:返回整个树的深度
*************************/
int BiSortTree::GetDepth()
{
int nMax = GetDepth(root);
return nMax;
}
/************************
函数名:GetDepth(BiNode &bt)
输入:BiNode &bt
功能:通过递归遍历结点的左右子树,直到结点为空
输出:返回以该节点为根节点的子树的最大深度
*************************/
int BiSortTree::GetDepth(BiNode &bt)
{
if(nullptr == bt) return 0;
int nL = GetDepth(bt->lchild);
int nR = GetDepth(bt->rchild);
int nMax = nL > nR ? nL : nR;
nMax += 1;
return nMax;
}
/************************
函数名:SingRotateLeft(BiNode &bt2)
输入:BiNode &bt2
功能:调整二叉排序树,使其平衡因子在-1到1之间
这里是RR型调整
输出:无
*************************/
void BiSortTree::SingRotateLeft(BiNode &bt2)
{
BiNode bt1 = bt2 -> rchild;
bt2 -> rchild = bt1->lchild;
bt1 -> lchild = bt2;
bt2 = bt1;
}
/************************
函数名:SingRotateRight(BiNode &bt2)
输入:BiNode &bt2
功能:调整二叉排序树,使其平衡因子在-1到1之间
这里是LL型调整
输出:无
*************************/
void BiSortTree::SingRotateRight(BiNode &bt2)
{
BiNode bt1 = bt2 -> lchild;
bt2 -> lchild = bt1->rchild;
bt1 -> rchild = bt2;
bt2 = bt1;
}
/************************
函数名:DoubleRotateRL(BiNode &bt3)
输入:BiNode &bt3
功能:调整二叉排序树,使其平衡因子在-1到1之间
这里是RL型调整
输出:无
*************************/
void BiSortTree::DoubleRotateRL(BiNode &bt3)
{
SingRotateRight(bt3 -> rchild);
SingRotateLeft(bt3);
}
/************************
函数名:DoubleRotateLR(BiNode &bt3)
输入:BiNode &bt3
功能:调整二叉排序树,使其平衡因子在-1到1之间
这里是LR型调整
输出:无
*************************/
void BiSortTree::DoubleRotateLR(BiNode &bt3)
{
SingRotateLeft(bt3->lchild);
SingRotateRight(bt3);
}
/************************
函数名:Function_One_sequential_search(BiNodes a[],int n,BiNodes k)
输入:BiNodes a[],int n,BiNodes k
功能:在顺序表中查找结点k
输出:如果结点存在就显示查找成功,反之查找失败
*************************/
void Function_One_sequential_search(BiNodes a[],int n,BiNodes k)//顺序表
{
cout << "现在展示的是顺序查找" << endl;
bool it = true;
for(int i = 0; i < n; i ++ )
{
cout <<"正在调用数据库第"<<i+1 <<"个数据" <<endl;
cout <<"学号为 " << Basicline[i].data <<endl;
cout <<"姓名为 " <<Basicline[i].name << endl;
cout << "班级为 " <<Basicline[i].Class << endl;
if(Basicline[i].data == k.data)
{
cout << "学号匹配成功" << endl;
it = false;
break;
}
else cout << "不匹配" <<endl;
system("pause");
system("cls");
}
if(it) cout << "数据库中不存在该同学" <<endl;
cout << "查找完毕" <<endl;
system("pause");
system("cls");
}
/************************
函数名:Function_Two_Binary_Search(int low,int high,int k)
输入:int low,int high,int k
功能:二分查找的递归算法,查找学号为k的结点
输出:如果查找到该结点就返回结点下标,反之返回-1,表示查找失败
*************************/
int Function_Two_Binary_Search(int low,int high,int k)//二分查找
{
if(low > high)
{
return -1;
}
else
{
int mid = (low + high)/2;
if(k < Basicline[mid].data)
{
cout << Basicline[mid].name << "的学号比待查找同学的学号大" << endl;
return Function_Two_Binary_Search( low,mid - 1, k);
}
else if(k > Basicline[mid].data)
{
cout << Basicline[mid].name << "的学号比待查找同学的学号小" << endl;
return Function_Two_Binary_Search( mid + 1,high, k);
}
else
{
return mid;
}
}
}
/************************
函数名:Function_Three_Block_Search(int key,int a[])
输入:int key,int a[]
功能:快查找
输出:查找成功返回其坐标
*************************/
int Function_Three_Block_Search(int key,int a[])//块查找
{
int low,high,mid;
low = 1;
high = table.len;
while(low <= high)
{
mid = (low + high) / 2;
if(key <= table.idx[mid].key)
{
if(key <= table.idx[mid-1].key)
{
high = mid - 1;
}
else
{
for(int i = table.idx[mid].start;i <= table.idx[mid].ends;i ++ )
{
if(key == a[i])
{
return i + 1;
}
}
return 0;
}
}
else
{
low = mid + 1;
}
}
return 0;
}
/************************
函数名:SetTable()
输入:无
功能:索引表的建立
输出:无
*************************/
void SetTable()
{
table.idx[1].key = 2019022; table.idx[1].start = 0; table.idx[1].ends = 5;
table.idx[2].key = 2019048; table.idx[2].start = 6; table.idx[2].ends = 11;
table.idx[3].key = 2019086; table.idx[3].start = 12; table.idx[3].ends = 17;
table.len = 3;
}
/************************
函数名:show(int n)
输入:int n
功能:计算每种查找的平均查找长度
输出:输出计算结果
*************************/
void show(int n)
{
cout << "顺序查找的平均查找长度为:" << (double)(n+1)/2.0 << endl;
cout << "折半查找的平均查找长度为:" << log(n+1)/log(2) - 1 <<endl;
cout << "分块查找的平均查找长度为:" << 0.5*(n/5.0 + 5) + 1 << endl;
cout << "平衡二叉树的平均查找长度为:" << 1.44*(log(n+2)/log(2))-1.328<<endl;
cout << "哈希查找的平均查找长度为:"<< (1+1/(1-(double)n/(double)N))*0.5 << endl;
}
/************************
函数名:find(int x)
输入:int x
功能:1/在构建哈希表时,此函数通过哈希算法可以在数组中
找到目前还没有存入数据的位置
2/在查找时可以通过哈希算法找到对应值在数组中的位置
输出:需要查找的点的下标
*************************/
int find(int x)
{
int t = (x % N + N) % N;
while (Hashline[t].data != 0 && Hashline[t].data != x)
{
t ++ ;
if (t == N) t = 0;
}
return t;
}
/************************
函数名:Menu()
输入:无
功能:完成各个实验要求的功能的展示
输出:每个功能对应的输出
*************************/
void Menu()//消息循环函数
{
cout <<"欢迎来到学生信息构建程序" << endl;
cout << "请输入数据数量" << endl;
string s;
cin >> s;
int n = 0;
for(int i = s.size() - 1; i >= 0; i -- )
{
if(s[i]>'9'||s[i]<'0')
{
cout << "输入数据中存在:"<< s[i] <<" 字符,输入数据应为纯数字,被迫退出程序" <<endl;
exit(1);
}
else
n+=(int)(s[i]-'0')*pow(10,s.size()-i-1);
}
if(n > MAX )
{
cout << "数据超过电话簿容量,按照电话簿最大容量计算" << endl;
n = MAX - 10;
}
for(int i = 0; i < n ; i ++ )
{
cout << "请以此输入学号,姓名,班级" <<endl;
cout << "学号:" <<endl;
cin >> Basicline[i].data;
A[i] = Basicline[i].data;
cout << "姓名:" <<endl;
cin >> Basicline[i].name;
cout << "班级:" << endl;
cin >> Basicline[i].Class;
Hashline[find(Basicline[i].data)] = Basicline[i];
}
cout << "信息录入完成" <<endl;
BiSortTree B{Basicline,n};
system("pause");
system("cls");
cout << "开始功能展示" << endl;
BiNodes k1 ;
cout << "请输入需要查找的信息" << endl;
cout << "请输入待查学号" <<endl;
cin >> k1.data;
Function_One_sequential_search(Basicline,n,k1);
cout << "现在展示的是块查找" << endl;
void SetTable();
int wt = Function_Three_Block_Search(k1.data,A);
cout << "姓名为:" << Basicline[wt].name << endl;
cout << "班级为:" << Basicline[wt].Class <<endl;
system("pause");
system("cls");
sort(Basicline,Basicline+n);
cout << "现在展示的是二分查找" << endl;
int t = Function_Two_Binary_Search(0,n-1,k1.data);
if(t==-1)cout << "查找失败" << endl;
else
{
cout << "查找成功" <<endl;
cout << "姓名是:"<<Basicline[t].name << endl;
cout << "班级是:"<<Basicline[t].Class <<endl;
}
system("pause");
system("cls");
cout << "现在展示的是平衡二叉排序树" << endl;
cout << "中序遍历:"<< endl;
B.InOrder();
system("pause");
system("cls");
cout << "平衡二叉树的查找功能" << endl;
BiNode tt;
tt = B.SearchBST(k1.data);
if(tt==nullptr) cout << "查找失败" << endl;
else
{
cout <<"查找成功" << endl;
cout << "姓名是: " << tt->name <<endl;
cout << "班级是: " << tt->Class <<endl;
cout << "学号是: " << tt->data <<endl;
}
system("pause");
system("cls");
cout << "平衡二叉树的插入功能" << endl;
BiNodes k;
cout << "输入姓名" <<endl;
cin >> k.name;
cout << "输入班级" << endl;
cin >> k.Class;
cout << "输入学号" << endl;
cin >> k.data;
if(B.InsertBST(k))cout << "插入成功" <<endl;
//else cout << "插入失败" << endl;
B.InOrder();
system("pause");
system("cls");
cout << "平衡二叉树的删除功能" << endl;
int y;
cout <<"输入想要删除的学生的学号"<< endl;
cin >> y ;
B.DeleteBST(y);
B.InOrder();
system("pause");
system("cls");
cout << "散列表的查找" << endl;
cout << "输入待查找的学号" << endl;
cin >> y ;
int y1 = find(y);
if(Hashline[y1].data==0)cout <<"查找失败" <<endl;
else
{
cout << "查找成功" <<endl;
cout << "姓名是:"<<Hashline[y1].name << endl;
cout << "班级是:"<<Hashline[y1].Class <<endl;
}
system("pause");
system("cls");
cout << "现在展示的是上述各类查找方法的平均查找长度" <<endl;
show(n);
cout <<"展示完成" <<endl;
}
int main( )
{
Menu();
return 0;
}