826. 单链表
使用数组模拟链表,因为采用结构体+new的方式比较慢,笔试中一般不使用。单链表的用途是邻接表,邻接表的应用场景是存储树和图。
每一个结点存储val(结点值)以及next(指针,指向下个节点的地址),用e[N]数组来存储节点的值,ne[N]数组来存储节点的next指针是多少,此外多定义一个head表示头指针的位置,一个idx表示当前已经用到了哪个点。e[N]和ne[N]是通过下标关联起来。如图所示
对于插入操作,如将红色点插入到头结点的位置(头插法)
cpp
void add_to_head(int x){
e[idx] = x;
ne[idx] = head;
head = idx++;
}
将元素插入到下标为k的结点后面
cpp
void add(int k, int x){
e[idx] = x;
ne[idx] = ne[k];
ne[k] = idx++;
}
将下标为k的结点后面的结点删掉
cpp
void remove(int k){
ne[k] = ne[ne[k]];
}
题目思路
- 向链表头插入一个数
- 删除第 k个插入的数后面的一个数
- 在第 k个插入的数后插入一个数
c++ 代码
cpp
#include<iostream>
using namespace std;
const int N = 100000;
int ne[N], e[N], head, idx;
//val[i]:表示结点i的值
//e[i]: 表示结点的下个节点的位置
//head:表示头指针的位置
//idx:表示当前已经用到了哪个点
void init(){
head = -1;
idx = 0;
}
//将x查到头结点
void add_to_head(int x){
e[idx] = x;
ne[idx] = head;
head = idx++;
}
void add(int k, int x){
e[idx] = x;
ne[idx] = ne[k];
ne[k] = idx++;
}
void remove(int k){
ne[k] = ne[ne[k]];
}
int main(){
int m;
cin >> m;
init();
while(m--){
int k, x;
char op;
cin >> op;
if(op == 'H'){
cin >> x;
add_to_head(x);
}else if(op == 'D'){
cin >> k;
if(!k){
head = ne[head];
}
remove(k - 1);
}else if(op == 'I'){
cin >> k >> x;
add(k - 1, x);
}
}
// 将整个结点进行遍历
for(int i = head; i != -1; i = ne[i]){
cout << e[i] << ' ';
}
return 0;
}
827. 双链表
题目思路
双链表就是每一个结点有两个指针,一个指向前一个结点,一个指向后一个结点,用两个数组去表示,l[N]表示左边(前面)结点的下标,r[N]表示右边(后边)结点的下标。
这里规定,下标为0的点为头结点head,下标为1的点为尾结点tail,最开始的状态如下(初始化内容)
在k结点右边插入一个元素
cpp
//在下标为k的点的右边插入x
void add(int k, int x){
e[idx] = x;
r[idx] = r[k];
l[idx] = k;
l[r[k]] = idx;//r[k]先调用,后修改
r[k] = idx;
}
删除下标为k的结点
cpp
void remove(int k){
r[l[k]] = r[k];
l[r[k]] = l[k];
}
c++代码
cpp
#include<iostream>
using namespace std;
const int N = 100005;
int head, tail, r[N], l[N], e[N], idx, m;
void init(){
r[0] = 1;
l[1] = 0;
idx = 2; // 0 ,1已经使用过了
}
//在下标为k的点的右边插入x
void add(int k, int x){
e[idx] = x;
r[idx] = r[k];
l[idx] = k;
l[r[k]] = idx;//r[k]先调用,后修改
r[k] = idx++;
}
//在k的左边插入一个数等价于在k的左边结点(L[k])后插入一个数
//删除第k个点
void remove(int k){
r[l[k]] = r[k];
l[r[k]] = l[k];
}
int main(){
cin >> m;
init();
while(m--){
int k, x;
string op;
cin >> op;
if(op == "L"){
cin >> x;
add(0, x);
}else if(op == "R"){
cin >> x;
add(l[1], x);//tail结点的左侧
}else if(op == "D"){
cin >> k;
remove(k + 1);
}else if(op == "IL"){
cin >> k >> x;
add(l[k + 1], x);
}else if(op == "IR"){
cin >> k >> x;
add(k + 1, x);
}
}
// 将整个表进行遍历
for(int i = r[0]; i != 1; i = r[i]){
cout << e[i] << " ";
}
return 0;
}
领接表
领接表是由多个单链表组成的,拿邻接表存储树和图放到第三章去讲。