链表知识补充

150 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第3天

双向链表

基本概念

定义

在单链表的每个结点中,再设置一个指向其前驱结点的指针域

注意:链表由单向的链变成了双向链,每一个节点都有两个指针分别指向该节点的前驱和后继。

代码:

/线性表的双向链表存储结构/ typedef struct DulNode { ElemType data; struct DuLNode prior; / 直接前驱指针*/ struct DuLNode next; / 直接后继指针*/ } DulNode, *DuLinkList;

基本操作

插入

p节点、其前驱的前驱和后继都要更新,需要按顺序写四条语句更新。(新增结点别需给数据域赋值)

s->prior=p->prior; //引入新结点,指向p的前驱 p->prior->next=s; //p前驱的后继连到s上 s->next=p; //新结点的后继连到p p->prior=s; //p的前驱连到s上

删除

把p结点的前驱的后继更新,p的后继的前驱更新

p->prior->next=p->next; p->next->prior=p->prior; free(p);

顺序表和链表的比较

1)顺序表:

特点:

逻辑上相邻的数据元素,物理存储位置也相邻,存储空间需要预先分配。

优点:

a) 方法简单,各种高级语言中都有数组,容易实现。 b) 不用为表示节点间的逻辑关系而增加额外的存储开销。 c) 顺序表具有按元素序号随机访问的特点。

缺点:

a) 在顺序表中做插入、删除操作时,平均移动表中的一半元素,因此n较大的顺序表效率低。 b) 静态分配,程序执行之前必须明确规定存储规模预先分配足够大的存储空间,估计过大,可能会导致顺序表后部大量闲置;预先分配过小,又会造成溢出。

2)链表:

特点

在链表中逻辑上相邻的数据元素,物理存储位置不一定相邻,用指针实现元素之间的逻辑关系,存储空间是动态分配的。

优点:

插入、删除运算方便。

缺点:

a) 要占用额外的存储空间存储元素之间的关系,存储密度降低。存储密度是指一个节点中数据元素所占的存储单元和整个节点所占的存储单元之比。 b) 链表不是一种随机存储结构,不能随机存取元素。

3) 顺序表和链表的区别

增: a) 顺序表往指定位置,不覆盖的添加一个值,后面的值日要往后移动,算法复杂度为O(n); b) 链表往指定位置添加一个节点,需要从表头遍历到指定位置,算法复杂度为O(n),如果带有索引的节点,算法复杂度为O(1)。 删: a) 顺序表指定位置,删除一个值时,需要将后面的值向前移动,算法复杂度为O(n); b) 链表指定一个位置,删除一个时,如果没有对指定节点进行索引,需要从表头遍历到指定位置,然后将指定节点删除,算法复杂度为O(n), 如果对指定节点做索引,删除节点的算法复杂度为O(1)。 查: a) 顺序表直接查询指定位置值算法复杂度为O(1); b) 链表需要遍历节点到指定位置,算法复杂度为O(n);如果节点指定位置节点有索引,算法复杂度为O(1). 改:修改其实就是查找修改值的位置,再对值进行修改。 a) 顺序表的增和删表数量规模比较大时,平均移动一半的元素,效率不高。 b) 对于有索引的链表,添加和删除只需要O(1)算法复杂度,效率高。因此,链表用于频繁的添加和删除数据时,有优势。 2.从内存角度 (1)顺序表是由数组组成的线性表,数组是一组地址连续的单元存储块,分配于栈区,可以自动释放。 (2)链表是由不连续的地址节点组成的线性表,每个节点可以是一个单元的地址块或连续地址块,分配于堆区,节点必须手动释放