1025 反转链表

题目

给定一个常数 K 以及一个单链表 L,请编写程序将 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,即最后不到 K 个元素不反转。

输入格式
每个输入包含 1 个测试用例。每个测试用例第 1 行给出第 1 个结点的地址、结点总个数正整数 N (≤10^5)、以及正整数 K (≤N),即要求反转的子链结点的个数。结点的地址是 5 位非负整数,NULL 地址用 −1 表示。

接下来有 N 行,每行格式为:

Address Data Next

其中 Address 是结点地址,Data 是该结点保存的整数数据,Next 是下一结点的地址。

输出格式

对每个测试用例,顺序输出反转后的链表,其上每个结点占一行,格式与输入相同。

输入样例:

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

解析

  如果你想到了用数组下标来表示结点地址,结构体里保存数据和next,恭喜你,离AC又远了一点
  这题最好将三个数据都放进结构体,方便输出,不用管next到底是谁,只用输出结构体数组里边的下一个结点的地址就可以
  当然这个结构体数组是经过反转后的数组
  首先我们需要将乱序输入的结点根据地址和next,顺序放进结构体数组,必要的过程,可以过滤掉无效结点
  然后利用reverse()反转结构体数组的元素,最后遍历一遍输出即可

答案

如何将乱序的 顺序存储起来呢?

暴力法

int SNode(int x){
    for( int i = 0 ; i < 999999 ; i ++ ){
        if( node[i].add == x){
            return i;
        }
    }
}
while (a != -1){
    re[i] = node[SNode(a)]; //串好放进re
    a = re[i].next; 
    i++;
}

可以说非常暴力,就连加过的结点还遍历一遍,遗憾的是超时了

索性不在这上面优化了,重写淦~

新方法就是将结点新加一个数据保存自己位置的同时,用数组下标直接表示地址,可以不用查找O(1)时间完成排序

for(i = s ; i != -1 ; i = node[i].next){
        re[a++] = node[i];
        num ++ ;  //num 用来计数真正在链表上的点
}

这样就可以啦,效果还不错,当然还有其他方法,这里就不写啦!

AC代码

#include <iostream>
#include<algorithm>
#include <string>
#include <stdio.h>
using namespace std;

struct Node{
    int add;
    int data;
    int next;
}node[100001],re[100001];

int s,n,m;
int main(){
    cin>>s>>n>>m;
    int c=0,num = 0,k;
    for(int i = 0 ; i < n ; i ++){
        int add;
        scanf("%d",&add);
        scanf("%d%d",&node[add].data,&node[add].next);
        node[add].add = add;
    }
    int a = 0,i;
    for(i = s ; i != -1 ; i = node[i].next){
        re[a++] = node[i];
        num ++ ;  //num 用来计数真正在链表上的点
    }//优化后的
    k = num;
    while( k - m >= 0 && m > 0 ){
        reverse( re + c * m,re + ( c + 1 ) * m );
        c ++;
        k = k -m;   
    }
    for(int i = 0 ; i < num ; i ++){
        if(i == num -1 ){
            printf("%05d %d -1\n",re[i].add,re[i].data,re[i].next);
        }else{
            printf("%05d %d %05d\n",re[i].add,re[i].data,re[i+1].add);
        }    
    }
}

这里附上用解析1中方法,模拟链表头插法实现全逆转的代码

#include <iostream>
#include<algorithm>
#include <string>
#include <stdio.h>
using namespace std;

struct Node{

    int data;

    int next;

}node[100000],re[100000];


int main(){
    int s,n,add,m,nadd;
    cin >> s >> n >> m;

    for(int i = 0 ; i < n ; i ++){
        scanf("%d",&add);
        scanf("%d%d",&node[add].data,&node[add].next);
    }
    add = s;
    re[s].data = node[s].data;    
    re[s].next = -1;

    for(int i = 1 ; i <= n ;i ++){ //头插法插入re

        nadd = node[add].next;

        re[nadd] = node[nadd];

        re[nadd].next = add;

        if(nadd == -1) break;

        add = nadd;
    }
    for(int i = add ; i != -1; i = re[i].next){
        if(re[i].next == -1){
            printf("%05d %d %d\n",i,re[i].data,re[i].next);
        }else{
            printf("%05d %d %05d\n",i,re[i].data,re[i].next);
        }   
    }
} 

仅能实现全逆转,不能分段逆转,我一度以为要成功了,但是紧接着就傻眼了,放上来供着👌

posted @ 2020-08-05 01:59  小马小马最可爱  阅读(254)  评论(0)    收藏  举报