02-线性结构3 Reversing Linked List

  这是我到目前为止这个习题集中花时间最久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 = &num;
 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时会超时,所以后来还是改用了数组方法,这才提升了操作效率。

posted @ 2018-03-26 09:30  BianK  阅读(499)  评论(0编辑  收藏  举报