模板
(1)典型示例
输入:
(The address of a node is a 5-digit nonnegative integer, and NULL is represented by −1.)
- the first line :
the address of the first node, and a positive N (≤ 1 0 5 10^5 105 ) which is the total number of nodes. - N lines:
Address Key Next
00100 5
99999 -7 87654
23854 -15 00000
87654 15 -1
00000 -15 99999
00100 21 23854
即,00100 -> 23854 -> 00000 -> 99999 -> 87654 -> -1
(2)代码模板
#include<cstdio>
using namespace std;
const int N = 100000+10; // 10^5
typedef struct{
int adress;
int data;
int next;
bool flag; //是否是链表上的结点 (其它结点 = false)
int order; // 链表中结点的序号【从0开始】(其它结点 = N)
/* ... ... */
}Node;
Node nodes[N];
int real_n=0; //真正链表中的结点个数
int main(){
// 初始化
for(int i=0; i<N; i++){
nodes[i].order = N;
}
// 输入
int f_ad, n;
scanf("%d%d", &f_ad, &n);
int ad, data, next;
for(int i=0; i<n; i++){
scanf("%d%d%d", &ad, &data , &next);
nodes[ad] = {ad, data, next};
}
// 设置flag order
for(int i=f_ad; i!=-1; i=nodes[i].next){
nodes[i].flag = true;
nodes[i].order = real_n;
real_n++;
}
/* ... ... */
// 输出
printf("%05d %d %05d", nodes[i].adress, nodes[i].data, nodes[i].next);
return 0;
}
1032(25:两个链表求公共结点)
(1)题目
两个链表求公共结点
代码:
#include<cstdio>
using namespace std;
const int N = 100000+10;
struct Node{
char data;
int next;
bool flag; // 是否是第一个链表中的元素
}nodes[N];
int main(){
int ad1, ad2, n;
scanf("%d %d %d", &ad1, &ad2, &n);
int ad, next;
char data;
for(int i=0; i<n; i++){
scanf("%d %c %d", &ad, &data, &next);
nodes[ad] = {data, next, false};
}
// 遍历第一个链表
for(int i=ad1; i!=-1; i=nodes[i].next){
nodes[i].flag = true;
}
// 遍历第二个链表
for(int i=ad2; i!=-1; i=nodes[i].next){
if(nodes[i].flag){
printf("%05d", i);
return 0;
}
}
printf("-1");
return 0;
}
(3)小结
- 全局变量的默认值
int /int * /char /bool /double 默认值均是0
char* /string 默认值为空(长度=0),char[i] 默认值是0 - 链表结点:flag标志 很关键
- struct 用{}赋值(struct没有构造函数)
node[ad].data = data; node[ad].next = next; node[ad].flag = false;
相当于
nodes[ad] = {data, next, false};
- 如何遍历一个链表
for(int i=ad1; i!=-1; i=nodes[i].next){...}
- 输出
return 0 提前结束;
最后输出 一般没有\n;
1052(25:链表排序)
(1)题目
链表排序
(2)代码
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 100000+10;
struct Node{
int adress;
int data;
int next;
bool flag; //是否是链表的结点
}nodes[N];
// 前:flag=true, data小
bool cmp(Node no1, Node no2){
if(no1.flag == no2.flag){
return no1.data < no2.data;
}else{
return no1.flag > no2.flag;
}
}
int main(){
int ad, n;
scanf("%d%d", &n, &ad);
int ad2, data2, next2;
for(int i=0; i<n; i++){
scanf("%d%d%d", &ad2, &data2 , &next2);
nodes[ad2] = {ad2, data2, next2, false}; // 所输入的结点不一定在链表中
}
int real_n = 0; //真正链表中的结点个数
// 遍历
for(int i=ad; i!=-1; i=nodes[i].next){
nodes[i].flag = true;
real_n++;
}
// sort
if(!real_n){
printf("0 -1");
}else{
sort(nodes, nodes+N, cmp);
printf("%d %05d\n", real_n, nodes[0].adress ); //不再是输入的ad
for(int i=0; i<real_n; i++){
printf("%05d %d ", nodes[i].adress, nodes[i].data);
if(i!=real_n-1){
printf("%05d\n", nodes[i+1].adress);
}else{
printf("-1");
}
}
}
return 0;
}
(3)小结
- 审题:
输入:where N is the total number of nodes in memory
输出: where N is the total number of nodes in the list - 链表结点:
flag 必有,因为(所输入的结点不一定在链表中, flag 和 real_n才是真的)
初始化:flag=false
从队头遍历:flag=true - 链表排序
链表结点:增加adress(不再以nodes[i]的下标为地址)
先按 flag 排(flag=true在前), 再按 data 排(data小的在前)
最后输出前n个结点 - 边界: n=0
1074(25:链表反转(间隔k ))
(1)题目
(2)代码
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 100000+10;
struct Node{
int adress;
int data;
int next;
bool flag; //是否是链表的结点
int order; // 链表中结点的序号
}nodes[N];
// 前:flag=true, order小
bool cmp(Node no1, Node no2){
if(no1.flag == no2.flag){
return no1.order < no2.order;
}{
return no1.flag > no2.flag;
}
}
void out_reverse(int start, int stop, int last){
for(int i=stop; i>=start; i--){
printf("%05d %d ", nodes[i].adress, nodes[i].data);
if(i==start){
if(last==-1){
printf("-1");
}else{
printf("%05d\n", nodes[last].adress);
}
}else{
printf("%05d\n", nodes[i-1].adress);
}
}
}
int main(){
for(int i=0; i<N; i++){
nodes[i].order = N;
}
int ad, n, k;
scanf("%d%d%d", &ad, &n, &k);
int ad2, data2, next2;
for(int i=0; i<n; i++){
scanf("%d%d%d", &ad2, &data2 , &next2);
nodes[ad2] = {ad2, data2, next2, false};
}
int real_n = 0; //真正链表中的结点个数
// 遍历
for(int i=ad; i!=-1; i=nodes[i].next){
nodes[i].flag = true;
nodes[i].order = real_n;
real_n++;
}
// sort
sort(nodes, nodes+N, cmp);
int inter = real_n / k;
if(real_n % k==0){
// 正好分完
for(int i=0; i<=inter-1; i++){
if(i!=inter-1){
out_reverse(i*k, i*k + k-1, (i+2)*k-1);
}else{
out_reverse(i*k, i*k + k-1, -1);
}
}
}else{
// 有剩下
if(inter<1){
for(int i=0; i<real_n; i++){
printf("%05d %d ", nodes[i].adress, nodes[i].data);
if(i==real_n-1){
printf("-1");
}else{
printf("%05d\n", nodes[i+1].adress);
}
}
}else{
for(int i=0; i<=inter-1; i++){
if(i!=inter-1){
out_reverse(i*k, i*k + k-1, (i+2)*k-1);
}else{
out_reverse(i*k, i*k + k-1, (i+1)*k);
}
}
for(int i=(inter-1)*k+k; i<real_n; i++){
printf("%05d %d ", nodes[i].adress, nodes[i].data);
if(i==real_n-1){
printf("-1");
}else{
printf("%05d\n", nodes[i+1].adress);
}
}
}
}
return 0;
}
(3)小结
- 链表结点
只要之后打乱结点,就要增加adress成员(如之后sort)
与结点在链表中的序号有关,就要增加order成员 - 测评:答案部分正确
情况1:边界
情况2:改写测试用例,测试各种情况的枝节
1097(25:删除链表上的重复数据)【非满分】
(1)题目
(2)代码
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 100000+10;
struct Node{
int adress;
int data;
int next;
int order; //序号
int keep; //=0:在链表中,保留,=1:在链表中,移除,=N,不在链表中
}nodes[N];
int abso[N]; //绝对值=i, abso[i]=1,链表中已有
// 前:keep小,order小
bool cmp(Node no1, Node no2){
if(no1.keep==no2.keep){
return no1.order < no2.order;
}else{
return no1.keep < no2.keep;
}
}
int main(){
for(int i=0; i<N; i++){
nodes[i].keep = N;
nodes[i].order = N;
}
int ad, n;
scanf("%d%d", &ad, &n);
int ad2, data2, next2;
for(int i=0; i<n; i++){
scanf("%d%d%d", &ad2, &data2 , &next2);
nodes[ad2] = {ad2, data2, next2};
}
int real_n = 0; //真正链表中的结点个数
// 遍历
for(int i=ad; i!=-1; i=nodes[i].next){
nodes[i].order = real_n;
if(abso[abs(nodes[i].data)]==1){
nodes[i].keep = 1;
}else{
abso[abs(nodes[i].data)]=1;
nodes[i].keep = 0;
}
real_n++;
}
// remove
sort(nodes, nodes+N, cmp);
int remove_first=real_n; // 第一个移除的结点序号
for(int i=0; i<real_n; i++){
if(nodes[i].keep==1){
remove_first = i;
break;
}
}
for(int i=0; i<remove_first; i++){
printf("%05d %d ", nodes[i].adress, nodes[i].data);
if(i!=remove_first-1){
printf("%05d\n", nodes[i+1].adress);
}else{
printf("-1\n");
}
}
for(int i=remove_first; i<real_n; i++){
printf("%05d %d ", nodes[i].adress, nodes[i].data);
if(i!=real_n-1){
printf("%05d\n", nodes[i+1].adress);
}else{
printf("-1\n");
}
}
return 0;
}
(3) 小结
- 静态链表的算法设计
设计struct的成员,灵活结合sort()
1133(25:拆分链表)
(1)题目
(2)代码
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
const int N = 100000+10; // 10^5
typedef struct{
int adress;
int data;
int next;
bool flag; //是否是链表上的结点 (其它结点 = false)
int order; // 链表中结点的序号【从0开始】(其它结点 = N)
/* ... ... */
}Node;
Node nodes[N];
int real_n=0; //真正链表中的结点个数
bool cmp(Node node1, Node node2){
return node1.order < node2.order;
}
int main(){
// 初始化
for(int i=0; i<N; i++){
nodes[i].order = N;
}
// 输入
int f_ad, n, k;
scanf("%d%d%d", &f_ad, &n, &k);
int ad, data, next;
for(int i=0; i<n; i++){
scanf("%d%d%d", &ad, &data , &next);
nodes[ad] = {ad, data, next};
}
// 设置flag order
for(int i=f_ad; i!=-1; i=nodes[i].next){
nodes[i].flag = true;
nodes[i].order = real_n;
real_n++;
}
/* ... ... */
sort(nodes, nodes+N, cmp);
vector<Node> vect;
for(int i=0; i<real_n; i++){
if(nodes[i].data<0){
vect.push_back(nodes[i]);
}
}
for(int i=0; i<real_n; i++){
if(nodes[i].data>=0 && nodes[i].data<=k){
vect.push_back(nodes[i]);
}
}
for(int i=0; i<real_n; i++){
if(nodes[i].data>k){
vect.push_back(nodes[i]);
}
}
for(int i=0; i<real_n; i++){
if(i==real_n-1){
vect[i].next = -1;
printf("%05d %d %d", vect[i].adress, vect[i].data, vect[i].next);
}else{
vect[i].next = vect[i+1].adress;
printf("%05d %d %05d\n", vect[i].adress, vect[i].data, vect[i].next);
}
}
return 0;
}