猪脚说第十五期

猪脚说第十五期

Diandian funny boy

查找与排序的算法很多,知识点比较多比较杂,第六次作业的编程题旨在考察大家对于不同算法的理解,并且感受不同算法的效率,总体来说是比较有趣的。在期末考试的选填中考察也比较多,希望同学们能够多花时间理解一下课件中每一种方法。

第六次作业编程题解

单词查找(查找-基本题)

这道题大家最容易出错的点在于hash查找的实现,值得注意的是题目中明确说明了**hash冲突的单词形成一有序链表**,因此这种方式中其实包含了链表的相关操作(如创建节点、查找等)。在和同学们交流的过程中,我们发现部分同学对于链表的操作已基本遗忘,在此还是建议大家复习一下,毕竟树与图的操作中也包含了不少链表的操作。

另外,有些同学把输入文件名写错了,这个是最亏的错误(太耽搁debug时间了),也在此希望同学们在考试时看清楚输入输出文件名。

最让猪脚气愤的是,强调过很多遍的\r\n问题,很多同学还是不引起重视。非常多的同学使用fgets函数读入单词,结果只把字符串的最末一位置为\0,因此所有单词都会在原本的基础上多一个\r,因此当执行strcmp("wins","wins\r")自然会出问题,无论如何也查找不到。建议就是,如果大家不能保证自己对于换行符的处理完全没有问题,那请直接使用在读入时就会自动去掉换行符的函数(如fscanf等)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXSIZE 21
#define NHASH 3001
#define MULT 37
typedef struct Node{
char inword[MAXSIZE];
struct Node *next;
}Fourth, *Fourthptr;
char word[450000][MAXSIZE];
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 order_search(char word[][MAXSIZE], char keyword[], int word_num){
int i, judge=0;
for(i=0;i<word_num;i++){
if(strcmp(keyword,word[i])==0){
printf("1 %d\n", i+1);
judge=1;
break;
}
else if(strcmp(keyword,word[i])<0)
break;
}
if(judge==0){
if(i<word_num)
printf("0 %d\n", i+1); // 注意break后i不会++,因此实际比较次数为i+1
else
printf("0 %d\n", word_num);
}
} // 还记得二维数组怎么进行形参传递吗
void bin_search(char word[][MAXSIZE], char keyword[], int word_num){
int count=0, low=0, high=word_num, judge=0, mid;
while(low<=high){
count++;
mid = (low+high)/2;
if(strcmp(keyword,word[mid])==0){
printf("1 %d\n", count);
judge=1;
break;
}
else if(strcmp(keyword,word[mid])>0)
low = mid + 1;
else
high = mid - 1;
}
if(judge==0){
printf("0 %d\n", count);
}
}
void index_search(char word[][MAXSIZE], char keyword[], int wordlist[]){
int ptr = keyword[0] - 'a';
int count=0, judge=0, low = wordlist[ptr], high = wordlist[ptr+1]-1, mid;
while(low<=high){
count++;
mid = (low+high)/2;
if(strcmp(keyword,word[mid])==0){
printf("1 %d\n", count);
judge=1;
break;
}
else if(strcmp(keyword,word[mid])>0)
low = mid + 1;
else
high = mid - 1;
}
if(judge==0){
printf("0 %d\n", count);
}
}
void search_in_hash(Fourthptr head, char a[]){
int count=0, judge=0;
Fourthptr p;
for(p=head;p!=NULL;p=p->next){
count++;
if(strcmp(p->inword,a)==0){
printf("1 %d\n", count);
judge=1;
break;
}
else if(strcmp(p->inword,a)>0)
break;
}
if(judge==0){
printf("0 %d\n", count);
}
}
Fourthptr insert_in_hash(Fourthptr head, char a[]){
Fourthptr p, q=head, r;
r = (Fourthptr)malloc(sizeof(Fourth));
strcpy(r->inword,a);
r->next=NULL;
for(p=head;p!=NULL&&(strcmp(p->inword,a)<0);q=p,p=p->next);
if(p==head){
r->next=head;
head=r;
}
else{
q->next=r;
r->next=p;
}
return head;
}
void hash_search(char word[][MAXSIZE], char keyword[], int word_num){
int i, address;
Fourthptr list[NHASH];
for(i=0;i<NHASH;i++)
list[i]=NULL;
for(i=0;i<word_num;i++){
address = hash(word[i]);
list[address] = insert_in_hash(list[address], word[i]);
}
search_in_hash(list[hash(keyword)], keyword);
}
int main() {
FILE *in;
int i=0, op, word_num, wordlist[27]={0};
char pos, keyword[MAXSIZE]={0};
in = fopen("dictionary3000.txt","r");
while((fscanf(in,"%s",word[i]))!=EOF){
pos = 'a';
while(*word[i]>=pos){
pos++;
}
i++;
wordlist[pos-'a'] = i;
} // 请直接使用fscanf函数,在读入的时候去掉换行符,且索引表可以在读入的时候同步建立
word_num=i-1;
scanf("%s %d", keyword, &op);
switch(op){
case 1:
order_search(word, keyword, word_num);
break;
case 2:
bin_search(word, keyword, word_num);
break;
case 3:
index_search(word, keyword, wordlist);
break;
case 4:
hash_search(word, keyword, word_num);
break;
} // 将各函数写好后,在main函数中根据逻辑调用即可
return 0;
}

排座位(简)

这道题大家有问题普遍都在第五个数据点。注意题目中MN的关系,有可能M是会小于N的,因此对于题目中的操作说明一定要仔细阅读,并结合样例说明进行理解,不要在某些地方进行一些“自以为”的操作。最后,该题总共进行了两次大排序,两次排序的关键字是不一样的。

另外也有一个该题表述不那么清楚的地方,即第二个步骤中,Q值是需要不断更新的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 21
struct excel{
int number;
char name[MAXSIZE];
int seat;
}student[501];
int cmp(const void * p1, const void * p2){
struct excel *a = (struct excel*)p1;
struct excel *b = (struct excel*)p2;
if(a->seat != b->seat)
return a->seat - b->seat;
else
return a->number - b->number;
}
int comp(const void * p1, const void * p2){
struct excel *a = (struct excel*)p1;
struct excel *b = (struct excel*)p2;
return a->number - b->number;
} // 关键字不同,则应该写两个比较函数
int min(int a, int b){
if(a<=b)
return a;
else
return b;
}
int main() {
int i, j, n, temp, latter, judge[501]={0};
FILE *in, *out;
in = fopen("in.txt","r");
out = fopen("out.txt","w"); // 记得是文件输出
scanf("%d", &n);
for(i=0;i<n;i++){
fscanf(in,"%d %s %d", &student[i].number, student[i].name, &student[i].seat);
judge[student[i].seat] = 1;
}
qsort(student,n,sizeof(struct excel),cmp);
temp=min(n,student[n-1].seat);
latter = n - 1;
for(i=1;i<=temp;i++){
if(judge[i]==0){
student[latter--].seat = i;
judge[i]=1;
temp=min(n,student[latter].seat);
}
}
latter=-1; // 后续需继续使用latter进行比较,因此置为-1
for(i=0;i<n;i++){
if(student[i].seat>latter)
latter = student[i].seat;
}
qsort(student,n,sizeof(struct excel),cmp);
for(i=0;i<n;i++){
for(j=i+1;j<n;j++){
if(student[j].seat==student[i].seat){
if(student[j].number>student[i].number)
student[j].seat = ++latter;
else
student[i].seat = ++latter;
}
else
break;
}
}
qsort(student,n,sizeof(struct excel),comp); // 注意两次排序的关键字是不同的
for(i=0;i<n;i++)
fprintf(out,"%d %s %d\n",student[i].number,student[i].name,student[i].seat);
fclose(in);
fclose(out);
return 0;
}

整数排序(排序-基本题)

题面中给了代码就按照题面的代码进行计算,不要自己另辟蹊径。不同的代码细节不同,具体比较次数肯定是不一样的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#include <stdio.h>
#include <stdlib.h>
int cnt=0; // 某些排序算法涉及递归,因此将cnt定义为全局变量
void selectSort(int a[], int n){
int i, j, d, temp, count=0;
for(i=0;i<n-1;i++){
d=i;
for(j=i+1;j<n;j++){
count++;
if(a[j]<a[d])
d=j;
}
if(d!=i){
temp=a[d];
a[d]=a[i];
a[i]=temp;
}
}
for(i=0;i<n-1;i++)
printf("%d ", a[i]);
printf("%d\n", a[i]);
printf("%d\n", count);
}
void bubbleSort(int a[], int n){
int i, j, temp, flag=1, count=0;
for(i=n-1;i>0&&flag==1;i--){
flag=0;
for(j=0;j<i;j++){
count++;
if(a[j]>a[j+1]){
temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
flag=1;
}
}
}
for(i=0;i<n-1;i++)
printf("%d ", a[i]);
printf("%d\n", a[i]);
printf("%d\n", count);
}
void adjust(int a[], int i, int n){
int j, temp;
temp=a[i];
j=2*i+1;
while(j<n){
cnt++;
if(j<n-1&&a[j]<a[j+1])
j++;
if(temp>=a[j])
break;
a[(j-1)/2]=a[j];
j=2*j+1;
}
a[(j-1)/2]=temp;
}
void heapSort(int a[], int n){
int i, temp;
for(i=n/2-1;i>=0;i--)
adjust(a,i,n);
for(i=n-1;i>=1;i--){
temp=a[i];
a[i]=a[0];
a[0]=temp;
adjust(a,0,i);
}
for(i=0;i<n-1;i++)
printf("%d ", a[i]);
printf("%d\n", a[i]);
printf("%d\n", cnt);
}
void merge(int a[], int tmp[], int left, int leftend, int rightend){
int i=left, j=leftend+1, q=left;
while(i<=leftend&&j<=rightend){
cnt++;
if(a[i]<=a[j])
tmp[q++]=a[i++];
else
tmp[q++]=a[j++];
}
while(i<=leftend)
tmp[q++]=a[i++];
while(j<=rightend)
tmp[q++]=a[j++];
for(i=left;i<=rightend;i++)
a[i]=tmp[i];
}
void mSort(int a[], int temp[], int left, int right){
int center;
if(left<right){
center = (left+right)/2;
mSort(a,temp,left,center);
mSort(a,temp,center+1,right);
merge(a,temp,left,center,right);
}
}
void mergeSort(int a[], int n){
int *temp;
int i;
temp=(int*)malloc(n*sizeof(int));
mSort(a,temp,0,n-1);
free(temp);
for(i=0;i<n-1;i++)
printf("%d ", a[i]);
printf("%d\n", a[i]);
printf("%d\n", cnt);
}
void swap(int a[], int i, int j){
int temp;
temp=a[i];
a[i]=a[j];
a[j]=temp;
}
void sort(int a[], int left, int right){
int i, last;
if(left<right){
last=left;
for(i=left+1;i<=right;i++){
cnt++;
if(a[i]<a[left])
swap(a,++last,i);
}
swap(a,left,last);
sort(a,left,last-1);
sort(a,last+1,right);
}
}
void quickSort(int a[], int n){
int i;
sort(a,0,n-1);
for(i=0;i<n-1;i++)
printf("%d ", a[i]);
printf("%d\n", a[i]);
printf("%d\n", cnt);
}
int main(){
int a[102]={0}, n, op, i;
scanf("%d %d", &n, &op);
for(i=0;i<n;i++)
scanf("%d", &a[i]);
switch(op){
case 1:
selectSort(a,n);
break;
case 2:
bubbleSort(a,n);
break;
case 3:
heapSort(a,n);
break;
case 4:
mergeSort(a,n);
break;
case 5:
quickSort(a,n);
break;
} // 将各种函数封装好后,main函数里实现逻辑调用即可
return 0;
}

虽说期末考试的编程题不会涉及图的相关知识,但是不代表大家可以对图不重视。图在期末的选填中占比较大(例如Prim算法原理、Dijkstra算法的具体实现等),因此把每道题的代码理解清楚了,也是一种很好的复习期末考试的方法。注意:在此次题解中,只会强调每道题的易错点,不再给出代码的详细注释。

第七次作业编程题解

图遍历(图-基本题)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <stdio.h>
#include <string.h>
int visited[105]={0}, judge=1, a[105][105]={0}, queue[105]={0};
void DFS(int num, int d){
int i;
if(judge<num){
printf("%d ", d);
judge++;
}
else
printf("%d\n", d);
visited[d]=1;
for(i=1;i<=num;i++){
if(a[d][i]==1&&visited[i]==0)
DFS(num,i);
}
}
void BFS(int num, int d){
int i, j, k, v;
queue[1] = d;
for(j=1,k=1;j<=k;){
v=queue[j++];
if(visited[v] == 1)
continue;
if(judge < num){
printf("%d ", v);
judge++;
}
else
printf("%d\n", v);
visited[v] = 1;
for(i=1;i<=num;i++){
if(a[v][i]==1&&visited[i]==0)
queue[++k] = i;
}
}
}
int main(){
int i, ding_num, bian_num, x, y, delete;
scanf("%d %d", &ding_num, &bian_num);
for(i=1;i<=bian_num;i++){
scanf("%d %d", &x, &y);
a[x][y]=1;
a[y][x]=1;
}
scanf("%d", &delete);
DFS(ding_num,0);
memset(visited,0,sizeof(visited));
judge=1;
BFS(ding_num,0);
memset(visited,0,sizeof(visited));
judge=1;
visited[delete]=1;
DFS(ding_num-1,0);
memset(visited,0,sizeof(visited));
judge=1;
visited[delete]=1;
BFS(ding_num-1,0);
return 0;
}

独立路径数计算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <stdio.h>
#include <stdlib.h>
struct edge{
int order;
int adjvex;
struct edge *next;
};
struct ver{
struct edge *link;
}graph[1005];
int visited[1005]={0}, path[1005]={0}, ding_num, bian_num, k;
struct edge *insert(struct edge *list, int a, int b){
struct edge *p, *q;
p = (struct edge*)malloc(sizeof(struct edge));
p->order = b;
p->adjvex = a;
p->next = NULL;
if(list==NULL)
list = p;
else{
q = list;
while(q->next!=NULL)
q = q->next;
q->next = p;
}
return list;
}
void DFS(int v, int pos){
struct edge *p;
if(v==ding_num-1){
for(k=0;k<pos-1;k++)
printf("%d ", path[k]);
printf("%d", path[k]);
printf("\n");
}
for(p=graph[v].link;p!=NULL;p=p->next){
if(visited[p->adjvex]==0){
path[pos]=p->order;
visited[p->adjvex]=1;
DFS(p->adjvex,pos+1);
visited[p->adjvex]=0;
}
}
}
int main() {
int i, ord, v1, v2;
scanf("%d %d", &ding_num, &bian_num);
for(i=0;i<bian_num;i++){
scanf("%d %d %d", &ord, &v1, &v2);
graph[v1].link=insert(graph[v1].link,v2,ord);
graph[v2].link=insert(graph[v2].link,v1,ord);
}
visited[0]=1;
DFS(0,0);
return 0;
}

最少布线(图)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <stdio.h>
#include <stdlib.h>
#define INFINITY 932767
struct Node{
int order;
int weight;
}line[305][305];
int cmp(const void * a, const void * b){
return *(int*)a - *(int*)b;
}
int cost=0, temp[305]={0};
void Prim(struct Node weights[][305], int n){
int minweight[305], edges[305], min, i, j, k=0;
for(i=1;i<n;i++){
minweight[i]=weights[0][i].weight;
edges[i]=0;
}
edges[0]=0;
minweight[0]=0;
for(i=1;i<n;i++){
min = INFINITY;
for(j=1;j<n;j++){
if(minweight[j]!=0&&minweight[j]<min){
min = minweight[j];
k=j;
}
}
temp[i-1]=weights[edges[k]][k].order;
cost+=weights[edges[k]][k].weight;
minweight[k]=0;
for(j=0;j<n;j++){
if(weights[k][j].weight<minweight[j]){
minweight[j]=weights[k][j].weight;
edges[j]=k;
}
}
}
}
int main() {
int i, j, ding_num, bian_num, v1, v2, id, wei;
for(i=0;i<305;i++){
for(j=0;j<305;j++){
line[i][j].weight=INFINITY;
line[i][j].order=0;
}
}
scanf("%d %d", &ding_num, &bian_num);
for(i=0;i<bian_num;i++){
scanf("%d %d %d %d", &id, &v1, &v2, &wei);
line[v1][v2].order=id;
line[v1][v2].weight=wei;
line[v2][v1].order=id;
line[v2][v1].weight=wei;
}
Prim(line,ding_num);
qsort(temp,ding_num-1,sizeof(int),cmp);
printf("%d\n", cost);
for(i=0;i<ding_num-2;i++)
printf("%d ", temp[i]);
printf("%d\n", temp[i]);
return 0;
}

北京地铁乘坐线路查询(202205)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXSIZE 20
#define MAXCOUNT 500
#define INFINITY 32767
struct str{
int ischange;
char name[MAXSIZE];
}station[MAXCOUNT];
struct lingjiejuzhen{
int line;
int weight;
}vertex[MAXCOUNT][MAXCOUNT];
int spath[MAXCOUNT]={0}, stationtotal=0, path[MAXCOUNT][MAXCOUNT];
void floyd(int v1,int v2){
int i,j,k;
for(i=0;i<stationtotal;i++){
for(j=0;j<stationtotal;j++){
if(i!=j&&vertex[i][j].weight<INFINITY)
path[i][j]=i;
}
}
for(k=0;k<stationtotal;k++){
for(i=0;i<stationtotal;i++){
for(j=0;j<stationtotal;j++){
if(vertex[i][j].weight>vertex[i][k].weight+vertex[k][j].weight){
vertex[i][j].weight=vertex[i][k].weight+vertex[k][j].weight;
path[i][j]=path[k][j];
}
}
}
}
}
int main(int argc, const char * argv[]) {
FILE *in;
int i, j, k, v1, v2, judge, change, linenum, stationnum, totalline;
int shi=0, zhong=0, count=1, temp[MAXCOUNT]={0};
char s[MAXSIZE]={0}, begin[MAXSIZE]={0}, end[MAXSIZE]={0};
scanf("%s %s", begin, end);
in = fopen("bgstations.txt","r");
for(i=0;i<MAXCOUNT;i++){
for(j=0;j<MAXCOUNT;j++){
vertex[i][j].weight=INFINITY;
vertex[i][j].line=0;
}
}
fscanf(in,"%d",&totalline);
for(i=0;i<totalline;i++){
v1=-1;
v2=-1;
fscanf(in,"%d %d",&linenum,&stationnum);
for(j=0;j<stationnum;j++){
judge=1;
memset(s,0,sizeof(s));
fscanf(in,"%s %d",s,&change);
for(k=0;k<stationtotal;k++){
if(strcmp(station[k].name,s)==0){
judge=0;
v1=k;
break;
}
}
if(judge==1){
strcpy(station[stationtotal].name,s);
station[stationtotal].ischange=change;
v1=k;
stationtotal++;
}
if(v2!=-1){
vertex[v1][v2].weight=1;
vertex[v2][v1].weight=1;
vertex[v2][v1].line=linenum;
vertex[v1][v2].line=linenum;
}
v2=v1;
}
}
fclose(in);
for(i=0;i<stationtotal;i++){
if(strcmp(station[i].name,begin)==0)
shi=i;
if(strcmp(station[i].name,end)==0)
zhong=i;
}
floyd(shi,zhong);
temp[0]=zhong;
judge=1;
for(i=zhong,j=0;i!=shi;){
temp[++j] = path[shi][i];
i=path[shi][i];
}
for(i=j;i>=1;i--){
if(judge==1){
printf("%s-%d", station[temp[i]].name, vertex[temp[i]][temp[i-1]].line);
judge=0;
}
else{
if(vertex[temp[i+1]][temp[i]].line==vertex[temp[i]][temp[i-1]].line)
count++;
else{
printf("(%d)-", count);
count=1;
judge=1;
i++;
}
}
}
printf("(%d)-%s\n", count, station[temp[0]].name);
return 0;
}

Author: diandian, Riccardo

  • Title: 猪脚说第十五期
  • Author: Diandian
  • Created at : 2023-07-14 23:03:20
  • Updated at : 2023-07-14 23:19:59
  • Link: https://cutedian.github.io/2023/07/14/猪脚说第十五期/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments