PAT中有关链表的题一般都是用顺序结构来表示,即将链表的节点储存在一个很大的数组中,数组下标就是节点的地址,节点结构中有一个next成员,储存着逻辑上下个节点的下标,用-1来表示空值。
//基本的节点结构
struct Node
{
//数据
int data;
//下个节点的坐标
int next;
};
考察范围无非增查删改反转这些,有一个方法可以在不破坏原有的逻辑顺序的前提下使用stl算法
为节点结构添加 address order 成员
struct Node
{
int data;
int next;
//添加成员
int address; //记录节点的地址
int order; //记录节点在链表中的逻辑顺序
Node():
order(INT32_MAX) //order默认为最大值
{ }
};
用一个vector来保存节点
节点的地址范围为 00000-99999
vector<Node> linklist(100000); //足够容纳所有的地址
先按照链表中节点的顺序遍历,为每个节点赋值其order
int order = 0;
for (auto it = head; it != -1; it = linklist[it].next)
{
linklist[it].order = order++;
}
再根据order大小排序,将节点聚集
根据order排序后,节点聚集在一起,下标失去地址的意义,但节点的相对次序还是和链表中一样
//order小的排在前面,即链表中的逻辑顺序
sort(linklist.begin(), linklist.end(), [](const Node& lhs, const Node&rhs) {
return lhs.order < rhs.order;
});
此时可以直接用stl的方法插入、删除节点
一个翻转链表的例子
vector<Node> linklist(100000);
int head;
int N;
cin >> head >> N;
while (N--)
{
int address, data, next;
cin >> address >> data >> next;
linklist[address] = Node(address, data, next);
}
int order = 0;
for (auto it = head; it != -1; it = linklist[it].next)
{
linklist[it].order = order++;
}
sort(linklist.begin(), linklist.end(), [](const Node& lhs, const Node&rhs) {
return lhs.order < rhs.order;
});
//将后面多余的空节点删掉
linklist.resize(order);
//可以直接使用翻转函数
reverse(linklist.begin(), linklist.end());
for (auto it = linklist.begin(); it != linklist.end(); ++it)
{
if (it != linklist.end() - 1)
{
//注意要用(it + 1)->address输出下一个节点的地址
//因为next没有在reverse后更新,也可以更新next后再将next输出
printf("%05d %d %05d\n", it->address, it->data, (it + 1)->address);
}
else
{
printf("%05d %d -1\n", it->address, it->data);
}
}