这是我到目前为止这个习题集中花时间最久ac的题目了……其实一开始思路还是挺清晰的,但是有三个测试点很长时间通过不了,最终结合别人的方法对自己的代码进行了大改。
1 #include <stdio.h> 2 #include <stdlib.h> 3 #define MaxSize 100001 4 5 typedef struct LNode *List; 6 struct LNode{ 7 int Addr; 8 int Data; 9 int NextAddr; 10 List Next; 11 }; 12 13 List FormList(int FirstAdd, int N, int *pn) 14 { 15 // struct LNode LN[MaxSize]; 16 List head; 17 int tmpAddr; //as the index of the original array 18 int i; 19 int Addr[MaxSize], Data[MaxSize], NextAddr[MaxSize]; 20 struct LNode LN[N + 1]; 21 LN[0].NextAddr = FirstAdd; 22 for(i = 0; i < N; i++){ 23 scanf("%d", &tmpAddr); 24 scanf("%d %d", &Data[tmpAddr], &NextAddr[tmpAddr]); 25 } 26 i = 1; 27 while(1){ 28 if(LN[i - 1].NextAddr == -1){ 29 LN[i - 1].Next = NULL; 30 (*pn) = i - 1; 31 break; 32 } 33 LN[i].Addr = LN[i - 1].NextAddr; 34 LN[i].Data = Data[LN[i].Addr]; 35 LN[i].NextAddr = NextAddr[LN[i].Addr]; 36 LN[i - 1].Next = LN + i; //? 37 i++; 38 } 39 head = LN; 40 return head; 41 } 42 43 void PrintList(List L) 44 { 45 List p; 46 p = L; 47 while(p->Next){ 48 p = p->Next; 49 if(p->NextAddr == -1) 50 printf("%05d %d %d\n", p->Addr, p->Data, p->NextAddr); 51 else 52 printf("%05d %d %05d\n",p->Addr, p->Data, p->NextAddr ); 53 } 54 } 55 56 List Reverse(List head, int K) 57 { 58 int cnt = 1; 59 List newP, old, tmp; 60 newP = head->Next; 61 old = newP->Next; 62 while(cnt < K){ 63 tmp = old->Next; 64 old->Next = newP; 65 old->NextAddr = newP->Addr; 66 newP = old; 67 old = tmp; 68 cnt++; 69 } 70 head->Next->Next = old; 71 if(old) 72 head->Next->NextAddr = old->Addr; 73 else 74 head->Next->NextAddr = -1; 75 return newP; 76 } 77 78 int main(int argc, char const *argv[]) 79 { 80 int FirstAdd, N, K; 81 int i, j; 82 int num = 0; 83 int *pn = # 84 List L; 85 scanf("%d %d %d", &FirstAdd, &N, &K); 86 L = FormList(FirstAdd, N, pn); 87 List p, rp; 88 p = L; 89 rp = NULL; 90 if(K <= num){ 91 for(i = 0; i < (num/K); i++){ 92 rp = Reverse(p, K); 93 p->Next = rp; //更新p 94 p->NextAddr = rp->Addr; //NextAddr的变换尤为重要 95 for(j = 0; j < K; j++) 96 p = p->Next; 97 } 98 } 99 PrintList(L); 100 return 0; 101 }
测试点“正好全反转”对应90 - 98行,当num是K的整数倍时,链表要每段都整体反转多次。
测试点“有多余结点不在链表上”对应num参数的操作,num代表输入的有效结点的个数,当输入一些链外结点时它们不会被计入有效结点,以保证循环次数的正确。
测试点“最大N,最后剩下K - 1不反转”除了需要考虑num数值以保证反转数的正确,还涉及了对时间复杂度的考察。这也是我最后一个通过的测试点,因为起先我的思路是把每组输入的内容都以结点形式存储下来:
List FormList(int FirstAdd, int N, int *pn) { List L[MaxSize], head, tmp; int i, j; int Addr[MaxSize], Data[MaxSize], NextAddr[MaxSize]; L[0] = (List)malloc(sizeof(struct LNode)); //L[0] as the head node, //whose Data and Addr is null while Next points to the first valid node for(i = 1; i < N + 1; i++) scanf("%d %d %d", &Addr[i], &Data[i], &NextAddr[i]); for(i = 1; i < N + 1; i++){ if(Addr[i] == FirstAdd){ L[1] = (List)malloc(sizeof(struct LNode)); L[1]->Addr = Addr[i]; L[1]->Data = Data[i]; L[1]->NextAddr = NextAddr[i]; L[0]->Next = L[1]; //Now the first valid node was constructed and pointed by the head node (*pn)++; break; } } i = 1; while(1){ for(j = 1; j < N + 1; j++){ if(L[i]->NextAddr == Addr[j]){ (*pn)++; L[i + 1] = (List)malloc(sizeof(struct LNode)); L[i + 1]->Addr = Addr[j]; L[i + 1]->Data = Data[j]; L[i + 1]->NextAddr = NextAddr[j]; L[i]->Next = L[i + 1]; } } if(L[i]->NextAddr == -1){ L[i]->Next = NULL; break; } i++; } head = L[0]; free(L[0]); return head; }
这样虽然很明确对应了每个独立结点,也方便串联操作,但是构建时的时间复杂度已达到O(n2),测试最大N时会超时,所以后来还是改用了数组方法,这才提升了操作效率。