02-1. Reversing Linked List (25)
http://www.patest.cn/contests/mooc-ds/02-1
Given a constant K and a singly linked list L, you are supposed to reverse the links of every K elements on L. For example, given L being 1→2→3→4→5→6, if K = 3, then you must output 3→2→1→6→5→4; if K = 4, you must output 4→3→2→1→5→6.
Input Specification:
Each input file contains one test case. For each case, the first line contains the address of the first node, a positive N (<= 105) which is the total number of nodes, and a positive K (<=N) which is the length of the sublist to be reversed. The address of a node is a 5-digit nonnegative integer, and NULL is represented by -1.
Then N lines follow, each describes a node in the format:
Address Data Next
where Address is the position of the node, Data is an integer, and Next is the position of the next node.
Output Specification:
For each case, output the resulting ordered linked list. Each node occupies a line, and is printed in the same format as in the input.
Sample Input:00100 6 4 00000 4 99999 00100 1 12309 68237 6 -1 33218 3 00000 99999 5 68237 12309 2 33218Sample Output:
00000 4 33218 33218 3 12309 12309 2 00100 00100 1 99999 99999 5 68237 68237 6 -1
題目大意:反轉單鏈表,給定常數K和單鏈表L,要求按每K個節點反轉單鏈表,如:L: 1->2->3->4->5->6 K=3,輸出:3->2->1->6->5->4,如果K=4,輸出:4->3->2->1->5->6.
輸入說明:每次輸入一個案例,對每個案例,第一行內容是鏈表第一個節點的地址,節點數N(N<=100,000)(不一定是最終形成的單鏈表的節點數),常數K(<=N),K是需要反轉的子鏈表的長度,節點的地址是一個5位的非負整數,NULL用-1來代替。
下面輸入N行 格式如下:
Address Data Next
Address代表節點的位置,Data是整型數字,Next是下一個節點的位置。
輸出說明:輸出反轉后的單鏈表,每個節點占一行,格式和輸入的一樣。
樣例輸入:
00100 6 4 00000 4 99999 00100 1 12309 68237 6 -1 33218 3 00000 99999 5 68237 12309 2 33218
樣例輸出:
00000 4 33218 33218 3 12309 12309 2 00100 00100 1 99999 99999 5 68237 68237 6 -1
------------------------------------------------------------------------------
分析: 第一行:00100 表示第一個節點的位置,即節點: 00100 1 12309 然后根據12309找到第二個節點:12309 2 33218,繼續找,直到找到最后一個節點 68237 6 -1。
形成的單鏈表是 1 -> 2 -> 3 -> 4 -> 5 -> 6。 第一行第二個數N=6,代表接下來會輸入6個節點,K=4,意思是每4個節點逆轉,余下2個節點,不足4個,故不反轉。輸出 4->3->2->1->5->6。
需要注意的是:1,如果K=1,鏈表不反轉,K等於鏈表的節點數,鏈表整個反轉,如果鏈表的節點數能被K整除,則每段都要反轉。還有就是輸出的時候節點的Next 是和逆轉后的節點相關,不是原先節點的Next,如:輸入的時候 節點 00000 4 99999 輸出的時候應為 00000 4 33218,應為反轉后節點4的下一個節點為3,而3的Address是33218。
------------------------------------------------------------------------------
life is short, show the code! C(gcc 4.7.2)
#include<stdio.h> #define MAX_SIZE 100004 typedef struct tagLNode{ int addr; //節點位置Address int data; //Data值 int nextAddr; //下個節點位置 struct tagLNode *next; //指向下個節點的指針 } LNode; /* LNode *listReverse(LNode *head, int k); 反轉單鏈表函數 參數1:單鏈表的頭節點, 參數2:反轉子鏈表的長度, 返回值:反轉后的鏈表的第一個節點(不是頭結點) */ LNode *listReverse(LNode *head, int k); //輸出單鏈表 參數為單鏈表的頭結點 void printList(LNode *a); int main() { int firstAddr; int n = 0; //節點數 N int k = 0; //反轉子鏈表的長度K int num = 0; //鏈表建好之后的鏈表節點數 int data[MAX_SIZE]; //存data值 節點位置作為索引值 int next[MAX_SIZE]; //存next值 節點位置為索引 int tmp; //臨時變量,輸入的時候用 scanf("%d %d %d", &firstAddr, &n, &k); LNode a[n+1]; //能存n+1個幾點的數組。 a[0].nextAddr = firstAddr; //a[0] 作為頭節點 //讀輸入的節點 int i = 1; for (; i < n+1; i++){ scanf("%d", &tmp); scanf("%d %d", &data[tmp], &next[tmp]); } //構建單鏈表 i = 1; while (1){ if (a[i-1].nextAddr == -1){ a[i-1].next = NULL; num = i-1; break; } a[i].addr = a[i-1].nextAddr; a[i].data = data[a[i].addr]; a[i].nextAddr = next[a[i].addr]; a[i-1].next = a+i; i++; } LNode *p = a; //p指向鏈表頭結點 LNode *rp = NULL; //反轉鏈表函數的返回值 if (k <= num ){ for (i = 0; i < (num/k); i++){ rp = listReverse(p, k); // p->next = rp; // 第一次執行,a[0]->next 指向第一段子鏈表反轉的第一個節點 p->nextAddr = rp->addr; // 更改Next值,指向逆轉后它的下一個節點的位置 int j = 0; //使p指向下一段需要反轉的子鏈表的頭結點(第一個節點的前一個節點) while (j < k){ p = p->next; j++; } } } printList(a); } LNode *listReverse(LNode *head, int k) { int count = 1; LNode *new = head->next; LNode *old = new->next; LNode *tmp = NULL; while (count < k){ tmp = old->next; old->next = new; old->nextAddr = new->addr; new = old; //new向后走一個節點 old = tmp; //tmp向后走一個節點 count++; } //使反轉后的最后一個節點指向下一段子鏈表的第一個節點 head->next->next = old; if (old != NULL){ //修改Next值,使它指向下一個節點的位置 head->next->nextAddr = old->addr; }else{ //如果old為NULL,即沒有下一個子鏈表,那么反轉后的最后一個節點即是真個鏈表的最后一個節點 head->next->nextAddr = -1; } return new; } void printList(LNode *a) { LNode *p = a; while (p->next != NULL){ p = p->next; if (p->nextAddr != -1 ){ //格式輸出,%.5意味着如果一個整數不足5位,輸出時前面補0 如:22,輸出:00022 printf("%.5d %d %.5d\n", p->addr, p->data, p->nextAddr); }else{ //-1不需要以%.5格式輸出 printf("%.5d %d %d\n", p->addr, p->data, p->nextAddr); } } }
測試點一共有7個: L 代表單鏈表節點數,因為構成單鏈表的節點不一定都在輸入的N個節點中,即:L<=N;
case 0:L = N 有節點 Address = 99999
case 1: L = m*K, L = N, (m = 2, 3, 4,...) 有節點 Address = 99999
case 2: K = N, L = N 有節點 Address = 99999
case 3: K = 1, L = m*K 有節點 Address = 99999
case 4: K = 1, L = N = 1 (很簡單的一個測試點)
case 5: K != 1, L % K = (K-1) (節點數很多,如果建鏈表的復雜度是O(n*n), 超時的可能性很大)
case 6: L > N (有多余節點) 有節點Address = 99999
要考慮的細節:K=1不反轉,K=L 全反轉,L%K == 0, 每段都反轉,L%k = (K-1),多余的節點不反轉。L<N,有多余節點的情況。
