在一般的链表创建中,我们习惯使用以下结构体的形式
struct Node{
int val;
Node* next;
}
虽然这种形式看起来直观清楚,但是在创建链表过程中使用到的new操作符,在数据范围过大时,会很慢,因此算法竞赛中我们使用单数组来创建链表。
单链表:
#include<iostream>
using namespace std;
const int N = 10010;
int e[N], r[N], head, cur;
//这里的cur代替了new用来为新的节点分配空间
void init()//初始化
{
head =0;
r[0] = -1;
cur = 1;
}
int find(int k)//返回第k个节点的下标
{
int dest =0;
while (k--)
{
dest = r[dest];
}
return dest;
}
void add_to_head(int x)//表头插入元素
{
e[cur] = x;
r[cur] = r[0];
r[0] = cur;
cur++;
}
void insert(int k,int x)//第k个节点的后面插入一个元素
{
k = find(k);
e[cur] = x;
r[cur] = r[k];
r[k] = cur;
cur++;
}
void remove(int t)//删除第k个节点
{
int k = find(t);
if (r[k] == -1)//当删除的节点为尾结点时要考虑特殊情况
{
k = find(t - 1);
r[k] = -1;
return;
}
//对于特定的删除某个节点
//一般思路来看我们需要知道他的前驱节点,
//然后让前驱结点指向该节点的后置节点。
//但是即使在不知前驱节点的情况下,我们可以将被删节点的信息全部拷贝成后置节点的信息,
//这就是一种伪删除的方式来实现未知前驱节点情况下的删除节点
e[k] = e[r[k]];
r[k] = r[r[k]];
}
int main()
{
init();
int m;
cin >> m;
while (m--)
{
printf("请输入你的选择:\n");
printf("1.表头插入一个元素x\n"
"2.第k个节点的后面插入一个元素x\n"
"3.第k个节点的前面插入一个元素x\n"
"4.删除第k个节点\n");
int flag;
scanf("%d", &flag);
switch (flag)
{
case 1:{int x; cin >> x; add_to_head(x); break; }
case 2:{int k, x; cin >> k >> x; insert(k, x); break; }
case 3:{int k, x; cin >> k >> x; insert(k - 1, x); break; }
case 4:{int k; cin >> k; remove(k); break; }
}
}
for (int i = r[0]; i != -1; i = r[i])
{
printf("%d->", e[i]);
}
puts("");
return 0;
}
输入 | 5 |
1 | 5 |
2 | 1 4 |
3 | 1 6 |
4 | 3 |
1 | 7 |
输出 | 7->6->5-> |
双链表:
#include<iostream>
using namespace std;
const int N = 100010;
int l[N], r[N], e[N], cur;
//默认0为头节点,1为尾节点
void init()
{
l[1] = 0;
r[0] = 1;
cur = 2;
}
void add_to_head(int x)//链表处插入一个点
{
e[cur] = x;
l[cur] = 0;
r[cur] = r[0];
l[r[0]] = cur;
r[0] = cur;
cur++;
}
int find(int k)
{
int dest = 0;
while (k--)
{
dest = r[dest];
}
return dest;
}
void insert(int k, int x)//第k个点的后面插入一个元素
{
e[cur] = x;
k = find(k);
l[cur] = k;
r[cur] = r[k];
l[r[k]] = cur;
r[k] = cur;
cur++;
}
void remove(int k)//删除第k个点
{
k = find(k);
r[l[k]] = r[k];
l[r[k]] = l[k];
}
int main()
{
init();
int m;
cin >> m;
while (m--)
{
printf("请输入你的选择:\n");
printf("1.表头插入一个元素x\n"
"2.第k个节点的后面插入一个元素x\n"
"3.第k个节点的前面插入一个元素x\n"
"4.删除第k个节点\n");
int flag = 0;
scanf("%d", &flag);
switch (flag)
{
case 1:{int x; cin >> x; add_to_head(x); break; }
case 2:{int k, x; cin >> k >> x; insert(k, x); break; }
case 3:{int k, x; cin >> k >> x; insert(k-1, x); break; }
case 4:{int k; cin >> k; remove(k); break;}
}
}
//打印链表
for (int i = r[0]; i != 1; i = r[i])//自左向右
{
printf("%d->", e[i]);
}
puts("");
for (int i = l[1]; i != 0; i = l[i])//自右向左
{
printf("%d->", e[i]);
}
puts("");
return 0;
}
输入 | 5 |
1 | 5 |
2 | 1 4 |
3 | 1 6 |
4 | 3 |
1 | 7 |
输出 | 7->6->5-> 5->6->7-> |
2023/1/8 by shybee