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
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---第一次