目录
1、问题定义
1、实现基于二叉排序树的查找。根据提示输入参赛队编号,若查找成功,输出该赛事类别对应的基本信息(参赛作品名称、参赛学校、赛事类别、参赛者和指导老师信息),同时,输出查找成功时的平均查找长度ASL;否则,输出“查找失败!”。请输出ASL的计算表达式和结果值。
2、能够提供按参赛学校查询参赛团队,根据提示输入参赛学校名称,若查找成功,输出该学校参赛的所有团队的基本信息,输出的参赛团队需有序输出(按参赛队编号)。(排序算法可从选择排序、插入排序、希尔排序、归并排序、堆排序中任意选择,并为选择算法的原因做出说明。)
2、问题分析
2.1问题1算法分析
问题1是一个对二叉排序树查找的问题,主要内容是构建二叉排序树,然后进行对参赛队伍编号的查找,最后输出查找成功时的平均查找长度ASL及其表达式。所以本题使用的方法是对二叉树的基本操作。
在构建二叉排序树时,选择以什么作为关键字很重要,本次我选用参赛队伍编号为关键字,若二叉排序树为空时,则插入的结点为根结点,否则就根据插入结点的关键字与根结点的关键字的值比较结果确定继续是在左子树上还是在右子树上找插入位置。在二叉排序树中插入的每个结点都代表一个队伍,通过对结点信息的读取就可获取参赛队伍的基本信息。
在进行查找操作时,将给定的关键字与二叉排序树的根结点记录的关键字进行比较,若相等则查找成功,输出该赛事类别对应的基本信息;若较小,则在根结点的左子树上继续查找;若较大,则在根结点的右子树上继续查找;直到遇到空结点时,查找失败。二叉排序树的查找性能在O(log2n)和O(n)之间。
当查找成功时,遍历所有的队伍,返回所有队伍在二叉排序树上的深度,通过返回的深度计算平均查找长度ASL。计算ASL算法的查找性能与查找队伍编号一致,都是在O(log2n)和O(n)之间。
问题2算法分析
任务要求实现对参赛学校的参赛团队的输出,由于每一个学校可能参赛的队伍不止一个,因此采用对线性表按值查找算法,通过输入的参赛学校,遍历数组,查找该学校参赛的所有团队,并输出其基本信息。在输出过程中需要有序输出,这里应用到数据结构中的排序算法。
根据数据结构课程所学知识,有多种经典算法可以解决排序问题,包括选择排序、插入排序、希尔排序、归并排序、堆排序等。不同的算法有不同的算法复杂度,而且每个算法的稳定情况也是不同的,考虑到搜索出来的参赛队伍是比较零散的,因此有些算法使用起来会比较麻烦,但是算法均可以进行排序操作。
而归并排序是借助于“归并”技术来进行排序的一种方法,即将若干个已排序的子序列合并成一个有序的序列。归并排序的最好、最坏和平均情况下的时间复杂度均为O(nlog2n),归并排序算法既适合于内排序,也适合于外排序,而且归并排序是一个稳定的排序算法,所以这个项目我采用归并排序来实现对参赛团队的排序。
3、概要设计
1、二叉树结构体定义
struct BTree {
//关键字值
int number;
//存储队伍基本信息
Team* t;
//结点的左右孩子指针
BTree* lchild, * rchild;
};
2、构建二叉排序树
//二叉树插入结点
BTree* insertBST(BTree* root, Team* team) {
if (root == NULL) { //当根结点为空时
BTree* root1 = new BTree();
root1->number = team->number;
root1->t = team;
root1->lchild = NULL;
root1->rchild = NULL;
return root1;
}
if (root->number < team->number) { //当根结点的大小小于插入结点的大小
root->rchild = insertBST(root->rchild, team);
}
else if (root->number > team->number){
root->lchild = insertBST(root->lchild, team);
}
return root;
}
3、按参赛队伍编号查找
//按编号搜索
BTree* Sreachnum(BTree* root, int number,int depth) {
if (root == NULL)return NULL;
if (root->number == number) {
return root;
}
if (root->number < number) {
return Sreachnum(root->rchild, number,depth+1);
}
else return Sreachnum(root->lchild, number,depth+1);
if (root->number != number)return NULL;
}
4、计算ASL
//返回编号的深度,用来计算ASL
int countASL(BTree* root, int number, int depth) {
if (root == NULL)return 0;
if (root->number == number) {
return depth;
}
if (root->number < number) {
return countASL(root->rchild, number, depth + 1);
}
else return countASL(root->lchild, number, depth + 1);
if (root->number != number)return 0;
}
5、按参赛学校查找参赛队伍
//按学校搜索
void Searchsch(string school) {
int j = 0;
for (int i = 0; i < Max; i++) {
if (teams[i].school == school) {
s[j] = teams[i];
j++;
}
}
//归并排序
mergesort(0, j-1);
for (int i = 0; i < j; i++)
cout << s[i].number <<'\t'<<s[i].offering <<'\t' << s[i].category <<'\t' << s[i].name <<'\t' << s[i].teacher <<'\n';
}
6、归并算法
//将相邻两个归并段合并成一个有序段的算法
void merge(int low, int mid, int high){
int i = low, j = mid + 1, k = low;
while (i <= mid && j <= high){
if (s[i].number < s[j].number)
s1[k++] = s[i++];
else
s1[k++] = s[j++];
}
while (i <= mid)
s1[k++] = s[i++];
while (j <= high)
s1[k++] = s[j++];
for (int i = low; i <= high; i++)
s[i] = s1[i];
}
//归并排序算法总体部分
void mergesort(int x, int y){
if (x >= y) return;
int mid = (x + y) / 2;
mergesort(x, mid);
mergesort(mid + 1, y);
merge(x, mid, y);
}
在主函数中通过递归返回的结点的深度计算ASL数值
cout << "输入要查找的参赛队编号:";
int number1;
cin >> number1;
BTree* s = new BTree();
s = Sreachnum(root, number1, 1); //按编号查找
if (s != NULL) {
cout << "参赛作品名称:" << s->t->offering << '\t' << "参赛学校:" << s->t->school
<< '\t' << "赛事类型:" << s->t->category << '\t' << "参赛者:"
<< s->t->name << '\t' << "指导老师:" << s->t->teacher << endl;
double s1 = 0;
cout << "ASL=(";
for (int i = 0; i < Count; i++) {
int s2;
s2 = countASL(root, teams[i].number, 1);
s1 += s2;
if (i == Count - 1)cout << s2 << ")*1/" << Count << " = ";
else cout << s2 << "+";
}
ASL = s1 / Count;
cout << ASL << '\n';
}
else cout << "查找失败!" << '\n';