PAT02-1Reversing Linked List (25) 單鏈表逆序


02-1. Reversing Linked List (25)

http://www.patest.cn/contests/mooc-ds/02-1

時間限制  400 ms   內存限制    65536 kB    代碼長度限制   8000 B   判題程序   Standard   作者 CHEN, Yue

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 33218
Sample 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,有多余節點的情況。







免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM