1. 程式人生 > >02-線性結構3 Reversing Linked List(PTA)

02-線性結構3 Reversing Linked List(PTA)

02-線性結構3 Reversing Linked List(25 point(s))

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, andNext 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
Author: 陳越 Organization: 浙江大學 Time Limit: 400ms Memory Limit: 64MB Code Size Limit:16KB


初學資料結構, 十分慚愧, 這道題虐了我好幾天;

但是最後一遍直接AC的感覺是十分美妙的;

現在對此題做些總結:

(一)單鏈表的倒轉

本來一開始, 以我個人的性格, 總是喜歡自己研究, 結果搞了好幾天都是各種段錯誤, 語法錯誤;

還誤入歧途, 嘗試了雙向連結串列, 極其繁瑣, 又不易除錯;

而後終於, 借鑑https://www.2cto.com/kf/201601/485759.html部落格的思想, 在連結串列倒轉這一塊算是有了較好的認識;

(二)採用遞迴

在第四個版本時, 重新架構程式碼;

重新思考題目, 發現無論如何, 都要遍歷一次, 按順序安放結點;

那麼為何不把問題主要分解成:

1.根據地址找到結點;

2.將其放到正確的位置;


而顯然, 要遍歷到K == 1 或者 Address 找不到, 方可知道要採用倒轉放置, 還是正序放置;

故遞迴做法, 顯然是十分合適的;

當遞迴至最裡層, 根據遞迴返回狀態, 選擇是要倒序, 還是正序;

而後層層回溯, 放置結點;


故總體時間複雜度為O(n);
n為結點地址為-1或找不到為止;
小於等於連結串列長度;
空間複雜度, 因有遞迴, 不是很懂, 當K較大時, 遞迴層數較深, 或許會較大;
但, 不考慮遞迴帶來的影響, S(n);
n為總連結串列長度;


總結:

最後的時候, 一次性寫完程式碼, 除了幾個分號不小心為中文的, 其餘沒有錯誤, 一次性編譯通過;

真的是十分的爽快;

在sublime上簡單的測試了一下, 發現沒有什麼問題, 便上交PTA;

最後一次AC!

還是太弱, 小題目就花了好幾天;

不過這道題下來, 對連結串列的使用確實有了很大的提升;


最後, 附程式碼:


/**********************/
/*    Title:
        Reversing_Linked_list_v0_4
/*    Author:
        cxy
/*    Start_Date:
        04242018
/*    Finished_Date:
        04242018
/*    FUNCTION:
        主要實現了,給定一系列的資料, 用單鏈表儲存, 而後根據結點資訊, 對應其內部排列關係, 進行給定位數的結點次序反轉。
        一直反轉到無法反轉;
        輸入:
        地址, 資料, 下一節點地址;
        輸出:
        按行:地址, 資料, 下一節點地址;

        具體可見https://pintia.cn/problem-sets/951072707007700992/problems/972813177016877056
/*    Details:
        採用遞迴思想, 重新規劃架構;
        避免前面版本的拖沓;
        無論如何, 都要遍歷一次, 要重新排序;
        就是說, 在遍歷同時, 直接考慮其位置;
        則共需遍歷一次;
        故總體時間複雜度為O(n);
        n為結點地址為-1或找不到為止;
        小於等於連結串列長度;
        空間複雜度, 因有遞迴, 不是很懂, 當K較大時, 遞迴層數較深, 或許會較大;
        但, 不考慮遞迴帶來的影響, S(n);
        n為總連結串列長度;
/**********************/

#include <stdio.h>
#include <stdlib.h>

#define ERROR_FIRST 1
#define ERROR         2
#define OK             3
#define WRONG        0

typedef int STATUS;
typedef struct LL_Node *p_llnode;
typedef struct Detail information;

struct Detail
{
    int Address;
    int Data;
    int Next;
};

struct LL_Node
{
    information node;
    p_llnode link;
};

p_llnode Read_List( int total_num );
p_llnode Reverse_List( p_llnode L, int start_address, int rev_num );
void Print_List( p_llnode L );
void Attach( p_llnode *rear, information INF );
STATUS Sub_Rev_List( p_llnode head, int *Address, int rev_num, p_llnode sub_list_head, p_llnode *sub_list_rear );
p_llnode Get_Needed_Node( p_llnode head, int Address );
void Get_Sub_FIRST_Head( p_llnode p_needed_node, p_llnode sub_list_head, p_llnode *sub_list_rear );
void Head_Insert( p_llnode p_needed_node, p_llnode sub_list_head );
void Rear_Insert( p_llnode p_needed_node, p_llnode *sub_list_rear );
void FREE_Left_Node( p_llnode head );
void Reindex_LLnode( p_llnode L );

int main(int argc, char const *argv[])
{
    p_llnode L = NULL;
    int start_address = 0, total_num = 0, rev_num = 0;

    scanf("%d %d %d", &start_address, &total_num, &rev_num);

    L = Read_List( total_num );
    L = Reverse_List( L, start_address, rev_num );

    Reindex_LLnode( L );
    Print_List( L );

    return 0;
}

p_llnode Read_List( int total_num )
{
    information INF;
    p_llnode head, rear, temp = NULL;

    if ( total_num <= 0)
        return NULL;

    rear = head = (p_llnode)malloc(sizeof(struct LL_Node));

    while ( total_num-- )
    {
        scanf("%d %d %d", &INF.Address, &INF.Data, &INF.Next);
        Attach( &rear, INF );
    }
    rear->link = NULL;

    temp = head;
    head = head->link;
    free(temp);

// test_read
    // temp = head;
    // while ( head )
    // {
    //     printf("%05d %d %05d\n", head->node.Address, head->node.Data, head->node.Next);
    //     head = head->link;
    // }

    return head;
}

// recursion;
p_llnode Reverse_List( p_llnode L, int start_address, int rev_num )
{
    p_llnode head, new_list_head, new_list_rear, sub_list_head, sub_list_rear, temp;
    int Address = start_address;
    int IS_FIRST_SUB_REV = 1;

    new_list_head = new_list_rear = sub_list_head = sub_list_rear = NULL;

    head = (p_llnode)malloc(sizeof(struct LL_Node));
    head->link = L;

    sub_list_head = (p_llnode)malloc(sizeof(struct LL_Node));
    sub_list_head->link = NULL;

    while ( Sub_Rev_List( head, &start_address, rev_num, sub_list_head, &sub_list_rear ) == OK )
    {
        if ( IS_FIRST_SUB_REV )
        {
            IS_FIRST_SUB_REV = 0;
            new_list_head = sub_list_head->link;        // new_list_head不帶頭空結點;
        }
        else
            new_list_rear->link = sub_list_head->link;
            
        new_list_rear = sub_list_rear;

        sub_list_head->link = NULL;
    }

    new_list_rear->link = sub_list_head->link;
    new_list_rear = sub_list_rear;
    // new_list_rear->link = NULL;
    FREE_Left_Node( head );
    free( head );
    free( sub_list_head );

    return new_list_head;
}

void Print_List( p_llnode L )
{
    while ( L->node.Next != -1 )
    {
        printf("%05d %d %05d\n", L->node.Address, L->node.Data, L->node.Next);
        L = L->link;
    }
    printf("%05d %d %d\n", L->node.Address, L->node.Data, L->node.Next);
}

void Attach( p_llnode *rear, information INF )
{
    p_llnode temp;

    temp = (p_llnode)malloc(sizeof(struct LL_Node));

    // temp->node = *INF? 結構體直接賦值, 可能會有問題; 雖然test時是OK的, 此點保留意見;
    temp->node.Address = INF.Address;
    temp->node.Data = INF.Data;
    temp->node.Next = INF.Next;
    temp->link = NULL;

    (*rear)->link = temp;
    *rear = temp;
}

STATUS Sub_Rev_List( p_llnode head, int *Address, int rev_num, p_llnode sub_list_head, p_llnode *sub_list_rear )
{
    p_llnode temp, p_needed_node;
    STATUS rev_status;

    p_needed_node = Get_Needed_Node( head, *Address );
    if ( !p_needed_node )        // Sub_Rev非正常終止訊號; 此時表示所給Address無法指定結點, 也可能為-1;
        return ERROR_FIRST;

    *Address = p_needed_node->node.Next;        // 更新Address;

    if ( rev_num == 1 )    // Sub_Rev正常終止訊號;
    {
        Get_Sub_FIRST_Head( p_needed_node, sub_list_head, sub_list_rear );
        return OK;
    }

    --rev_num;

    rev_status = Sub_Rev_List( head, Address, rev_num, sub_list_head, sub_list_rear );
    switch ( rev_status )
    {
        case ERROR_FIRST:
            Get_Sub_FIRST_Head( p_needed_node, sub_list_head, sub_list_rear );
            return ERROR;

        case ERROR:
            Head_Insert( p_needed_node, sub_list_head );    // 注意! sub_list_head是p_llnode型;
            return ERROR;

        case OK:
            Rear_Insert( p_needed_node, sub_list_rear );    // 注意! sub_list_rear是p_llnode *型;
            return OK;

        default:
            return WRONG;
    }
}

p_llnode Get_Needed_Node( p_llnode head, int Address )
{
    p_llnode p_front_node, temp;

    p_front_node = head;

    while ( p_front_node->link && p_front_node->link->node.Address != Address )
        p_front_node = p_front_node->link;

    if ( !p_front_node->link )
        return NULL;

    temp = p_front_node->link;
    p_front_node->link = temp->link;
    temp->link  = NULL;

    return temp;
}

void Get_Sub_FIRST_Head( p_llnode p_needed_node, p_llnode sub_list_head, p_llnode *sub_list_rear )
{
    *sub_list_rear = sub_list_head->link = p_needed_node;
}

void Head_Insert( p_llnode p_needed_node, p_llnode sub_list_head )
{
    p_needed_node->link = sub_list_head->link;
    sub_list_head->link = p_needed_node;
}

void Rear_Insert( p_llnode p_needed_node, p_llnode *sub_list_rear )
{
    (*sub_list_rear)->link = p_needed_node;
    *sub_list_rear = p_needed_node;
}

void FREE_Left_Node( p_llnode head )
{
    p_llnode temp;

    while ( head->link )
    {
        temp = head->link;
        head->link = temp->link;
        free(temp);
    }
}

void Reindex_LLnode( p_llnode L )
{
    while ( L->link )
    {
        L->node.Next = L->link->node.Address;
        L = L->link;
    }
    L->node.Next = -1;
}



                                                                                                            04252018-22:06---第一次