zoukankan      html  css  js  c++  java
  • 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
    ", p->addr, p->data, p->nextAddr);
            }else{
                //-1不需要以%.5格式输出
                printf("%.5d %d %d
    ", 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,有多余节点的情况。






  • 相关阅读:
    2190 ACM 数学概率论的乘法和加法原则
    2186 ACM 水题 int 向下取整
    2110 ACM Crisis of HDU 母函数
    2079 ACM 选课时间 背包 或 母函数
    2111 ACM 贪心 水题
    2108 ACM 向量积 凹凸
    My Web Developer Roadmap
    2109 ACM 排序
    2107 ACM 水题
    vi的常用命令
  • 原文地址:https://www.cnblogs.com/kevin-lwb/p/4283456.html
Copyright © 2011-2022 走看看