Data Structure第六次作业讲解

Posted L_RUA

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Data Structure第六次作业讲解相关的知识,希望对你有一定的参考价值。

Data Structure第六次作业讲解

写给读者的话(务必阅读)

期中以来,有不少同学向我反应代码写的慢、正确率不高等问题。由于OS已经爆炸闲的没事干 因此我决定将自己原来写的代码重构重构,并整理成博客附上整个思路的讲解。首先,我必须申明,博客所写的东西,是供想提升自己代码水平,理清写码思路的同学用的。我希望同学们能够明白:作为一个考试分数占 80% 的学科,抄袭他人代码完成作业不是白赚了那 20% 的分数,而是失去了一次良好的练兵的机会(从本次开始,文章中给出的代码均已提交评测,抄袭需谨慎)。其次,个人所写代码只是提供一个写码、思考问题的思路,并不代表题目的唯一解法,更不代表最优解法没有提交到课程网站上测试,只在本地通过测试数据,甚至可能有bug噢。我希望我的代码能够起到抛砖引玉的作用,能够让同学对课上内容有更深刻的理解,写代码时能够有更多更好的想法。最后,我希望同学们在完成作业的同时,能够对自己的代码进行复杂度的分析。数据结构的使用,往往离不开对性能的约束,因此,掌握复杂度的分析也是这门课程重要的一环。

关于代码风格

本文中所有的代码风格皆采取 OO 的标准,同时作者也希望同学们能够以这种标准约束自己,这样也会方便助教 debug。简单来说,大致约束如下:

1、符号后带空格。

2、大括号不换行。

3、if、while、for 等括号两端应该带空格,并且一定要用大括号括起来。

4、一行不要写过多字符(不超过60),较长的判断可以换行处理。

5、缩进为 4 个空格,不同层次间要有合适的缩进。

6、一行只声明一个变量,只执行一个语句。

关于使用到的工具

采取了dhy大佬的意见,决定新添加这个栏目,对本次代码中使用到的基础的一些数据结构或是函数进行一些简单的讲解,便于大家的使用和理解。

1、快速读入

inline int read() { //快速读入,可以放在自己的缺省源里面 
	int x = 0; //数字位 
	int f = 1; //符号位 
	char ch = getchar(); //读入第一个字符 
	while (!isdigit(ch)) { //不是数字 
		if (ch == \'-\') { //特判负号 
			f = -1;
		}
		ch = getchar();
	}
	while (isdigit(ch)) { //读入连续数字 
		x = (x << 3) + (x << 1) + ch - \'0\'; // x * 10 == (x << 3) + (x << 1) 
		ch = getchar();
	}
	return x * f;
}

快速读入是比较好用的一种读入的写法,我这里的实现是通过循环读入直到得到下一个数字,在具体的题目中也可以根据自己的需要对循环的条件和结束条件做更改来读入字符串等。(由于只涉及到简单循环,这里不作更深入的讲解)。切忌不经思考和理解就使用,容易出现读入死循环等问题。

2、链式前向星

在解决需要建边(如:树、图)相关的问题时,比较方便的一种数据结构。在第一道题中用到了类似的结构,因此我们在这里做个讲解。

typedef struct edge {
	int to; //指向这条边到达的对象
	int nxt; //指向当前表头的下一条边,为 0 则代表没有
} Edge;
Edge e[maxn];
int h[maxn];
int cnt;

void adde(int x, int y) { //建一条 x 向 y 的边
	e[++cnt] = (Edge) {y, h[x]}; //产生新的指向 y 的表头,并将 nxt 指向之前的表头
	h[x] = cnt; //更新表头
}

void forEach(int x) {
	int i;
	for (i = h[x]; i; i = e[i].nxt) { //遍历时从表头开始依次访问每个边,取出其指向的点
		int y = e[i].to;
		forEach(y);
	}
}

如此图所示,我们新加入编号为 3 的边

初始状态 e[1] = {2, 0} (前面为to,后面为nxt)

​ e[2] = {3, 1}

​ h[1] = 2

这时我们新建 e[3] = {4, h[1]} 即 {4,2}

再令 h[1] = 3

那么遍历的时候我们可以通过 h[1] 找到 e[3],再通过 e[3].nxt 找到 e[2], 再通过 e[2].nxt 找到 e[1],就获得了完整的边的信息。

第一题:单词查找(查找-基本题)

题目描述

【问题描述】

从标准输入中读入一个英文单词及查找方式,在一个给定的英文常用单词字典文件dictionary3000.txt中查找该单词,返回查找结果(查找到返回1,否则返回0)和查找过程中单词的比较次数。查找前,先将所有字典中单词读入至一个单词表(数组)中,然后按要求进行查找。字典中单词总数不超过3500,单词中的字符都是英文小写字母,并已按字典序排好序(可从课件下载区下载该字典文件)。字典中的单词和待查找单词的字符个数不超过20。

查找方式说明:查找方式以1~4数字表示,每个数字含义如下:

1:在单词表中以顺序查找方式查找,因为单词表已排好序,遇到相同的或第一个比待查找的单词大的单词,就要终止查找;

2:在单词表中以折半查找方式查找;

3:在单词表中通过索引表来获取单词查找范围,并在该查找范围中以折半方式查找。索引表构建方式为:以26个英文字母为头字母的单词在字典中的起始位置和单词个数来构建索引表,如:

字母 起始位置 单词个数
a 0 248
b 248 167

该索引表表明以字母a开头的单词在单词表中的开始下标位置为0,单词个数为248。

4:按下面给定的hash函数为字典中单词构造一个hash表,hash冲突时按字典序依次存放单词。hash查找遇到冲突时,采用链地址法处理,在冲突链表中找到或未找到(遇到第一个比待查找的单词大的单词或链表结束)便结束查找。

/* compute hash value for string */

#define NHASH 3001

#define MULT 37

unsigned int hash(char *str)

{

​ unsigned int h=0;

​ char *p;

​ for(p=str; *p!=\'\\0\'; p++)

​ h = MULT*h + *p;

​ return h % NHASH;

}

提示:hash表可以构建成指针数组,hash冲突的单词形成一有序链表。

【输入形式】

单词字典文件dictionary3000.txt存放在当前目录下,待查找单词和查找方式从标准输入读取。待查找单词只包含英文小写字母,与表示查找方式的整数之间以一个空格分隔。

【输出形式】

将查找结果和单词比较次数输出到标准输出上,两整数之间以一个空格分隔。
【样例输入与输出】
单词字典文件dictionary3000.txt与课件下载中提供的相同,下面两列中,左侧为待查找单词与查找方式,右侧为对应的输出结果:

wins 1 0 3314

wins 2 0 12

wins 3 0 7

wins 4 0 2

yes 1 1 3357

yes 2 1 10

yes 3 1 4

yes 4 1 1
【样例说明】

wins在单词字典中不存在,4种查找方式都输出结果0,顺序查找、折半查找、索引查找和hash查找的单词比较次数分别为:3314、12、7和2次(wins的hash位置与字典中physics和suggest相同)。

yes在单词字典中存在,4种查找方式都输出结果1,顺序查找、折半查找、索引查找和hash查找的单词比较次数分别为:3357、10、4和1。

题目大意

按照题目所给的要求用多种查找方式和hash表来对单词进行查找并且输出查找的次数。

题目思路

我们按照题目的要求来模拟每种查找方式就可以了。

第一种:顺序查找我们直接用数组存储所有的串枚举即可

第二种:二分查找,每次找中间的比对更改上下界即可(读入保证字符串顺序)

第三种:限定区间的二分查找,我们在字母变化的时候预处理区间的范围就可以了

第四种:hash,用链表串起来查找就行

代码实现

#include <stdio.h>
#include <string.h>

#define maxn 3505
#define NHASH 3001
#define MULT 37

typedef struct line {
	char* s;
	int nxt;
} Line;

int h[NHASH];
Line l[maxn];
char s[maxn][25];
int B[255], E[255], cnt;

unsigned int hash(char *str){ //直接用题目给的代码
       unsigned int h=0;
       char *p;
       for(p=str; *p!=\'\\0\'; p++){
           h = MULT*h + *p;
       }
       return h % NHASH;
}

void Push(int nw, char *s) {
	++cnt;
	l[cnt].s = s;
	if (!h[nw]) { //第一个读入的,特判
		h[nw] = cnt;
		return;
	}
	if (strcmp(l[h[nw]].s, s) > 0) { //当前串直接比链表首还大,特判更改 
		l[cnt].nxt = h[nw];
		h[nw] = cnt;
		return;
	}
	int lst, i;
	for (i = h[nw]; i && strcmp(l[i].s, s) < 0; i = l[i].nxt) {//找到第一个小于当前串的位置 
		lst = i; //保存上一个比当前串大的位置。 
	}
	l[cnt].nxt = l[lst].nxt; //接入当前串
	l[lst].nxt = cnt;
}

int Init() { //初始化读入,并作必要的处理。 
	FILE* IN;
	IN = fopen("dictionary3000.txt", "r");
	int t = 0;
	while(fscanf(IN, "%s", s[t]) != EOF) {
		if (s[t][0] != s[t - 1][0]) { //说明首字母出现了变化,我们更改首字母的开始结束 
			int i;
			for (i = s[t - 1][0] + 1; i < s[t][0]; ++i) { //中间的字母没有出现过,特殊处理 
				B[i] = E[i] = t;
			}
			E[s[t - 1][0]] = B[s[t][0]] = t; //更新上一个字母结尾和新字母开始 
		}
		int nw = hash(s[t]); //调用给出函数计算hash值
		Push(nw, s[t]); //放入链表里面进行管理 
		++t;
	}
	--t; //最后读入了 EOF
	int i;
	for (i = \'z\'; i > s[t][0]; --i) {//别忘了剩余没读入的字母 
		B[i] = E[i] = t; 
	}
	return t; //返回读入总数	
}

void Print(int ans, int qcnt) {
	printf("%d %d\\n", ans, qcnt);
}

void query_normal(char* q, int total) { //最简单的顺序查找 
	int ans = 0;
	int qcnt = 0;
	int i;
	for (i = 0; i <= total; ++i) {
		++qcnt;
		if (strcmp(q, s[i]) == 0) { //找到
			ans = 1;
			break;
		} 
		if (strcmp(q, s[i]) < 0) { //不可能找到结束
			break;
		}
	}
	Print(ans, qcnt);
}

void query_div(char* q, int total, int L, int R) {
	int qcnt = 0;
	int ans = 0;
	while (L <= R) { // 标准二分 
		int mid = (L + R) >> 1;
		++qcnt;
		if (strcmp(s[mid], q) == 0) { //找到
			ans = 1;
			break;
		}
		if (strcmp(q, s[mid]) < 0) { //更改上下界
			R = mid - 1;
		} else {
			L = mid + 1;
		}
	}
	Print(ans, qcnt);
}

void query_hash(char* q) {
	int nw = hash(q); //获得hash值,遍历链表
	int ans = 0;
	int qcnt = 0;
	int i;
	for (i = h[nw]; i; i = l[i].nxt) {
		++qcnt;
		int t = strcmp(l[i].s, q);
		if (t == 0) {
			ans = 1;
			break;
		}
		if (t > 0) {
			break;
		}
	}
	Print(ans, qcnt);
}

int main() {
	int total = Init();
	char q[25];
	int ty;
	scanf("%s%d", q, &ty);
	if (ty == 1) {
		query_normal(q, total);
	}
	if (ty == 2) {
		query_div(q, total, 0, total);
	}
	if (ty == 3) {
		query_div(q, total, B[q[0]], E[q[0]] - 1); //上下界为之前预处理的首字母对应的 B 和 E
	}
	if (ty == 4) {
		query_hash(q);
	}
	return 0;
} 

复杂度分析

第一种查询方式复杂度 O(n * |S|)

第二种方式复杂度O(logn * |S|)

第三种方式复杂度O(logt * |S|) // t 代表 max(首字母相同的串的个数)

第四种方式可以根据模数算出平均冲突次数,这里就不作分析了。

第二题:排座位(简)a

题目描述

【问题描述】

某班级要进行期末考试,准备考试时打乱座次,现已按照学号顺序人工为学生随机安排了座位号,但其中可能会出现漏排和重复安排座位的情况。编写程序读入人工安排的考试座位安排表T1,对安排情况进行检查,并对漏排和重复安排座位的情况进行修正,修正后,若学生人数为N,则每位学生考试座位安排应在1~N之间,其中没有缺号和重号。假设T1中学号信息不会出现重复,同一座位号最多有两位同学的座位号相同,并且座位号不会连续漏排;初始考试座位安排表存放在当前目录下的in.txt中,其中包括每位学生的学号、姓名和座位号,要求修正后的考试座位安排表输出到当前目录下的out.txt文件中。程序检查座位号的规则如下:
1、首先对考试座位安排表T1按座位号从小到大的顺序排序(原始考试安排可能有座位号相同情况,座位号相同时则按原始学号顺序排序),得到按座位号排序的安排表T2;

2、对表T2从头开始检查漏排座位号情况:假设当前表中安排的最大座位号为M,取M和N的较小值Q;从1号开始检查,若某个小于等于Q的座位序号没有安排学生,则将表T2的最后学生的座位设置为该座位号;若存在多个漏排座位,则从表T2最后依次向前设置;

3、然后再检查表T2中重排座位号情况:假设当前表中安排的最大座位号为m,将座位号重复的、学号较大的学生的座位号依次设置为m+1、m+2、m+3......;

\\4. 将调整好的表T2按学号由小到大序排序后按输出格式要求输出至指定输出文件中。

【输入形式】

从标准输入中读入学生人数(不超过100的正整数)。

初始考试座位安排表存储在当前目录下的in.txt文件中,已按照学号由小到大的顺序分行存储每位学生座位信息,依次为学生学号(不超过8位的正整数)、姓名(由不超过20位的英文字母组成)和座位号(不超过100的正整数),各数据间以一个空格分隔。最后一个学生座位信息后有回车换行。

【输出形式】

按照学号由小到大的顺序将修正后的考试座位安排表输出到当前目录下的out.txt文件中,每行依次为学号、姓名和座位号,各数据之间以一个空格分隔。

题目大意

按照题目的意思去模拟一个排序过程即可。

题目思路

模拟排序过程,没有什么特殊的思路,活用快排可以很简单地解决这个问题。

需要注意的是,第二部分的 Q 是随着处理的过程动态变化的,只取最开始的值会出问题。

比如下面这个例子:

a 1

b 2

c 2

d 3

e 4

f 4

g 5

h 7

初始的时候,我们不难发现,Q = min(N, M) = 7

然后枚举1到7,在 6 的时候发现空位,把 h 座位改成 6

结果因为 7 的位置被空出来, 7 的时候发现空位,又把 h 座位改成 7,就违背了我们把前面座位排满的意图。

代码实现

#include<stdio.h>
#include<string.h>
#define maxn 1005

typedef struct student{
	int num;
	int pos;
	char name[25];
} Student;

Student stu[maxn];

int n; 

int sort_pos(const void* a, const void *b) {//按照座位排序,座位相同时按学号 
	Student* s1 = (Student*) a;
	Student* s2 = (Student*) b;
	if (s1->pos == s2->pos) {
		return s1->num - s2->num;
	}
	return s1->pos - s2->pos;
}

int sort_num(const void* a, const void* b) {//按照学号排序 
	Student* s1 = (Student*) a;
	Student* s2 = (Student*) b;
	return s1->num - s2->num;
}

int max(int x, int y) { //三目运算符返回最大值 
	return x > y ? x : y;
} 

int min(int x, int y) { //三目运算符返回最小值 
	return x < y ? x : y;
}

int used[maxn]; // 每个座位是否被使用的标记 

int q[maxn]; //存储座位重复的人的编号 
int qcnt;

int solve_empty() { //处理漏排座位 
	int Q = min(n, stu[n - 1].pos);
	int t = n - 1; //当前最末尾的人对应的编号
	int i;
	for (i = 0; i < n; ++i) { //标记已经使用过的座位 
		++used[stu[i].pos];
	} 
	for (i = 1; i <= Q; ++i) {
		if (!used[i]) {
			--used[stu[t].pos];
			stu[t--].pos = i;
			++used[i];
		}
		Q = min(Q, stu[t].pos); //记得动态更新 Q
	}
	int maxUsed = 0;
	for (i = 0; i < n; ++i) {
		used[stu[i].pos] = 0;
		maxUsed = max(maxUsed, stu[i].pos);
	}
	qcnt = 0;
	for (i = 0; i < n; ++i) {
		if (!used[stu[i].pos]) { //第一次使用这个座位
			used[stu[i].pos] = 1;
		} else { //和前面使用座位冲突
			q[qcnt++] = i;
		}
	} 
	return maxUsed;
}

int sort_dup(const void* a, const void* b) {
	int* n1 = (int*) a;
	int* n2 = (int*) b;
	return stu[*n1].pos - stu[*n2].pos;
}

void solve_dup(int maxUsed) { //处理重复座位 
	qsort(q, qcnt, sizeof(int), sort_dup);
	//之前我们处理之后,每个人的座位是乱序的,这里最好重新按座位大小排序 
	//其实不用排序 
	int i = 0;
	for (i = 0; i < qcnt; ++i) {
		stu[q[i]].pos = ++maxUsed;
	}
}

int main(){
	scanf("%d", &n);
	FILE *IN = fopen("in.txt", "r");
	FILE *OUT = fopen("out.txt", "w");
	int i;
	for (i = 0; i < n; ++i) {
		fscanf(IN, "%d%s%d", &stu[i].num, stu[i].name, &stu[i].pos); //读入所有数据 
	}
	qsort(stu, n, sizeof(Student), sort_pos);  //按座位排
	int maxUsed = solve_empty(); //记录当前最大座位编号
	solve_dup(maxUsed);
	qsort(stu, n, sizeof(Student), sort_num); //按学号排
	for(i = 0; i < n; ++i) {
		fprintf(OUT,"%d %s %d\\n", stu[i].num, stu[i].name, stu[i].pos);
	}
	return 0;
}

复杂度分析

由于涉及到排序,复杂度是 O(nlogn * |S|) 的。

第三题:整数排序(排序-基本题)

题目描述

【问题描述】

从标准输入中输入一组互不相同的整数(个数不超过100)及排序方式,按照从小到大排序,输出按某种算法排序的结果及元素的比较次数。

说明:排序方式为一个1~5的整数,分别表示:

1:选择排序,比较次数是指选择未排序部分的最小元素时的比较次数。

2:冒泡排序,比较次数是指相邻元素的比较次数,若某趟排序中没有进行数据交换,就认为排序结束。

3:堆排序,比较次数是指根元素调整过程中根元素与子树根结点的比较次数,即下面算法中红色语句的执行次数:

void adjust(int k[ ],int i,int n)

{

int j,temp;

temp=k[i];

j=2*i+1;

while(j<n){

​ if(j<n-1 && k[j]<k[j+1])

​ j++;

​ if(temp>=k[j])

​ break;

​ k[(j-1)/2]=k[j];

​ j=2*j+1;

}

k[(j-1)/2]=temp;

}

4:二路归并排序,比较次数是指两组有序数据合并成一组时的比较次数,即下面算法中红色语句的执行次数(注意:调用 merge时,要使用上课讲的递归算法):

void merge(int x[ ],int tmp[ ],int left,int leftend,int rightend)

{

int i=left, j=leftend+1, q=left;

while(i<=leftend && j<=rightend)

{

​ if(x[i]<=x[j])

​ tmp[q++]=x[i++];

​ else

​ tmp[q++]=x[j++];

}

while(i<=leftend)

​ tmp[q++]=x[i++];

while(j<=rightend)

​ tmp[q++]=x[j++];

for(i=left; i<=rightend; i++)

​ x[i]=tmp[i];

}

5:快速排序,比较次数是指分界元素与其它元素的比较次数,即下面算法中红色语句的执行次数:

void quickSort(int k[ ],int left,int right)

{

int i, last;

if(left<right){

​ last=left;

​ for(i=left+1;i<=right;i++)

​ if(k[i]<k[left])

​ swap(&k[++last],&k[i]);

​ swap(&k[left],&k[last]);

​ quickSort(k,left,last-1);

​ quickSort(k,last+1,right);

}

}

【输入形式】

首先在屏幕上输入2个整数,分别表示待排序的整数个数及排序方式,然后在下一行依次输入待排序的整数。各整数之间都以一个空格分隔。

【输出形式】

先在一行上输出排序结果,各整数间以一个空格分隔。然后在下一行上输出排序过程中的元素比较次数。

题目大意

与第一题类似,用多种方式进行排序同时统计比较次数。

题目思路

没什么特别的思路,模拟即可,注意在每次数字出现比较的时候给cnt + 1。

代码实现

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#define maxn 105
#define INF 1e9

inline int read() { //快速读入,可以放在自己的缺省源里面 
	int x = 0; //数字位 
	int f = 1; //符号位 
	char ch = getchar(); //读入第一个字符 
	while (!isdigit(ch)) { //不是数字 
		if (ch == \'-\') { //特判负号 
			f = -1;
		}
		ch = getchar();
	}
	while (isdigit(ch)) { //读入连续数字 
		x = (x << 3) + (x << 1) + ch - \'0\'; // x * 10 == (x << 3) + (x << 1) 
		ch = getchar();
	}
	return x * f;
}

int n;
int ty;
int a[maxn];
int used[maxn];

void selectionSort() { //选择排序 
	int i, j;
	int cnt = 0;
	for (i = 1; i <= n; ++i) {
		int MIN = INF;
		int pos;
		for (j = 1; j <= n; ++j) {
			if (!used[j]) { //找还没被选出的最小的 
				++cnt; //比较一次 
				if (a[j] < MIN) {
					MIN = a[j];
					pos = j;
				}
			}
		}
		--cnt; //选中第一个数并不需要比较,次数减一 
		used[pos] = 1;
		printf("%d ", MIN); //直接输出找到的最小值 
	}
	puts("");
	printf("%d", cnt);
} 

void swap(int *a, int *b) { //交换两个数 
	int c;
	c = *a;
	*a = *b;
	*b = c;
} 

void bubbleSort() { //冒泡排序 
	int i;
	int j;
	int cnt = 0;
	for (i = 1; i < n; ++i) {
		int tag = 0;
		for (j = 1; j <= n - i; ++j) {
			++cnt; //比较一次 
			if (a[j] > a[j + 1]) { //冒泡排序前后交换条件 
				swap(&a[j], &a[j + 1]);
				tag = 1;
			}
		}
		if (!tag) { //没有产生交换 
			break;
		}
	}
	for (i = 1; i <= n; ++i) {
		printf("%d ", a[i]);
	}
	puts("");
	printf("%d", cnt);
}

//注意,标算给的是大根堆 

void adjust(int t, int* cnt) { //与自己的两个儿子进行比较进行调整 
	while (1) {
		if ((t << 1) > n) {
			break;
		}
		++(*cnt);
		int p = t << 1;
		if ((t << 1 | 1) <= n && a[p] < a[t << 1 | 1]) { //比较找出左右儿子较大的那个 
			p = t << 1 | 1;
		}
		if (a[t] < a[p]) { //比较儿子和当前点 
			swap(&a[t], &a[p]);
		} else {
			break;
		}
		t = p;
	}
}

void heapSort() { //堆排序 
	int i;
	int cnt = 0;
	for (i = n >> 1; i >= 1; --i) { //自底向上调整堆 
		adjust(i, &cnt);
	}
	int lst = n; //记录原本的个数 
	for (i = n; i >= 1; --i) {
		swap(&a[1], &a[n]); //把最大的换到最后 
		--n;
		adjust(1, &cnt);
	}
	for (i = 1; i <= lst; ++i) {
		printf("%d ", a[i]);
	}
	puts("");
	printf("%d ", cnt);
}

int b[maxn];
void merge(int l, int r, int* cnt) {
	if (l == r) { //相等返回 
		return;
	}
	int mid = (l + r) >> 1;
	merge(l, mid, cnt);
	merge(mid + 1, r, cnt); //先处理两边
	int l1 = l;
	int l2 = mid + 1;
	int nw = l;
	while (l1 <= mid && l2 <= r) { //两端都还有值可用 
		++(*cnt);
		if (a[l1] <= a[l2]) {
			b[nw++] = a[l1++];
		} else {
			b[nw++] = a[l2++];
		}
	} 
	while (l1 <= mid) { //左边未排完 
		b[nw++] = a[l1++]; 
	}
	while (l2 <= r) { //右边未排完 
		b[nw++] = a[l2++];
	}
	int i;
	for (i = l; i <= r; ++i) { //将临时的 b 复制给 a 
		a[i] = b[i];
	} 
}

void mergeSort() { //归并排序 
	int cnt = 0, i;
	merge(1, n, &cnt);
	for (i = 1; i <= n; ++i) {
		printf("%d ", a[i]);
	}
	puts("");
	printf("%d", cnt);
}

void qSort(int l, int r, int* cnt) {
	if (l > r) {
		return;
	}
	int i;
	int lst;
	lst = l; //以 l 来比较大小 
	for (i = l + 1; i <= r; ++i) {
		++(*cnt);
		if (a[i] < a[l]) {
			swap(&a[++lst], &a[i]);
		}
	}
	swap(&a[l], &a[lst]);// 将 l 放在最后一个比它小的后面  
	qSort(l, lst - 1, cnt);
	qSort(lst + 1, r, cnt);
}

void quickSort() { //快速排序 
	int cnt = 0;
	int i;
	qSort(1, n, &cnt);
	for (i = 1; i <= n; ++i) {
		printf("%d ", a[i]);
	}
	puts("");
	printf("%d", cnt);
}

int main() {
	n = read();
	ty = read();
	int i;
	for (i = 1; i <= n; ++i) {
		a[i] = read();
	}
	if (ty == 1) {
		selectionSort(); 
	}
	if (ty == 2) {
		bubbleSort();
	}
	if (ty == 3) {
		heapSort();
	}
	if (ty == 4) {
		mergeSort();
	}
	if (ty == 5) {
		quickSort();
	}
	return 0;
}

复杂度分析

复杂度就是每种排序的复杂度。

摇起来

大巴黎,咚咚咚

以上是关于Data Structure第六次作业讲解的主要内容,如果未能解决你的问题,请参考以下文章

耿丹16-1第六次作业

第六次作业周总结

OOP第四次到第六次作业总结

第六次作业—例行报告

第六次作业psp

软件工程第六次作业 - 每周例行汇报