文章目录
静态链表
与动态链表不同的是,静态链表不需要指针来建立结点之间的连接关系。对于有些问题,结点的地址是比较小的整数(例如五位数的地址),就没有必要建立动态链表。
静态链表的实现原理是hash,即通过建立一个结构体数组,并令数组的下标直接表示结点的地址,直接访问结点中的元素就可以访问结点。而且,静态链表是不需要头结点的。静态链表结点定义如下:
struct static_list {
typename data; //数据域
int next; //指针域
} node[size];
next为一个int型整数,用于存放下一个结点的地址,实际上就是数组下标。例如包含三个结点的链表,初始结点的地址为111,第二个结点的地址为222,第三个结点的地址为333,则静态链表可如下建立:
node[111]=222;
node[222]=333;
node[333]=-1 //-1表示NULL,表明没有后继结点
通用解题步骤
- 定义静态链表;
struct static_list {
int address; //地址
typename data; //数据域
int next; //指针域
xxxxx; //结点的某个性质
} node[size];
以上设置了结点的地址、指针域、数据域,以及一个适应性性质等等。
- 程序开始时对链表初始化,如xxx里的性质,是否访问过;
for(int i=0;i<MAXN;i++){
node[i].xxx=false;
}
- 题目一般回给出一条链表首结点的地址,那么我们就可以根据这个地址来遍历得到整条链表。这一阶段我们需要对结点的性质进行标记,并且对有效结点进行计数等等操作。
int p = begin, count = 0;
while(p!=-1){
xxx = 1;
count++;
p=node[p]->next;
}
- 由于使用静态链表,是直接采用地址映射的方式,这就会使数组下标不连续,而很多时候题目给出的结点并不都是有效结点。为了能够访问有效结点,一般需要对数组进行排序,并把有效结点移动到数组左端。具体需求视题目而定。
我们看如下两个例子理解静态列表的用法:
一、链表的共享空间
1、题目描述
给出两个链表的首地址以及若干结点的地址、数据、下一个结点的地址,求两条链表首个共用结点的地址。如果两个链表没有共用结点,输出-1。
输入样例1
第一行输入两个链表的首地址,以及正整数N,表示结点个数。
00001 00002 4
00001 a 10001
10001 s -1
00002 a 10002
10002 t -1
输出样例1
-1
输入样例2
11111 22222 9
67890 i 00002
00010 a 12345
00003 g -1
12345 D 67890
00002 n 00003
22222 B 23456
11111 L 00001
23456 e 67890
00001 o 00010
输出样例2
67890
2、思路
- 由于地址的范围很小,因此直接使用静态链表,根据题意需要在结点的结构体中再定义一个int变量flag,表示结点是否在第一条链表出现,是返回1,否则返回-1;
- 从第一个链表首地址出发遍历第一个链表,将所有经过的结点flag值赋为1;
- 接下来枚举第二条链表,当出现第一个flag值为1的结点,说明是第一条链表中出现的结点,即两个链表的第一个共用结点;
- 如果第二条链表枚举完毕没有发现共用结点则返回-1。
3、注意
- 使用
%05d
格式输出地址,不足五位高位补0; - 使用map可能会超时;
scanf
读入%c
格式时,%d
之间加空格。
4、代码实现
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 10000 + 10;
struct static_list {
char data;
int next;
bool flag;
} node[MAXN];
int main() {
for (int i = 0; i < MAXN; i++) {
node[i].flag = false;
}
int s1, s2, n; //第一行的三个元素,分别为两个链表首地址和结点个数
scanf("%d%d%d", s1, s2, n);
int address, next;
char data;
for (int i = 0; i < n; i++) {
scanf("%d %c %d", &address, &data, &next);
node[address].data = data;
node[address].next = next;
}
int p;
for (p = s1; p != -1; p = node[p].next) {
node[p].flag = true;
}
for (p = s2; p != -1; p = node[p].next) {
if (node[p].flag == true) break;
}
if (p != -1) {
printf("%05d\n", p);
} else {
printf("-1\n");
}
return 0;
}
二、Linked List sorting
1、题目描述
给出N个结点的地址address、数据域data、以及指针域next,然后给出链表的首地址,要求把这个链表上的结点按data值从小到大输出。要求输入输出的格式相同。
输入样例
5 00001
11111 100 -1
00001 0 22222
33333 100000 11111
12345 -1 33333
22222 1000 12345
输出样例
5 12345
12345 -1 00001
00001 0 11111
11111 100 22222
22222 1000 33333
33333 100000 -1
2、思路
按照输入,该链表如下:(格式[address,data,next])
[00001,0,22222] -> [22222,1000,12345] -> [12345,-1,33333]->[33333,100000,11111]->[11111,100,-1]
按照key值排序之后得到:
[12345,-1,00001] -> [00001,0,11111] -> [11111,100,22222]->[22222,1000,33333]->[33333,100000,-1]
按照通用解题步骤:
- 定义静态链表,其中结点性质由bool型变量flag定义,表示为结点在链表中是否出现;
- 初始化,令flag全为false(即0),表示初始状态下所有结点都是无效结点;
- 由题目给出的链表首地址begin遍历整条链表,并标记有效结点的flag为true(即1),同时计数有效结点的个数count;
- 对结点进行排序,排序函数cmp的原则是:如果cmp两个参数结点中有无效结点的话,按flag从大到小排序,以把有效结点拍到数组左端(有效结点的flag为1),否则按照数据域从小到大排序;
- 由于有效结点已经按照数据域从小到大排序,因此按照要求输出有效结点即可。
3、注意
- 可以直接使用
%05d
的输出格式,以在不足五位时高位补0;但要注意**-1**不能使用%05d
输出,否则会输出-0001; - 题目可能存在无效结点。
4、代码实现
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100000 + 10;
struct static_list {
int address, data, next;
bool flag; //判断结点是否在链表上
} node[MAXN];
bool cmp(static_list a, static_list b) {
if (a.flag == false || b.flag == false) {
return a.flag > b.flag; //把无效结点放后面
} else {
return a.data < b.data;
}
}
int main() {
for (int i = 0; i < MAXN; i++) {
node[i].flag = false;
}
int n, begin, address; //链表首地址begin
scanf("%d%d", &n, &begin);
for (int i = 0; i < n; i++) {
scanf("%d", &address);
scanf("%d%d", &node[address].data, &node[address].next);
node[address].address = address;
}
int count = 0, p = begin;
while (p != -1) {
node[p].flag = true;
count++;
p = node[p].next;
}
if (count == 0) {
printf("0 -1");
} else {
sort(node, node + MAXN, cmp);
printf("%d %05d\n", count, node[0].address);
for (int i = 0; i < count; i++) {
if (i != count - 1) {
printf("%05d %d %05d", node[i].address, node[i].data, node[i].next);
} else {
printf("%05d %d -1\n", node[i].address, node[i].data);
}
}
}
return 0;
}