【数据结构】四、双向链表和双向循环链表

1.双向链表的定义

双向链表是在单链表的每个结点里再增加一个指向其直接前驱的指针域prior,这样链表就形成了有两个方向不同的链

//双向链表的结点结构体
struct DuLinkNode
{
    Elemtype data;  //数据域
    struct DuLNode* prior;  //前驱指针域
    struct DuLNode* next;  //后继指针域
};
typedef DuLinkNode* DuLinkList;  //DuLinkList表示双向链表,DuLinkNode* 表示单个结点

2.双向循环链表的定义

双向循环链表就是在双向链表的基础上,让头结点的前驱指针指向链表的最后一个结点,让最后一个结点的后继指针指向头结点

3.双向循环链表的对称性

p结点前驱结点的后继也是p结点,后继结点的前驱也是p结点

4.双向链表的操作概述

求链表长度、找第pos个位置的数据等操作只涉及一个方向的指针,所以它们的算法与单链表相同。但在进行插入、删除等操作时,会涉及两个方向的指针。

5.双向链表的插入操作

//在带头结点的双向循环链表L的第i个位置插入数据域为e的结点
void ListInsert_Du(DuLinkList &L, int i, Elemtype e)
{
    //先找到第i个位置的指针p
    DuLinkNode *p = new DuLinkNode;
    p = L->next; //从首结点开始
    int k = 0;
    while((p != NULL) && (k < i))
    {
        p = p->next;
        k++;
    }
    //创建一个新结点s
    DuLinkNode *s = new DuLinkNode;
    //将s结点的数据域赋值为e
    s->date = e;
    //把s的前驱指针指向第i个位置的前一个结点
    s->prior = p->prior;
    //将第i个位置的前一个结点的后继指针指向s结点
    p->prior->next = s;
    //将s结点的后继指针指向p
    s->next = p;
    //将p结点的前驱指针指向s
    p->prior = s;
}

6.双向链表的删除操作

//删除带头结点的双向循环链表L的第i个位置的结点
void ListDelete_Dul(DuLinkList &L, int i)
{
    //先找到第i个结点p
    DuLinkNode *p = new DuLinkNode;
    p = L->next;
    int k = 0;
    while((p != NULL) && (k < i))
    {
        p = p->next;
        k++;
    }
    //将第i个位置的前一个结点的后继指针指向第i个位置的后一个结点
    p->prior->next = p->next;
    //将第i个位置的后一个结点的前驱指针指向第i个位置的前一个结点
    p->next->prior = p->prior;
}

7.链表和顺序表的比较

链表的优点:(1) 存储空间可以动态分配和释放。(2) 删除和修改链表时,不需要移动结点,只需修改指针。

链表的缺点:(1) 存储空间比较大,存储密度小,因为每个结点的指针都需要额外的空间来存储。(2) 链表是非随机存取结构,对任一结点的操作都要从头指针依次指到指定的结点,增加了算法的复杂度。

顺序表的优点:(1) 存储密度为1,因为只需存储结点数据本身,不用为表示结点间的逻辑关系而增加额外的存储空间。(2) 随机存取,直接通过下标来存取。

顺序表的缺点:(1) 需要预先分配空间,可能会导致空间的浪费和溢出。(2) 删除和修改顺序表时,要移动结点本身,时间开销较大。

  • 5
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值