文章目录
数据结构第3章 - 线性表(Part 3)
写在开头
哈哈哈咕咕了好久!在前面学习了顺序表和单链表之后,我们将学习双链表和静态链表。这章会非常短因为双链表和单链表异曲同工,只是多出了prev用来指向其前一个节点。特别地,双链表也可以视作一正一反两个单链表,这样只要你的单链表基础足够好,那么学习双链表相信也不是问题。
另外对于静态链表就更简单啦~ 静态链表使用数组存储节点,并用下一个节点的下标代替了原本指向内存地址的指针。
线性表存储结构2 - 链表
链表2 - 双链表
双链表的定义
双链表是用一组任意的存储单元存放线性表的元素,通过每个节点存储它上一个和下一个数据所在内存地址的指针而存放整张线性表。
定义代码:
template<class DataType>
class NodeList {
public:
DataType val; //存储该节点的值
NodeList* prev; //存储上一个节点的地址
NodeList* next; //存储下一个节点的地址
NodeList(DataType v) : val(v), prev(nullptr), next(nullptr) {}
NodeList(DataType v, NodeList* p, NodeList* n) : val(v), prev(p), next(n) {}
};
不难看出,使用了一个prev能够使链表更方便地返回或者前进。
双链表的增删改查
代码和单链表很相似,这里给出修改思路,就不给代码啦(不是懒;P)
插入(增)
s->prev=p;
s->next=p->next;
p->next->prev=s;
p->next=s;
删除(删)
p->prev->next=p->next;
p->next->prev=p->prev;
delete p;
改、查
同单链表,没必要重复写了
链表3 - 静态链表
静态链表的定义
静态链表使用数组来表示单链表,用数组元素的下标来模拟单链表的指针。静态链表每个数组元素由两个元素构成:data和next。
const int MAX_SIZE=256; //按需修改
template<class DataType>
struct SNode {
DataType data;
int next;
}SList[MAX_SIZE];
静态链表的增删改查
类比传统意义上的单链表,静态链表仅仅是将访问方式由指针改为下标,所以代码也非常相似。
特别地,使用数组的0位置存储头节点的位置(就像头指针),其余存储数据和next。这边依然给出核心代码。
插入
插入节点和链表也比较相像,但是为了数据不浪费存储空间,我们这边使用avail变量记录该静态链表的第一个空闲节点下标。
假设s插在p后面。
s=avail;
avail=SList[avail].next; //因为空闲点的next肯定是空闲的,所以可以直接修改avail
SList[s].data=x; //赋值
SList[s].next=Slist[p].next; //插入点
删除
假设要删除p的后继,则代码如下:
q=SList[p].next; //存储要删除的节点
SList[p].next=SList[q].next; //使p节点下一个位置指向q的下一个数据的位置
SList[q].next=avail; //让删掉的节点置为avail,q插在avail最前端
avail=q; //avail指向q,因为q已经被删除掉了
线性表的间接寻址
通过将数组与指针结合,用数组存储指向第i位地址的指针。
写在最后
线性表最常用的存储还是单链表,当然每种结构都要熟悉。可以多找点题目做做,就是这样啦。
EOF