Reversing Linked List
题目要求:
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.
输入格式:
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
输出格式:
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
输出样例:
00000 4 33218
33218 3 12309
12309 2 00100
00100 1 99999
99999 5 68237
68237 6 -1
解题思路:
- 用数组下标来表示结点位置,从而方便的表示对应位置的结点。
- 将链表以K为界划分为若干子链,将每个子链反转,然后衔接左右的子链。
- 反转子链的方法:用head和tail头尾指针,分别指向待反转子链的头尾,固定tail不动,将头依次插到tail后面(期间要多用到一个p指针记录位置 )。
注意:
- 给出的结点不一定所有的结点都是链表的成员结点(可能有多余结点)。
- 中间的子链要衔接上一个子链的尾,也要衔接下一个子链的头 。
- 需要考虑到的情况:如果K=1,链表不反转;如果K等于链表的节点数,链表整个反转;如果链表的节点数能被K整除,则每段都要反转。
完整程序:
/*【解题思路】
1.用数组下标来表示结点位置,从而方便的表示对应位置的结点
2.将链表以K为界划分为若干子链,将每个子链反转,然后衔接左右的子链
3.反转子链的方法:用head和tail头尾指针,分别指向待反转子链的头尾,固定tail不动,将头依次插到tail后面(期间要多用到一个p指针记录位置)
1 -> 2 -> 3 -> 4 变为 2 -> 3 -> 4 -> 1 变为 3 -> 4 -> 2 -> 1 变为 4 -> 3 -> 2 -> 1
*/
/*【注意】
1.给出的结点不一定所有的结点都是链表的成员结点(可能有多余结点)
2.中间的子链要衔接上一个子链的尾,也要衔接下一个子链的头
3.需要考虑到的情况:如果K=1,链表不反转;如果K等于链表的节点数,链表整个反转;如果链表的节点数能被K整除,则每段都要反转
*/
#include <stdio.h>
#define MAXSIZE 100001
typedef struct Node {
int data; // 值
int next; // 下一个结点的地址(五位十进制数编码地址,并非真正的地址)
} Node;
Node List[MAXSIZE];
int Reverse(int fp,int K); // 反转函数
int main()
{
int fp,p,N,K; // fp:first position 表示首地址,p表示地址,N表示结点数,K表示子链长度
scanf("%d %d %d",&fp,&N,&K);
for(int i = 0;i < N;i ++) {
scanf("%d",&p);
scanf("%d %d",&List[p].data,&List[p].next);
}
int NList; // NList:New List 表示新链表,即反转后的链表,实际上是反转后的链表的第一个结点的地址(五位数地址)
NList = Reverse(fp,K);
p = NList;
while(List[p].next != -1) {
printf("%05d %d %05d\n",p,List[p].data,List[p].next);
p = List[p].next;
}
printf("%05d %d %d\n",p,List[p].data,List[p].next);
}
int Reverse(int fp,int K)
{
// head指向子链的头结点,tail指向子链的尾结点,NHead指向反转后的链表的第一个结点
int head = fp,tail = fp,NHead; // 先将head和tail都置于第一个结点处
int k = K;
/*将tail移动k - 1位到子链的尾结点*/
while(tail != -1 && k != 1) {
tail = List[tail].next;
k --;
}
k = K; // 更新k
if(tail != -1) NHead = tail; // 第一个子链的尾结点就是反转后的链表的第一个结点
/*下面进行反转子链操作*/
while(tail != -1) {
int p = head; // 用p记录要移动的结点,解放出head,从而让head指向下一个head(移动一个结点后的新head)
while(head != tail) {
head = List[p].next;
List[p].next = List[tail].next; // 衔接到下一个子链(此时衔接的是未反转的下一个链的链头)
List[tail].next = p;
p = head; // 此时已经完成一个结点的移动操作,将p指向下一个要移动的结点
}
// 此时已经完成了一个子链的反转操作,head = tail = p,均指向新子链的第一个结点
while(k != 1) { // 将p移动k - 1位指向新子链链尾,用来衔接下一个反转链链头(用来衔接下一个子链反转后的链头)
p = List[p].next;
k --;
}
/*接下来更新head和tail,让它们均指向下一个待反转子链的第一个结点*/
head = List[p].next;
tail = List[p].next;
k = K; // 更新k
/*将tail移动k - 1位到子链的尾结点*/
while(tail != -1 && k != 1) {
tail = List[tail].next;
k --;
}
k = K; // 更新k
if(tail != -1) List[p].next = tail; // 用来衔接上一个子链的链尾
}
return NHead;
}