PAT刷题记002 | 线性结构

点击上方“ 剑指数模 ”,选择“ 置顶 / 星标 ”

回复『进群』,加入高手如云



在公众号后台回复『PAT刷题记002』, 获得浙江大学MOOC_Week2课件及本文所有源码.


1. 

PAT刷题记001 | 复杂度

题 目 2.1

来源: 数据结构浙大MOOC: 02-线性结构1 两个有序链表序列的合并 (15 分)

分 析 2.1

分别遍历两个链表, 比较当前元素的大小, 遇到较小元素的则下放到结果链表中, 指针后移,直至其中一链表遍历完成,最后将存在剩余元素的链表接在结果链表后即可.

 1/*
2 * 合并有序连边 
3 * Author: Gangjian Liu 
4 * Email: [email protected]
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: [email protected]
5 * 编译环境:DEVC++ 
6*/
7
8#include
9#include
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: [email protected]
5 * 编译环境:DEVC++ 
6*/
7
8#include
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春季考试真题


你可能感兴趣的:(PAT刷题记002 | 线性结构)