数据结构:双向链表

文章目录

单链表的链式存储结构的结点中只有一个指示直接后继的指针域,由此,从某个结点出发只能顺指针向后寻查其他结点。若要寻查结点的直接前驱,则必须从表头指针出发。换句话说。在单链表中,查找直接后继结点的执行时间为0(1),而查找直接前驱的执行时间为0(n)。为克服单链表这种单向性的缺点,可利用双向链表(Double Linked List)。
顾名思义,在双向链表的结点中有两个指针域,一个指向直接后继,另一个指向直接前驱。

1.双链表的结构定义

c 复制代码
typedef struct DuLNode {  
    ElemType data;  
    struct DuLNode *prior;  
    struct DuLNode *next;  
}DuLnode,*DuLinkList;

双向循环链表

和单链的循环表类似,双向链表也可以有循环表

  • 让头结点的前驱指针指向链表的最后一个结点
  • 让最后一个结点的后继指针指向头结点。

2.双链表结构的对称性

c 复制代码
p->prior->next = p = p->next->prior

在双向链表中有些操作(如:istLength、GetElem等),因仅涉及一个方向的指针,故它们的算法与线性链表的相同。但在插入、删除时,则需同时修改两个方向上的指针,两者的操作的时间复杂度均为O()。

2.双向链表的插入

  1. s->prior=p->prior;
  2. p->prior->next=s;
  3. s->next=p;
  4. p->prior=s;
c 复制代码
void insertBefore(Node** head, Node* p, int value) {
    Node* s = (Node*)malloc(sizeof(Node)); // 创建新节点
    if (!s) return; // 内存分配失败处理

    s->data = value; // 设置新节点的数据
    s->next = p;     // 设置新节点的后继为p
    s->prior = p->prior; // 设置新节点的前驱为p的前驱

    if (p->prior) { // 如果p不是头节点
        p->prior->next = s; // 更新p的前驱的后继指向新节点
    } else { // 如果p是头节点
        *head = s; // 更新头指针
    }

    p->prior = s; // 更新p的前驱指向新节点
}

3.双向链表的删除

  1. p->prior-next=p->next;
  2. p->next->prior=p->prior;
c 复制代码
void deleteNode(Node** head, Node* p) {
    if (p == NULL) return; // 检查p是否为NULL

    // 更新前驱节点的后继指针
    if (p->prior != NULL) {
        p->prior->next = p->next;
    } else {
        *head = p->next; // 如果p是头节点,更新头指针
    }

    // 更新后继节点的前驱指针
    if (p->next != NULL) {
        p->next->prior = p->prior;
    }

    // 释放被删除节点的内存
    free(p);
}

4.顺序表和链表的比较

链式存储结构的优点

  • 结点空间可以动态申请和释放;
  • 数据元素的逻辑次序靠结点的指针来指示,插入和删除时不需要移动数据元素。
    链式存储结构的缺点
  • 存储密度小,每个结点的指针域需额外占用存储空间。当每个结点的数据域所占字节不多时,指针域所占存储空间的比重显得很大。
  • 链式存储结构是非随机存取结构。对任一结点的操作都要从头指针依指针链查找到该结点,这增加了算法的杂度。
    存储结构
比较项目 顺序表 链表
预先分配,会导致空间闲置或溢出现象 ×
动态分配,不会出现存储空间闲置或溢出现象 ×
不用为表示结点间的逻辑关系而增加额外的存储开销,存储密度等于1 ×
需要借助指针来体现元素间的逻辑关系,存储密度小于1 ×
随机存取,按位置访问元素的时间复杂度为O(1) ×
顺序存取,按位置访问元素时间复杂度为O(n) ×
平均移动约表中一半元素,时间复杂度为O(n),时间复杂度为O(1) ×
不需移动元素,确定插入、删除位置后,时间复杂度为O(1) ×

适用情况

  • 顺序表:
    1. 表长变化不大,且能事先确定变化的范围
    2. 很少进行插入或删除操作,经常按元素位置序号访问数据元素
  • 链表:
    1. 长度变化较大
    2. 频繁进行插入或删除操作
相关推荐
AIAdvocate1 小时前
Pandas_数据结构详解
数据结构·python·pandas
jiao000011 小时前
数据结构——队列
c语言·数据结构·算法
kaneki_lh1 小时前
数据结构 - 栈
数据结构
铁匠匠匠1 小时前
从零开始学数据结构系列之第六章《排序简介》
c语言·数据结构·经验分享·笔记·学习·开源·课程设计
C-SDN花园GGbond1 小时前
【探索数据结构与算法】插入排序:原理、实现与分析(图文详解)
c语言·开发语言·数据结构·排序算法
CV工程师小林3 小时前
【算法】BFS 系列之边权为 1 的最短路问题
数据结构·c++·算法·leetcode·宽度优先
Navigator_Z3 小时前
数据结构C //线性表(链表)ADT结构及相关函数
c语言·数据结构·算法·链表
还听珊瑚海吗3 小时前
数据结构—栈和队列
数据结构
Aic山鱼3 小时前
【如何高效学习数据结构:构建编程的坚实基石】
数据结构·学习·算法
sjsjs114 小时前
【数据结构-一维差分】力扣1893. 检查是否区域内所有整数都被覆盖
数据结构·算法·leetcode