目录

说明:

1110 区块反转

输入格式:

输出格式:

输入样例:

输出样例:

1105 链表合并

输入格式:

输出格式:

输入样例:

输出样例:

1025 反转链表

输入格式:

输出格式:

输入样例:

输出样例:

1075 链表元素分类

输入格式:

输出格式:

输入样例:

输出样例:

7-11 链表去重

输入格式:

输出格式:

输入样例:

输出样例:

L2-022 重排链表

输入格式:

输出格式:

输入样例:

输出样例:

总结:


说明:

此文章对pat上有关链表的一类题做了一个总结(主要来自乙级和天梯赛训练题集),以下题目解题思路均借鉴永远有多远博主的博客(可以通过下面链接去博主里面看各个题目)L2-002 链表去重 (25 分) C++_永远有多远.的博客-CSDN博客_链表去重 c++查了很多题解,个人认为这个思路是新颖易理解的,用结构体数组来模拟链表,在链表中比较难实现的操作利用数组就很容易实现,故总结于此,并加上自己对代码的理解(可见注释)。

1110 区块反转

给定一个单链表 L,我们将每 K 个结点看成一个区块(链表最后若不足 K 个结点,也看成一个区块),请编写程序将 L 中所有区块的链接反转。例如:给定 L 为 1→2→3→4→5→6→7→8,K 为 3,则输出应该为 7→8→4→5→6→1→2→3。

输入格式:

每个输入包含 1 个测试用例。每个测试用例第 1 行给出第 1 个结点的地址、结点总个数正整数 N (≤105)、以及正整数 K (≤N),即区块的大小。结点的地址是 5 位非负整数,NULL 地址用 −1 表示。

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

Address Data Next

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

输出格式:

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

输入样例:

00100 8 3
71120 7 88666
00000 4 99999
00100 1 12309
68237 6 71120
33218 3 00000
99999 5 68237
88666 8 -1
12309 2 33218

输出样例:

71120 7 88666
88666 8 00000
00000 4 99999
99999 5 68237
68237 6 00100
00100 1 12309
12309 2 33218
33218 3 -1

AC:

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
struct node
{int address;int data;int next;
}s[N];
int main()
{//输入int start,n,k;cin>>start>>n>>k;for(int i=0;i<n;i++){int addr;cin>>addr;cin>>s[addr].data>>s[addr].next;}vector<int> v;//数组来存地址for(int i=start;i!=-1;i=s[i].next)v.push_back(i);//遍历链表,将地址存到数组中for(int i=0;i<v.size();i+=k) //先部分旋转,i+=k表示k个一旋转reverse(v.begin()+i,min(v.begin()+i+k,v.end()));//用reverse来选转,k个一旋转,如果最后不满足k个,则到结尾有几个旋转几个reverse(v.begin(),v.end());//再整体一旋转 就到达了效果
//输出for(int i=0;i<v.size()-1;i++)printf("%05d %d %05d\n",v[i],s[v[i]].data,v[i+1]);//%05d用来填充,v[i]里面存储的是本元素的地址,s[v[i]].data存储本元素数据值,v[i+1]存下一个地址printf("%05d %d -1\n",v[v.size()-1],s[v[v.size()-1]].data);}

1105 链表合并

给定两个单链表 L1​=a1​→a2​→⋯→an−1​→an​ 和 L2​=b1​→b2​→⋯→bm−1​→bm​。如果 n≥2m,你的任务是将比较短的那个链表逆序,然后将之并入比较长的那个链表,得到一个形如 a1​→a2​→bm​→a3​→a4​→bm−1​⋯ 的结果。例如给定两个链表分别为 6→7 和 1→2→3→4→5,你应该输出 1→2→7→3→4→6→5。

输入格式:

输入首先在第一行中给出两个链表 L1​ 和 L2​ 的头结点的地址,以及正整数
N (≤105),即给定的结点总数。一个结点的地址是一个 5 位数的非负整数,空地址 NULL 用 -1 表示。

随后 N 行,每行按以下格式给出一个结点的信息:

Address Data Next

其中 Address 是结点的地址,Data 是不超过 105 的正整数,Next 是下一个结点的地址。题目保证没有空链表,并且较长的链表至少是较短链表的两倍长。

输出格式:

按顺序输出结果链表,每个结点占一行,格式与输入相同。

输入样例:

00100 01000 7
02233 2 34891
00100 6 00001
34891 3 10086
01000 1 02233
00033 5 -1
10086 4 00033
00001 7 -1

输出样例:

01000 1 02233
02233 2 00001
00001 7 34891
34891 3 10086
10086 4 00100
00100 6 00033
00033 5 -1

 AC:

#include<bits/stdc++.h>
using namespace std;const int N = 1e5+10;struct node
{int address;int  data;int  next;
}s[N];int main()
{//输入int start1, start2, n;cin >> start1 >> start2 >> n;for (int i = 0; i < n; i++) {int addr;cin >> addr;cin >> s[addr].data >> s[addr].next;}
//设两个数组来存两个链表的地址vector<int>v1, v2;for (int i = start1; i != -1; i = s[i].next) {v1.push_back(i);}for (int i = start2; i != -1; i = s[i].next) {v2.push_back(i);}if (v1.size() < v2.size()) swap(v1, v2);//将v1一直为较长的那条链表if (v1.size() >= v2.size() * 2) reverse(v2.begin(), v2.end()); //如果 n≥2m(v1的长度大于v2的),你的任务是将比较短的那个链表逆序(逆序仍利用的reverse)
//长的链表两个元素之后插入一个短链表中的元素int cnt = 0, tmp = 0;for (int i = 0; i < v1.size(); i++) {//遍历长链表cnt++;if (cnt == 3 && tmp < v2.size()) {//在长链表的两个元素之后也就是第三个位置插入cnt = 0;//赋值为0,重新开始计数v1.insert(v1.begin() + i, v2[tmp++]);//insert函数,v2中的元素插入相应位置}}
//n=2m的情况,tmp不等于v2.size(),也就省最后一个了直接把那元素压入到v1数组最后if (tmp != v2.size()) v1.push_back(v2[tmp++]);
//遍历合并后的链表进行输出for (int i = 0; i < v1.size() - 1; i++) {printf("%05d %d %05d\n", v1[i], s[v1[i]].data, v1[i + 1]);}printf("%05d %d -1\n", v1[v1.size() - 1], s[v1[v1.size() - 1]].data);return 0;
}

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 (≤105)、以及正整数 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

 AC:

#include<bits/stdc++.h>
using namespace std;const int N = 1e5+10;struct node
{int address;int data;int next;
}s[N];int main()
{//输入int start, n, k;cin >> start >> n >> k;for (int i = 0; i < n; i++) {int addr;cin >> addr;cin >> s[addr].data >> s[addr].next;s[addr].address = addr;}vector<int> v;//遍历链表,将地址存到vector数组for (int i = start; i != -1; i = s[i].next) {v.push_back(i);}
//v.size()-v.size()%k来控制有几个k来旋转,i+=k表示k个一旋转for (int i = 0; i < (v.size() - v.size() % k); i += k) {reverse(v.begin() + i, v.begin() + i + k);//i=0开始,左闭右开 所以是+i+k}
//输出for (int i = 0; i < v.size(); i++) {if (i != v.size() - 1) {printf("%05d %d %05d\n", v[i], s[v[i]].data, v[i + 1]);}else {printf("%05d %d -1\n", v[i], s[v[i]].data);}}return 0;
}

1075 链表元素分类

给定一个单链表,请编写程序将链表元素进行分类排列,使得所有负值元素都排在非负值元素的前面,而 [0, K] 区间内的元素都排在大于 K 的元素前面。但每一类内部元素的顺序是不能改变的。例如:给定链表为 18→7→-4→0→5→-6→10→11→-2,K 为 10,则输出应该为 -4→-6→-2→7→0→5→10→18→11。

输入格式:

每个输入包含一个测试用例。每个测试用例第 1 行给出:第 1 个结点的地址;结点总个数,即正整数N (≤105);以及正整数K (≤103)。结点的地址是 5 位非负整数,NULL 地址用 −1 表示。

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

Address Data Next

其中 Address 是结点地址;Data 是该结点保存的数据,为 [−105,105] 区间内的整数;Next 是下一结点的地址。题目保证给出的链表不为空。

输出格式:

对每个测试用例,按链表从头到尾的顺序输出重排后的结果链表,其上每个结点占一行,格式与输入相同。

输入样例:

00100 9 10
23333 10 27777
00000 0 99999
00100 18 12309
68237 -6 23333
33218 -4 00000
48652 -2 -1
99999 5 68237
27777 11 48652
12309 7 33218

输出样例:

33218 -4 68237
68237 -6 48652
48652 -2 12309
12309 7 00000
00000 0 99999
99999 5 23333
23333 10 00100
00100 18 27777
27777 11 -1

AC: 

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
struct node
{int data;int address;int next;
}s[N];
int main()
{//输入int start1,n,k;cin>>start1>>n>>k;for(int i=0;i<n;i++){int addr;cin>>addr;cin>>s[addr].data>>s[addr].next;}vector<int> v1;//用数组来存链表中的地址for(int i=start1;i!=-1;i=s[i].next){if(s[i].data<0)//按照顺序进行遍历 如果是负数就先放入数组中(也就是链表里)v1.push_back(i);}for(int i=start1;i!=-1;i=s[i].next){if(s[i].data<=k&&s[i].data>=0)//按照顺序进行遍历,如果数值在[0,k]之间在后面依次放进数组里v1.push_back(i);}for(int i=start1;i!=-1;i=s[i].next){if(s[i].data>k)//按照顺序进行遍历,最后将大于k的数值放在k后面v1.push_back(i);}
//输出for(int i=0;i<v1.size()-1;i++)printf("%05d %d %05d\n",v1[i],s[v1[i]].data,v1[i+1]);printf("%05d %d -1",v1[v1.size()-1],s[v1[v1.size()-1]].data);}

7-11 链表去重

给定一个带整数键值的链表 L,你需要把其中绝对值重复的键值结点删掉。即对每个键值 K,只有第一个绝对值等于 K 的结点被保留。同时,所有被删除的结点须被保存在另一个链表上。例如给定 L 为 21→-15→-15→-7→15,你需要输出去重后的链表 21→-15→-7,还有被删除的链表 -15→15。

输入格式:

输入在第一行给出 L 的第一个结点的地址和一个正整数 N(≤105,为结点总数)。一个结点的地址是非负的 5 位整数,空地址 NULL 用 -1 来表示。

随后 N 行,每行按以下格式描述一个结点:

地址 键值 下一个结点

其中地址是该结点的地址,键值是绝对值不超过104的整数,下一个结点是下个结点的地址。

输出格式:

首先输出去重后的链表,然后输出被删除的链表。每个结点占一行,按输入的格式输出。

输入样例:

00100 5
99999 -7 87654
23854 -15 00000
87654 15 -1
00000 -15 99999
00100 21 23854

输出样例:

00100 21 23854
23854 -15 99999
99999 -7 -1
00000 -15 87654
87654 15 -1

AC:

#include <bits/stdc++.h>
using namespace std;const int MAXN = 100000;struct node
{int data, next;
}nodep[MAXN];int flag[MAXN] = { 0 };int main()
{//输入int node1, n;cin >> node1 >> n;for (int i = 0; i < n; i++) {int temp;cin >> temp;cin >> nodep[temp].data >> nodep[temp].next;}memset(flag, 0, sizeof(flag));//初始化为0vector<int>v1, v2;//定义两个数组来存两个链表for (int i = node1; i != -1; i = nodep[i].next) {if (flag[abs(nodep[i].data)] == 0) {//flag数组来进行标记,flag=0,只有第一个绝对值等于 K 的结点被保留flag[abs(nodep[i].data)] = 1;//标记为1,剩下的就存到新的链表v1.push_back(i);//将不重复的点存到v1中}else {v2.push_back(i);//将绝对值重复的结点地址存到另一条链表中}}
//输出不重复的链表printf("%05d %d ", v1[0], nodep[v1[0]].data);for (int i = 1; i < v1.size(); i++) {printf("%05d\n%05d %d ", v1[i], v1[i], nodep[v1[i]].data);}printf("-1\n");
//如果有绝对值相同的,链表长度不为0,则输出另一条链表if (v2.size()) {printf("%05d %d ", v2[0], nodep[v2[0]].data);for (int i = 1; i < v2.size(); i++) {printf("%05d\n%05d %d ",v2[i], v2[i], nodep[v2[i]].data);}printf("-1\n");}
}

L2-022 重排链表

给定一个单链表 L1​→L2​→⋯→Ln−1​→Ln​,请编写程序将链表重新排列为 Ln​→L1​→Ln−1​→L2​→⋯。例如:给定L为1→2→3→4→5→6,则输出应该为6→1→5→2→4→3。

输入格式:

每个输入包含1个测试用例。每个测试用例第1行给出第1个结点的地址和结点总个数,即正整数N (≤105)。结点的地址是5位非负整数,NULL地址用−1表示。

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

Address Data Next

其中Address是结点地址;Data是该结点保存的数据,为不超过105的正整数;Next是下一结点的地址。题目保证给出的链表上至少有两个结点。

输出格式:

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

输入样例:

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

输出样例:

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

AC: 

#include<bits/stdc++.h>
using namespace std;const int MAXN = 100000;struct node
{int address, data, next;
}nodep[MAXN];int main()
{//输入int address1, n;cin >> address1 >> n;for (int i = 0; i < n; i++) {int address;cin >> address;cin >> nodep[address].data >> nodep[address].next;nodep[address].address = address;}vector<int>s, ans;//将题目要求的结点的地址顺序存在ans中,后面按题目要求统一输出for (int i = address1; i != -1; i = nodep[i].next) {s.push_back(i);//遍历链表时按照题目要求进行遍历 并将每个结点的地址放入s中}int l = 0, r = s.size() - 1;//l, r表示将要输出的结点位置,
// 当(r + 1) - (l - 1) == 1 时 已经都遍历了一遍 此时退出循环while (1) {//先输出最右边 输出之后r--往左移 再输出最左边,输出后 l++ans.push_back(s[r]);//将按照题目顺序遍历的地址存到答案链表中r--;if ((r + 1) - (l - 1) == 1) break;ans.push_back(s[l]);l++;if ((r + 1) - (l - 1) == 1) break;}
//输出答案链表for (int i = 0; i < ans.size(); i++) {if (i != ans.size() - 1) {printf("%05d %d %05d\n", ans[i], nodep[ans[i]].data, ans[i + 1]);}else {printf("%05d %d -1\n", ans[i], nodep[ans[i]].data);}}
}

总结:

这一类问题开头存储变量方式以及输入都是如下

#include <bits/stdc++.h>
using namespace std;const int MAXN = 100000;struct node
{int address, data, next;//其实结构体里只有data和next就行  后面就用不到结构体里的address了,有新的变量去存储了}nodep[MAXN];int main()
{//根据题目进行相关输入int address1, n;cin >> address1 >> n;for (int i = 0; i < n; i++) {int address;cin >> address;cin >> nodep[address].data >> nodep[address].next;nodep[address].address = address;}vector<int>s, ans;//for (int i = address1; i != -1; i = nodep[i].next) {//遍历链表s.push_back(i)

输出为如下:

 for (int i = 0; i < ans.size(); i++) {if (i != ans.size() - 1) {printf("%05d %d %05d\n", ans[i], nodep[ans[i]].data, ans[i + 1]);}//%05d用来填充,ans[i]里面存储的是本元素的地址,nodep[ans[i]].data存储本元素数据值,ans[i+1]存下一个地址else {printf("%05d %d -1\n", ans[i], nodep[ans[i]].data);}}

然后重要的是中间的操作,要根据不同的题目要求做出相应的操作。

【区块反转】【链表合并】【反转链表】【链表元素分类】【链表去重】【重排链表】相关推荐

  1. c++实现简单的数据结构(1.链表合并 2.士兵队列训练问题 3.Rails 4.Josephus Problem 5.Tree Recovery 6.四则运算 7.愚人节的礼物 8.Web)

    系列文章目录 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 例如:第一章 Python 机器学习入门之pandas的使用 提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮 ...

  2. 查找两个单词链表共同后缀的起始结点(C++,单链表/双向链表解法)

    描述 假定采用带头结点的单链表保存单词,当两个单词有相同的后缀时,则可共享相同的后缀空间.例如,"loading"和"being"的存储映像如下图所示: 设st ...

  3. 使用OC实现单链表:创建、删除、插入、查询、遍历、反转、合并、判断相交、求成环入口...

    一.概念 链表和数组都是一种线性结构,数组有序存储的,链表是无序存储的. 数组中的每一个元素地址是递增或者递减的关系,链表的每一个节点的地址没有此规律,它们是通过指针的指向连接起来. 链表种类:单链表 ...

  4. 七十、反转和合并链表、 链表有环的判断

    @Author:Runsen 编程的本质来源于算法,而算法的本质来源于数学,编程只不过将数学题进行代码化. ---- Runsen 最近在重新梳理学算法的知识,本文为链表常见操作复习的总结文章,会讲解 ...

  5. 基础数据结构【二】————动态数组,单向链表及链表的反转

    DEMO1:     动态分配变量(链表,而静态数组是线性表,意味着动态数组访问和遍历复杂度为O(n),而插入和删除复杂度为O(1),而静态数组线性表则完全相反) int* intptr = new ...

  6. 全面分析再动手的习惯:链表的反转问题(递归和非递归方式)

    定义一个方法(函数),实现输入一个链表的头结点,然后可以反转这个链表的方向,并输出反转之后的链表的头结点. typedef struct Node{int data;Node *next; } Nod ...

  7. 每隔k次反转一次 链表_PTA 5-2 Reversing Linked List (25) [法一] - 线性表 - 链表反转 (PAT 1074)...

    Given a constant K and a singly linked list L, you are supposed to reverse the links of every K elem ...

  8. C++递归与非递归实现链表的反转

    思想参考:http://ceeji.net/blog/reserve-linked-list-cpp/ #include"list.h" using namespace std; ...

  9. JAVA实现链表的反转(《剑指offer》)

    题目描述 输入一个链表,反转链表后,输出链表的所有元素. /* public class ListNode {int val;ListNode next = null;ListNode(int val ...

最新文章

  1. 协议森林03 IP接力赛 (IP, ARP, RIP和BGP协议)
  2. [转] Nexus OSS 3.xx 体验
  3. Qt操作SQLite数据库练习(20200215)
  4. oracle的rank,over partition 使用 和lead
  5. Java和SAP ABAP的异常处理
  6. FFmpeg在Ubuntu的安装以及教程~~~
  7. 使用Power Designer(PD)创建数据库模型、数据库表
  8. 关于playframework1.2.4 static 关键字使用的一些思考
  9. 重新理解创业:一个创业者的途中思考
  10. 手把手教你用Java设计并实现一个城市公交查询系统
  11. VirtualBox虚拟机中安装XP系统
  12. Win7如何显示文件扩展名
  13. MySQL 文本类型,存储大小
  14. 50元打造双网卡负载均衡服务器(Network Load Balancing)
  15. 群晖 重启 mysql_群晖nas修改MariaDB配置文件
  16. uboot中展示gpio接口的驱动
  17. Swift游戏实战-跑酷熊猫 07 平台的移动
  18. excel 去重复值
  19. 漫画趣解Flink实时数仓
  20. Modbus转Profinet网关连接台达ME300案例

热门文章

  1. 数据库的三级模式和两级映射--简单介绍
  2. windows生成文件MD5值
  3. Elasticsearch-常用的查询
  4. java微信获取openId和sessionKey
  5. 【Java位运算】异或运算的使用
  6. 16、Inner Class(内部类)
  7. 1.两数之和(哈希表)
  8. 用于脉冲检测的三种检波电路
  9. 微信小程序:ibeacon实现室内定位签到模型
  10. ti嵌入式开发板DY—Tiva-PB的调试日记——第一天