MOOC 陈姥姥的数据结构作业题
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=3K = 3, then you must output 3→2→1→6→5→4; if K=4K = 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 NN (≤105≤10^5) which is the total number of nodes, and a positive KK (≤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.
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
核心:
1.用结构数组模拟链表
2.核心的逆序怎么做
我在听完陈姥姥详细的解题思路后还是困惑了一段时间,用数组下标代替指针后,具体的操作细节和边界要怎么处理;
最后我觉得给数组+1个单元作为链表的空表头,用来模拟指针链表的空表头,后面按照指针的操作具体到下标操作上,思路和步骤都会很清晰
即数组为100001个 而不是100000个
程序大概流程:
/*
1.开一个100001大小的结构数组Array,数组的下标index 就是对应结点的地址,结点中的.Next存储着链表中的下一个结点地址,即在数组中的下标。Array[0]~Array[99999]用来存储给定的数据,最后一个Array[100000] 作为整个链表的空表头,Array[100000].Next存储链表的第一个结点的数组下标
2.读入给定的数据,首地址存入Array[100000].Next,结点个数N,每次逆序的结点个数K; 之后的每行数据根据给出的下标存入对应的结构数组中:比如12309 2 33128 存入Array[12309]中
3.由于陈姥姥挖的坑 给定的结点个数N,并不都在链表上,所以要遍历链表求得链表的实际结点数numofList;进而 得出需要逆序的次数count = numofList/K;
4.写逆序函数
*/
具体看代码(c语言):
#include <stdio.h>
#define index int
#define MaxSize 100001
#define head 100000
typedef struct _Node{
int Data;
index Next;
}Node;
void Reverse( Node* Array,int K,int count );
int main()
{
Node Array[MaxSize]; //连续的结构数组,其中的一部分组成链表
scanf("%d",&Array[head].Next); //Array[100000]作为链表的空表头,它的.Next是链表第一个元素的数组下标
int i,N,K,idx;
scanf("%d %d",&N,&K);
for(i=0;i<N;i++){ //读入数据放入对应的结构数组单元
scanf("%d",&idx);
scanf("%d %d",&Array[idx].Data,&Array[idx].Next);
}
int numofList=0; //链表中实际的单元个数,不是所有读入的单元都在链表上【这里是陈姥姥挖的坑】
index p = Array[head].Next;
while(p!=-1){
numofList++;
p = Array[p].Next;
}
int count = numofList/K; //每K个做一次逆序 需要做几次逆序
Reverse( Array,K,count ); //传数组的地址进去
p = Array[head].Next; //输出 最后一个结构.Next = -1;不能直接输出-0001 需要特殊处理
while( p != -1 ){
if( Array[p].Next != -1 ){
printf("%05d %d %05d\n",p,Array[p].Data,Array[p].Next);
}else{
printf("%05d %d %d\n",p,Array[p].Data,Array[p].Next);
}
p = Array[p].Next;
}
return 0;
}
void Reverse( Node* Array,int K,int count )
{
index rear = head;//每次逆序后的尾巴 把新逆序后的链表接上 第一次是空表头
index New,Old,Temp;
while(count--){
New = Array[rear].Next;
Old = Array[New].Next;
int cnt = 1;
while(cnt<K){ //逆序的核心步骤,New指向第一个 Old指向第二个 Temp临时保存Old->Next 即第三个
Temp = Array[Old].Next;
Array[Old].Next = New;
New = Old;
Old = Temp; //每次逆序后New Old 后移1位 继续逆序
cnt++;
}
Temp = Array[rear].Next; //逆序完成后的收尾工作
Array[Array[rear].Next].Next = Old;//逆序的这一段的第一个依然还是指向第二个 需要指向后面还没有逆序的第一个
Array[rear].Next = New; //需要把前面尾巴指向新逆序后第一个
rear = Temp; //新的 逆序后的尾巴 用来接上下次逆序后的第一个元素
}
}
比第一次写的清晰很多,简洁不少,提交全红的时候还是很开心的,数据结构这门课真的很锻炼思维,前路漫漫,诸君共勉。