数据结构:双向链表


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

1.双链表的结构定义

typedef struct DuLNode {  
    ElemType data;  
    struct DuLNode *prior;  
    struct DuLNode *next;  
}DuLnode,*DuLinkList;

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

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

2.双链表结构的对称性

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;
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;
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. 频繁进行插入或删除操作
  • 48
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

写代码的大学生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值