这题是把n个结点的链表,每k个数反转,而且最后不足k个数不反转。
比如给定L为1→2→3→4→5→6,K为3,则输出应该为3→2→1→6→5→4;如果K为4,则输出应该为4→3→2→1→5→6
然后这里的链表给出结点地址,数据,及下一节点的地址,格式如下
00000 4 99999
一开始没思路,自己写了个很烂的代码,只能通过一个case。后来搜索解题思路,大致是用一个数组存入所有结点,然后按起始地址,顺序重排所有结点,最后每k个结点反转。
用一个结构体来定义结点
typedef struct
{
int addr;
int data;
int next;
}List,*pList;
数组用new申请一个堆空间,因为题目结点上限是10w个
pList pl = new List[100000]();
数据输入部分用scanf提高时间效率
然后按每个节点的起始地址存入到数组中,好处是可以利用数组O(1)的复杂度,瞬间访问到某个结点,而不用遍历整个数组
List t; for ( i=0 ; i < n ; ++ i ) { scanf("%d%d%d",&t.addr,&t.data,&t.next); pl[t.addr]=t; }
按链表起始结点,让所有结点有序,直到最后一个结点,这里用了STL的Vector数据结构存储有序的链表
vector<List> v; while(beg!=-1) { v.push_back(pl[beg]); beg=pl[beg].next;//更新为下一节点的起始地址 }
翻转链表,就是把k个结点入栈,再出栈存到新的向量中;如果剩余不足k个数,则顺序存入向量中
记得还要修正next地址,就是让翻转后的链表结点next地址正确。这一步不必在翻转的代码中做,只要在最后打印输出的时候,把next地址修改为下一节点的起始地址
完整代码如下
#include <iostream> #include <vector> #include <stack> #include <stdio.h> using namespace std; typedef struct { int addr; int data; int next; }List,*pList; int main() { vector<List> v,v2; pList pl = new List[100000]();//用一个数组存储数据 List t; int beg; int n,k,i; cin >> beg >> n >> k; for ( i=0 ; i < n ; ++ i ) { //cin >> pl[i].addr >> pl[i].data >> pl[i].next ; scanf("%d%d%d",&t.addr,&t.data,&t.next); pl[t.addr]=t;//让每个节点的起始地址直接作为数组的下标 } if(beg == -1) //首地址为-1.直接输出 { printf("-1\n"); return 0; } //用一个vector按开始地址顺序存储链表,否则用暴力法双重循环查找链表的起始地址超时 while(beg!=-1) { v.push_back(pl[beg]); beg=pl[beg].next;//更新为下一节点的起始地址 } //每k个一组,将向量数据入栈,再出栈,存入新的向量 //auto it = v.begin(); vector<List>::iterator it=v.begin(); for ( ; it != v.end() ; ) { stack<List> s; if(v2.size()+k <= v.size())//要有k个数才逆转链表 { for (i=0;i<k;++i) { s.push(*it); ++it; } while(!s.empty()) { List temp = s.top(); s.pop(); v2.push_back(temp); } }else{ v2.push_back(*it);//小于k个数,不逆转,直接存入向量 ++it; } } //输出 it = v2.begin(); for ( ; it != v2.end()-1 ; ++it) { it->next=(it+1)->addr;//修正逆转后的链表的next地址 printf("%05d %d %05d\n" , it->addr ,it->data ,it->next); } it->next=-1; printf("%05d %d %d\n" , it->addr ,it->data ,it->next); return 0; }