点击上方“ 剑指数模 ”,选择“ 置顶 / 星标 ”
回复『进群』,加入高手如云
在公众号后台回复『PAT刷题记002』, 获得
浙江大学MOOC_Week2
课件及本文所有源码.1.
PAT刷题记001 | 复杂度
题 目 2.1
来源: 数据结构浙大MOOC: 02-线性结构1 两个有序链表序列的合并 (15 分)
分 析 2.1
分别遍历两个链表, 比较当前元素的大小, 遇到较小元素的则下放到结果链表中, 指针后移,直至其中一链表遍历完成,最后将存在剩余元素的链表接在结果链表后即可.
1/*
2 * 合并有序连边
3 * Author: Gangjian Liu
4 * Email: liugangjian0427@foxmail.com
5 * 编译环境:DEVC++
6*/
7
8List Merge( List L1, List L2 ){
9 List p, q;
10 List L3, r;
11 L3 = (List)malloc(sizeof(struct Node));
12 L3->Next = NULL;
13 r = L3;
14
15 // 处理头节点
16 p = L1->Next;
17 q = L2->Next;
18
19 // 尾插法处理合并连表
20 while(p&&q){
21 if(p->Data <= q->Data){
22 r->Next = p;
23 p = p->Next;
24 }
25
26 else{
27 r->Next = q;
28 q = q->Next;
29 }
30
31 r = r->Next;
32 }
33
34 // 处理剩余节点
35 if(p)
36 r->Next = p;
37 else
38 r->Next = q;
39
40 L1->Next = NULL;
41 L2->Next = NULL;
42 return L3;
43}
题 目 2.2
来源: 数据结构浙大MOOC: 02-线性结构2 一元多项式的乘法与加法运算 (20 分)
分 析 2.2
程序框架的搭建
如何读多项式
这里采用的是将尾指针Rear->link = NULL
的方式, 每次把新输入项节点接在尾指针后即可.
1// 读多项式
2Polynomial ReadPoly(){
3 Polynomial P, Rear, t;
4 int c, e, N;
5
6 scanf("%d", &N);
7 P = (Polynomial)malloc(sizeof(struct PolyNode));
8 P->link = NULL;
9 Rear = P;
10
11 while(N--){
12 scanf("%d %d", &c, &e);
13 Attach(c, e, &Rear);
14 }
15
16 // 释放头节点
17 t = P; P = P->link; free(t);
18
19 return P;
20}
21// 附加项
22void Attach(int c, int e, Polynomial* pRear){
23 Polynomial T;
24 T = (Polynomial)malloc(sizeof(struct PolyNode));
25
26 T->coef = c;
27 T->expon = e;
28 T->link = NULL;
29 (*pRear)->link = T;
30
31 // 修改尾指针的值
32 (*pRear)= T;
33}
如何定义加法运算
加法的定义在两项指数不同时的思路与题目2.1: 两个有序链表的合并
一致, 需要讨论的是当两项指数相同时该如何操作.
1// 加法运算
2Polynomial Add(Polynomial P1, Polynomial P2){
3 Polynomial t1, t2, P, Rear, t;
4 t1 = P1;
5 t2 = P2;
6 P = (Polynomial)malloc(sizeof(struct PolyNode));
7 P->link = NULL;
8 Rear = P;
9
10 while(t1&&t2){
11 // 指数相等时
12 if(t1->expon == t2->expon){
13 if(t1->coef+t2->coef == 0);
14 else
15 Attach(t1->coef + t2->coef, t1->expon, &Rear);
16
17 t1 = t1->link;
18 t2 = t2->link;
19 }
20 // t1指数大于t2
21 else if(t1->expon > t2->expon){
22 Attach(t1->coef, t1->expon, &Rear);
23 t1 = t1->link;
24 }
25 // t1指数小于t2
26 else{
27 Attach(t2->coef, t2->expon, &Rear);
28 t2 = t2->link;
29 }
30 }
31 // 处理剩余多项式
32 while(t1){
33 Attach(t1->coef, t1->expon, &Rear);
34 t1 = t1->link;
35 }
36
37 while(t2){
38 Attach(t2->coef, t2->expon, &Rear);
39 t2 = t2->link;
40 }
41
42 // 处理头节点
43 t = P; P = P->link; free(t);
44
45 return P;
46}
如何定义乘法运算
这里我们采用逐项插入
的方法, 先用P1
的第一项与P2
每一项相乘,得到初始项. 之后用P1
剩余每一项与P2
每一项想成,将结果插入初始项中合适位置.
1// 乘法运算
2Polynomial Mult(Polynomial P1, Polynomial P2){
3 int c, e;
4
5 if(!P1||!P2)
6 return NULL;
7
8 Polynomial t1, t2, P, Rear, T;
9 t1 = P1;
10 t2 = P2;
11 P = (Polynomial)malloc(sizeof(struct PolyNode));
12 P->link = NULL;
13 Rear = P;
14
15 // 先用P1的第一项与P2相乘,得到初始项
16 while(t2){
17 Attach(t1->coef*t2->coef, t1->expon+t2->expon, &Rear);
18 t2 = t2->link;
19 }
20
21 t1 = t1->link;
22
23 while(t1){
24 // 重新定位
25 t2 = P2;
26 Rear = P;
27
28 while(t2){
29 e = t1->expon+t2->expon;
30 c = t1->coef*t2->coef;
31
32 // 根据指数e寻找合适的插入位置
33 while(Rear->link && Rear->link->expon > e)
34 Rear = Rear->link;
35 // 若指数等
36 if(Rear->link && Rear->link->expon == e){
37 if(Rear->link->coef + c)
38 Rear->link->coef += c;
39 // 系数和为0则抛弃之
40 else{
41 T = Rear->link;
42 Rear->link = T->link;
43 free(T);
44 }
45 }
46 // 若指数小
47 else{
48 T = (Polynomial)malloc(sizeof(struct PolyNode));
49 T->coef = c;
50 T->expon = e;
51 T->link = Rear->link;
52 Rear->link = T;
53 Rear = Rear->link;
54 }
55 t2 = t2->link;
56 }
57
58 t1 = t1->link;
59
60 }
61 t2 = P; P = P->link; free(t2);
62 return P;
63}
完整代码如下
1/*
2 * 一元多项式的乘法与加法运算
3 * Author: Gangjian Liu
4 * Email: liugangjian0427@foxmail.com
5 * 编译环境:DEVC++
6*/
7
8#include<stdio.h>
9#include<stdlib.h>
10
11// 数据结构设计
12typedef struct PolyNode *Polynomial;
13struct PolyNode{
14 int coef;
15 int expon;
16 Polynomial link;
17};
18
19void Attach(int c, int e, Polynomial* P);
20void PrintPoly(Polynomial P);
21Polynomial Add(Polynomial P1, Polynomial P2);
22Polynomial ReadPoly();
23Polynomial Mult(Polynomial P1, Polynomial P2);
24
25
26int main(){
27 Polynomial P1, P2, PP, PS;
28
29 P1 = ReadPoly();
30 P2 = ReadPoly();
31
32 PP = Mult(P1, P2);
33 PS = Add(P1, P2);
34
35 PrintPoly(PP);
36 PrintPoly(PS);
37 return 0;
38}
39
40// 乘法运算
41Polynomial Mult(Polynomial P1, Polynomial P2){
42 int c, e;
43
44 if(!P1||!P2)
45 return NULL;
46
47 Polynomial t1, t2, P, Rear, T;
48 t1 = P1;
49 t2 = P2;
50 P = (Polynomial)malloc(sizeof(struct PolyNode));
51 P->link = NULL;
52 Rear = P;
53
54 // 先用P1的第一项与P2相乘,得到初始项
55 while(t2){
56 Attach(t1->coef*t2->coef, t1->expon+t2->expon, &Rear);
57 t2 = t2->link;
58 }
59
60 t1 = t1->link;
61
62 while(t1){
63 // 重新定位
64 t2 = P2;
65 Rear = P;
66
67 while(t2){
68 e = t1->expon+t2->expon;
69 c = t1->coef*t2->coef;
70
71 // 根据指数e寻找合适的插入位置
72 while(Rear->link && Rear->link->expon > e)
73 Rear = Rear->link;
74 // 若指数等
75 if(Rear->link && Rear->link->expon == e){
76 if(Rear->link->coef + c)
77 Rear->link->coef += c;
78 // 系数和为0则抛弃之
79 else{
80 T = Rear->link;
81 Rear->link = T->link;
82 free(T);
83 }
84 }
85 // 若指数小
86 else{
87 T = (Polynomial)malloc(sizeof(struct PolyNode));
88 T->coef = c;
89 T->expon = e;
90 T->link = Rear->link;
91 Rear->link = T;
92 Rear = Rear->link;
93 }
94 t2 = t2->link;
95 }
96
97 t1 = t1->link;
98
99 }
100 t2 = P; P = P->link; free(t2);
101 return P;
102}
103
104// 加法运算
105Polynomial Add(Polynomial P1, Polynomial P2){
106 Polynomial t1, t2, P, Rear, t;
107 t1 = P1;
108 t2 = P2;
109 P = (Polynomial)malloc(sizeof(struct PolyNode));
110 P->link = NULL;
111 Rear = P;
112
113 while(t1&&t2){
114 // 指数相等时
115 if(t1->expon == t2->expon){
116 if(t1->coef+t2->coef == 0);
117 else
118 Attach(t1->coef + t2->coef, t1->expon, &Rear);
119
120 t1 = t1->link;
121 t2 = t2->link;
122 }
123 // t1指数大于t2
124 else if(t1->expon > t2->expon){
125 Attach(t1->coef, t1->expon, &Rear);
126 t1 = t1->link;
127 }
128 // t1指数小于t2
129 else{
130 Attach(t2->coef, t2->expon, &Rear);
131 t2 = t2->link;
132 }
133 }
134 // 处理剩余多项式
135 while(t1){
136 Attach(t1->coef, t1->expon, &Rear);
137 t1 = t1->link;
138 }
139
140 while(t2){
141 Attach(t2->coef, t2->expon, &Rear);
142 t2 = t2->link;
143 }
144
145 // 处理头节点
146 t = P; P = P->link; free(t);
147
148 return P;
149}
150
151// 读多项式
152Polynomial ReadPoly(){
153 Polynomial P, Rear, t;
154 int c, e, N;
155
156 scanf("%d", &N);
157 P = (Polynomial)malloc(sizeof(struct PolyNode));
158 P->link = NULL;
159 Rear = P;
160
161 while(N--){
162 scanf("%d %d", &c, &e);
163 Attach(c, e, &Rear);
164 }
165
166 // 释放头节点
167 t = P; P = P->link; free(t);
168
169 return P;
170}
171
172// 附加项
173void Attach(int c, int e, Polynomial* pRear){
174 Polynomial T;
175 T = (Polynomial)malloc(sizeof(struct PolyNode));
176
177 T->coef = c;
178 T->expon = e;
179 T->link = NULL;
180 (*pRear)->link = T;
181
182 // 修改尾指针的值
183 (*pRear)= T;
184}
185
186// 输出多项式
187void PrintPoly(Polynomial P){
188 //调整输出格式
189 int flag = 0;
190
191 if(!P){
192 printf("0 0\n");
193 return;
194 }
195
196 while(P){
197 // 如果输出的是首项
198 if(!flag)
199 flag = 1;
200 else
201 printf(" ");
202
203 printf("%d %d",P->coef,P->expon);
204 P = P->link;
205 }
206 printf("\n");
207}
拓 展 2.3
来源: 某大公司笔试题改编的2014年春季PAT真题
分 析 2.3
本题值得注意的地方有两点:
链表的反转操作
子函数返回指针时的定义
链表的反转操作
1void ReservingList(Item* ItemList,int HeadPos, int K){
2 int Front, Rear, p, count;
3 count = 1;
4 Front = ItemList[HeadPos].Pos;
5 // 计算有效节点数
6 while(ItemList[Front].Nex != -1){
7 count++;
8 Front = ItemList[Front].Nex;
9 }
10 // 初始化头和尾
11 Front = ItemList[HeadPos].Pos;
12 Rear = ItemList[HeadPos].Nex;
13 // 设置结果头节点位置
14 // 题目说明Num<10^5
15 int Head = N, Tail;
16
17 // 反转操作
18 int i, j;
19 for(i=0; i < count/K; ++i){
20 // 上一次的开头是下一次的结尾
21 Tail = Front;
22 for(j=1; j < K; ++j){
23 p = ItemList[Rear].Nex;
24 ItemList[Rear].Nex = ItemList[Front].Pos;
25 Front = Rear;
26 Rear = p;
27 }
28 ItemList[Head].Nex = Front;
29 Head = Tail;
30 Front = ItemList[Rear].Pos;
31 Rear = ItemList[Rear].Nex;
32 }
33
34 // 对于剩余节点的处理
35 if(count % K){
36 ItemList[Head].Nex = Front;
37 PrintItemList(ItemList, ItemList[N].Nex);
38 }
39 else{
40 ItemList[Head].Nex = -1;
41 PrintItemList(ItemList, ItemList[N].Nex);
42 }
43}
返回指针变量时子函数的定义
1Item* ReadItemList(int Num){
2 // 函数的局部变量都是存在stack中的,
3 // 当这个函数调用过程结束时,这个局部变量会被要释放掉的,
4 // 内存将重新分配,故返回地址可能出差
5 static Item ItemList[N];
6 int i, Pos, Val, Nex;
7 for(i=0; i < Num; i++){
8 scanf("%d %d %d",&Pos, &Val, &Nex);
9 ItemList[Pos].Pos = Pos;
10 ItemList[Pos].Val = Val;
11 ItemList[Pos].Nex = Nex;
12 }
13 return ItemList;
14}
完整代码如下
1/*
2 * Reversing Linked List
3 * Author: Gangjian Liu
4 * Email: liugangjian@pku.edu.cn
5 * 编译环境:DEVC++
6*/
7
8#include<stdio.h>
9#define N 100001
10
11struct Node{
12 int Pos;
13 int Val;
14 int Nex;
15};
16
17typedef struct Node Item;
18
19Item* ReadItemList(int Num);
20void ReservingList(Item* ItemList, int HeadPos, int K);
21void PrintItemList(Item* ItemList, int HeadPos);
22
23int main(){
24 Item* ItemList;
25 int HeadPos, Num, K;
26 scanf("%d %d %d", &HeadPos, &Num, &K);
27 ItemList = ReadItemList(Num);
28 ReservingList(ItemList, HeadPos, K);
29 return 0;
30}
31
32void ReservingList(Item* ItemList,int HeadPos, int K){
33 int Front, Rear, p, count;
34 count = 1;
35 Front = ItemList[HeadPos].Pos;
36 // 计算有效节点数
37 while(ItemList[Front].Nex != -1){
38 count++;
39 Front = ItemList[Front].Nex;
40 }
41 // 初始化头和尾
42 Front = ItemList[HeadPos].Pos;
43 Rear = ItemList[HeadPos].Nex;
44 // 设置结果头节点位置
45 // 题目说明Num<10^5
46 int Head = N, Tail;
47
48 // 反转操作
49 int i, j;
50 for(i=0; i < count/K; ++i){
51 // 上一次的开头是下一次的结尾
52 Tail = Front;
53 for(j=1; j < K; ++j){
54 p = ItemList[Rear].Nex;
55 ItemList[Rear].Nex = ItemList[Front].Pos;
56 Front = Rear;
57 Rear = p;
58 }
59 ItemList[Head].Nex = Front;
60 Head = Tail;
61 Front = ItemList[Rear].Pos;
62 Rear = ItemList[Rear].Nex;
63 }
64
65 // 对于剩余节点的处理
66 if(count % K){
67 ItemList[Head].Nex = Front;
68 PrintItemList(ItemList, ItemList[N].Nex);
69 }
70 else{
71 ItemList[Head].Nex = -1;
72 PrintItemList(ItemList, ItemList[N].Nex);
73 }
74}
75
76Item* ReadItemList(int Num){
77 // 函数的局部变量都是存在stack中的,
78 // 当这个函数调用过程结束时,这个局部变量会被要释放掉的,
79 // 内存将重新分配,故返回地址可能出差
80 static Item ItemList[N];
81 int i, Pos, Val, Nex;
82 for(i=0; i < Num; i++){
83 scanf("%d %d %d",&Pos, &Val, &Nex);
84 ItemList[Pos].Pos = Pos;
85 ItemList[Pos].Val = Val;
86 ItemList[Pos].Nex = Nex;
87 }
88 return ItemList;
89}
90
91void PrintItemList(Item* ItemList, int HeadPos){
92 while(HeadPos != -1){
93 if(ItemList[HeadPos].Nex != -1)
94 printf("%05d %d %05d\n",ItemList[HeadPos].Pos,ItemList[HeadPos].Val,ItemList[HeadPos].Nex);
95 else
96 printf("%05d %d %d\n",ItemList[HeadPos].Pos,ItemList[HeadPos].Val,ItemList[HeadPos].Nex);
97 HeadPos = ItemList[HeadPos].Nex;
98 }
99}
拓 展 2.4
来源: 2013年PAT春季考试真题