一、种类
单链表:每个结点只记录自己的后继,只能向后走;
双链表:每个结点记录自己的后继和前驱,可以向前或向后走;
循环单链表:本身是一单链表,最后一个结点的后继是第一个结点;
循环双链表:本身是一双链表,形成环形。
二、链表实现
a.结构体模拟:
实现一个数据结构,维护一张表(最初只有一个元素 1)。需要支 持下面的操作,其中 x 和 y 都是 int 范围内的正整数,且都不一样, 操作数量不多于 2000: ins_back(x,y) :将元素 y 插入到 x 后面; ins_front(x,y) :将元素 y 插入到 x 前面; ask_back(x) :询问 x 后面的元素; ask_front(x) :询问 x 前面的元素; del(x):从表中删除元素 x,不改变其他元素的先后顺序
struct node{
int pre,nxt;//记录前驱和后继结点在S数组中的下标
int key;//结点的值
node(int _key=0,int _pre=0,int _nxt=0){//结构体初始化
pre=_pre;nxt=_nxt;key=_key;
}
}s[1005];
int tot=0;//记录S数组目前使用了多少位置
int find(int x){//查找x的结点编号
int now=1;
while(now&&s[now].key!=x)now=s[now].nxt;
return now;
}
/* ins_back ,ins_front :注意更新后继的前驱以及前驱的后继*/
void ins_back(int x, int y) {//y插x后面
int now = find(x);
s[++tot] = node(y, now, s[now].nxt);//结点y的前驱是now,后继是是s[now].nxt
s[s[now].nxt].pre = tot;//更新原来now的后继的pre值;
s[now].nxt = tot;//更新now的后继
}
void ins_back(int x, int y) {//y插x前面
int now = find(x);
s[++tot] = node(y, s[now].nxt,now,);//结点y的前驱是s[now].nxt ,后继是是now,
s[s[now].nxt].pre = tot;//更新原来now的前驱的pre值;
s[now].nxt = tot;//更新now的前驱
}
/*ask_back,ask_front: 同理只需根据编号获得其后继/前驱的值即可*/
int ask_back(int x) {
int now = find(x);
return s[s[now].nxt].key;
}
int ask_front (int x) {
int now = find(x);
return s[s[now].pre].key;
}
/*del:删除一个元素时,只需让这个元素的前驱的后继变成它的后 继,它的后继的前驱变成它的前驱即可 */
void del(int x) {
int now = find(x);
int le = s[now].pre, rt = s[now].nxt;
s[le].nxt = rt;
s[rt].pre = le;
}
b.头文件
链表需要使用list的头文件,支持一下常用方法:
list<int> a;定义一个名为a的链表
int arr[5]={1,2,3};list<int a(arr,arr+3);从数组arr中前3个元素作为链表a的初始值
a.size();返回链表a的结点数
list<int>: :iterator it;定义一个名为it的迭代器指针;
a.begin(),a.end();链表开始和末位的迭代器指针
a.push_front(x);a.push_back(x);在链表开头或末位插入元素x
a.insert(it ,x);在迭代器it前插入元素x
a.pop_front();a.pop_back();删除链表开头或末位
a.erase(it);删除迭代器it所在的元素,
for(it=a.begin;it!=a.end;it++)遍历链表
遍历时如果要删除元素,一定要备份一个迭代器;否则it原来指向的结点删除后就不复存在,
导致询问下一个结点是时会无效访问。