PTA 5-2 Reversing Linked List (25) [法一] - 线性表 - 链表反转 (PAT 1074)

题目:http://www.patest.cn/contests/pat-a-practise/1074

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, 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.

Sample Input:

00100 6 4         //第一行:链表的首地址add,结点个数n,每隔k个进行一次反转
00000 4 99999     //后面n行:结点的地址address,数据data,下一个结点的地址next
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

题目大意:

反转单链表,给定常数K和单链表L,要求按每K个节点反转单链表,如:L: 1->2->3->4->5->6 K=3,输出:3->2->1->6->5->4,如果K=4,输出:4->3->2->1->5->6.

特殊情况:

1. 有其他链表干扰(即有多个-1出现):找链表有效长度

2. k=1 或者 k=n :不变 或者 全部逆序

3. 需逆序的起点大于有效长度 : 直接输出原链表

  推荐测试:

1. k=1或者k=n:

00100 6 6
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 00000
99999 5 68237
12309 2 33218

2. 有其他链表干扰(即有多个-1出现):

00100 6 2
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 -1
99999 5 68237
12309 2 33218

 – 定义结构

struct Node {
    int iData;
    int iNext;
};
const int iMaxLen = 100004;
int iHead; //!首地址
int N, K;
Node NodeList[iMaxLen];
 – paixu():

1. 找有效长度:判断next是否遇到-1
2. 若需逆序的起点 > 有效长度(k > iEffectiveLength):doPrint(iHead)
3. 更新结点总数 N 为有效长度 iEffectiveLength

K>1:
4. 初始化新链表(反转后)的首尾地址

// iNewHead,iLastTail 表示新链表(反转后)的首尾地址
// iTheHead,iTheTail 表示链表中反转的每一小节的开头和结尾
reverseK(iHead, K, &iTheHead, &iTheTail);
iNewHead = iTheHead;
iLastTail = iTheTail;

5. 计算反转次数:

iReserveCount = N/K – 1

6. 每K个翻转一次

for(int i = 0; i < iReverseCount; ++i) {
    reverseK(NodeList[iTheTail].iNext, K, &iTheHead, &iTheTail);
        NodeList[iLastTail].iNext = iTheHead;
        iLastTail = iTheTail;
}

K<=1:

iNewHead = iHead;

7.输出链表:

doPrint(iNewHead);
 – reverseK():

从 iStartHead 开始反转k个元素(原理即单链表反转)

int reverseK(int iStartHead, int iK, int *pHead, int *pTail)
//iStartHead:每一小节开始反转的结点
//node1,node2,nodeTmp:可看作反转所需的三个指针
完整代码:
#include <cstdio>
struct Node {
    int iData;
    int iNext;
};
const int iMaxLen = 100004;
int iHead; //!首地址
int N, K;
Node NodeList[iMaxLen];

void doPrint(int iNodeAdd)
{
    while(iNodeAdd!=-1){
        if(NodeList[iNodeAdd].iNext == -1){
            printf("%.5d %d -1\n",iNodeAdd,NodeList[iNodeAdd].iData);
            break;
        }
        printf("%.5d %d %.5d\n",iNodeAdd, NodeList[iNodeAdd].iData, NodeList[iNodeAdd].iNext);
        iNodeAdd = NodeList[iNodeAdd].iNext;
    }
}
//!从iStartHead开始反转k个元素
int reverseK(int iStartHead, int iK, int *pHead, int *pTail)
{
    //!只有一个节点
    if(-1 == iStartHead || iK <= 1)
        return -1;
    if(2 == iK){
        int node1 = iStartHead;
        int node2 = NodeList[iStartHead].iNext;
        NodeList[node1].iNext = NodeList[node2].iNext;
        NodeList[node2].iNext = node1;
        *pHead = node2;
        *pTail = node1;
        return 0;
    }
    *pTail = iStartHead;
    int node1 = iStartHead;
    int node2 = NodeList[iStartHead].iNext;
    int nodeTmp = -1;
    for(int i = 0; i < iK - 1; ++i){
        nodeTmp = NodeList[node2].iNext;
        NodeList[node2].iNext = node1;
        node1 = node2;
        node2 = nodeTmp;
    }
    *pHead = node1;
    NodeList[*pTail].iNext = node2;
    return 0;
}
void paixu() {
    int iNodeTmp = iHead;
    //!找有效结点的长度:即判断next是否遇到-1
    int iEffectiveLength = 1;
    while(-1 != NodeList[iNodeTmp].iNext) {
        ++iEffectiveLength;
        iNodeTmp = NodeList[iNodeTmp].iNext;
    }
    //!需逆序的起点大于有效长度
    if(K > iEffectiveLength){
        //!直接输出当前没有逆序的结点
        doPrint(iHead);
    }
    //!有效长度覆盖输入的结点总个数
    N = iEffectiveLength;

    int iNewHead;
    if(K > 1) {
        int iTheHead, iTheTail;
        int iLastTail;
        //!first init reverse to decide the new head
        reverseK(iHead, K, &iTheHead, &iTheTail);
        iNewHead = iTheHead;
        iLastTail = iTheTail;
                        
        int iReverseCount = N / K - 1;  //!反转次数       
        for(int i = 0; i < iReverseCount; ++i) {
            reverseK(NodeList[iTheTail].iNext, K, &iTheHead, &iTheTail);
            NodeList[iLastTail].iNext = iTheHead;
            iLastTail = iTheTail;
        }
    }
    else
        iNewHead = iHead;
    doPrint(iNewHead);
}
int main() {
    //!初始化 data和next都初始化为0
    for(int i = 0; i < iMaxLen; ++i) {
        NodeList[i].iData = 0;
        NodeList[i].iNext = -1;
    }
    //!输入首地址,结点总数,需逆序到的数
    scanf("%d %d %d", &iHead, &N, &K);
    int iSingleNodeAddress, iSingleNodeData, iSingleNodeNext;
    for(int i = 0; i < N; ++i) {
        scanf("%d %d %d", &iSingleNodeAddress, &iSingleNodeData, &iSingleNodeNext);
        NodeList[iSingleNodeAddress].iData = iSingleNodeData;
        NodeList[iSingleNodeAddress].iNext = iSingleNodeNext;
    }
    paixu();
    return 0;
}
    原文作者:claremz
    原文地址: https://www.cnblogs.com/claremore/p/4802164.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞