双向链表(Double Linked List)

这篇具有很好参考价值的文章主要介绍了双向链表(Double Linked List)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、简介

        虽然单向链表能够100%解决逻辑关系为“一对一”数据的存储问题,但在解决那些需要大量查找前趋节点的问题是,单向链表无疑是不能用了,因为单向链表适合“从前往后”查找,并不适合“从后往前”查找。

        如果要提高链表的查找效率,那双向链表(双链表)无疑是首选。

        双向链表字面上的意思是“双向”的链表,如图1所示。

双向链表(Double Linked List)
图1 - 双向链表示意图

        双向指各个节点之间的逻辑关系是双向的,该链表通常只有一个头节点。

        从图1还可以看出,双向链表中每个节点包括一下3个部分,分别是指针域(用于指向当前节点的直接前驱节点)、数据域(用于存储数据元素)和指针域(用于指向当前节点的后继节点)。

二、创建

1、声明

typedef struct line{
    struct line *prior;//指向直接前趋
    int data;
    struct line *next;//指向直接后继
}line;

2、创建

line* initLine(line *head){
    head=(line*)malloc(sizeof(line));//创建链表第一个结点(首元结点)
    head->prior=NULL;
    head->next=NULL;
    head->data=1;
    line *list=head;
    for(int i=2; i<=3; i++)
    {
        //创建并初始化一个新结点
        line *body=(line*)malloc(sizeof(line));
        body->prior=NULL;
        body->next=NULL;
        body->data=i;

        list->next=body;//直接前趋结点的next指针指向新结点
        body->prior=list;//新结点指向直接前趋结点
        list=list->next;
    }
    return head;
}

三、基本操作

1、添加节点

        添加节点可以分为三种,分别是:添加至表头添加至链表的中间位置添加至链表尾

添加至表头

        将新元素添加到表头,只需要将其与表头元素建立双层逻辑关系即可。

        假设定义新元素节点为tmp,表头节点为head,则只需要执行下面两个步骤和即可:

  1. tmp的next变成head,head的prior编程tmp;
  2. 将head移至tmp,重新指向新的表头。

        比如将元素7天添加到双向链表的表头,则实现过程如图2所示。

双向链表(Double Linked List)
图2 - 添加元素至双向链表的表头

添加至链表的中间位置

        添加至表的中间位置主要分为两个步骤:

  1. 新节点先与其后继节点建立双层逻辑关系;
  2. 新节点的前驱与之建立双层逻辑关系。

         此过程如图3所示。

双向链表(Double Linked List)
图3 - 双向链表中间位置添加数据元素示意图

 添加至表尾

        与添加至表头很相似,其过程如下:

  1. 找到双向链表的最后一个节点;
  2. 让新节点与其进行双层逻辑关系建立。

        此过程如图4所示。 

双向链表(Double Linked List)
图4 - 双向链表尾部添加元素示意图

代码

经过上述内容,我们可以试着编写代码了。

line *insertLine(line *head,int data,int add){
    //新建数据域为data的结点
    line *temp=(line*)malloc(sizeof(line));
    temp->data=data;
    temp->prior=NULL;
    temp->next=NULL;
    //插入到链表头,要特殊考虑
    if(add==1)
    {
        temp->next=head;
        head->prior=temp;
        head=temp;
    }
    else
    {
        line *body=head;
        //找到要插入位置的前一个结点
        for(int i=1; i<add-1; i++)
        {
            body=body->next;
        }
        //判断条件为真,说明插入位置为链表尾
        if(body->next==NULL)
        {
            body->next=temp;
            temp->prior=body;
        }
        else
        {
            body->next->prior=temp;
            temp->next=body->next;
            body->next=temp;
            temp->prior=body;
        }
    }
    return head;
}

2、删除节点

        双向链表删除节点时,只需要遍历到要删除的节点,然后将其删除即可。

        例如,从删除2的过程如图5所示。

双向链表(Double Linked List)
图5 - 双向链表删除元素的操作示意图

代码

//删除结点的函数,data为要删除结点的数据域的值
line *delLine(line *head,int data)
{
    line *temp=head;
    //遍历链表
    while(temp)
    {
        //判断当前结点中数据域和data是否相等,若相等,摘除该结点
        if (temp->data==data)
        {
            temp->prior->next=temp->next;
            temp->next->prior=temp->prior;
            free(temp);
            return head;
        }
        temp=temp->next;
    }
    printf("链表中无该数据元素");
    return head;
}

3、查找节点

        依次遍历表中数据,直到找到为止。

代码

//head为原双链表,elem表示被查找元素
int selectElem(line * head,int elem){
//新建一个指针t,初始化为头指针 head
    line * t=head;
    int i=1;
    while(t)
    {
        if(t->data==elem)
        {
            return i;
        }
        i++;
        t=t->next;
    }
    //程序执行至此处,表示查找失败
    return -1;
}

4、更改节点

        在查找的基础上完成。过程是通过遍历找到的节点,直接将数据域修改即可。

代码

//更新函数,其中,add 表示更改结点在双链表中的位置,newElem 为新数据的值
line *amendElem(line *p,int add,int newElem){
    line *temp=p;
    //遍历到被删除结点
    for (int i=1; i<add; i++)
    {
        temp=temp->next;
    }
    temp->data=newElem;
    return p;
}

四、完整代码

        给出的所有代码的整合代码:

#include <bits/stdc++.h>
typedef struct line{
    struct line *prior;
    int data;
    struct line *next;
}line;
//双链表的创建
line* initLine(line * head);
//双链表插入元素,add表示插入位置
line * insertLine(line * head,int data,int add);
//双链表删除指定元素
line * delLine(line * head,int data);
//双链表中查找指定元素
int selectElem(line * head,int elem);
//双链表中更改指定位置节点中存储的数据,add表示更改位置
line *amendElem(line * p,int add,int newElem);
//输出双链表的实现函数
void display(line * head);
int main(){
    line *head=NULL;
    //创建双链表
    head=initLine(head);
    display(head);
    //在表中第 3 的位置插入元素 7
    head=insertLine(head,7,3);
    display(head);
    //表中删除元素 2
    head=delLine(head,2);
    display(head);

    printf("元素 3 的位置是:%d\n",selectElem(head,3));
    //表中第 3 个节点中的数据改为存储 6
    head=amendElem(head,3,6);
    display(head);
    return 0;
}
line* initLine(line * head){
    head=(line*)malloc(sizeof(line));
    head->prior=NULL;
    head->next=NULL;
    head->data=1;
    line *list=head;
    for(int i=2; i<=5; i++)
    {
        line*body=(line*)malloc(sizeof(line));
        body->prior=NULL;
        body->next=NULL;
        body->data=i;

        list->next=body;
        body->prior=list;
        list=list->next;
    }
    return head;
}
line *insertLine(line *head,int data,int add){
    //新建数据域为data的结点
    line *temp=(line*)malloc(sizeof(line));
    temp->data=data;
    temp->prior=NULL;
    temp->next=NULL;
    //插入到链表头,要特殊考虑
    if(add==1)
    {
        temp->next=head;
        head->prior=temp;
        head=temp;
    }
    else
   	{
        line * body=head;
        //找到要插入位置的前一个结点
        for(int i=1; i<add-1; i++)
        {
            body=body->next;
        }
        //判断条件为真,说明插入位置为链表尾
        if(body->next==NULL)
        {
            body->next=temp;
            temp->prior=body;
        }
        else
        {
            body->next->prior=temp;
            temp->next=body->next;
            body->next=temp;
            temp->prior=body;
        }
    }
    return head;
}
line *delLine(line *head,int data)
{
    line *temp=head;
    //遍历链表
    while(temp)
    {
        //判断当前结点中数据域和data是否相等,若相等,摘除该结点
        if(temp->data==data)
        {
            temp->prior->next=temp->next;
            temp->next->prior=temp->prior;
            free(temp);
            return head;
        }
        temp=temp->next;
    }
    printf("链表中无该数据元素");
    return head;
}
//head为原双链表,elem表示被查找元素
int selectElem(line *head,int elem){
//新建一个指针t,初始化为头指针 head
    line *t=head;
    int i=1;
    while(t)
    {
        if(t->data==elem)
        {
            return i;
        }
        i++;
        t=t->next;
    }
    //程序执行至此处,表示查找失败
    return -1;
}
//更新函数,其中,add 表示更改结点在双链表中的位置,newElem 为新数据的值
line *amendElem(line *p,int add,int newElem){
    line * temp=p;
    //遍历到被删除结点
    for(int i=1; i<add; i++)
    {
        temp=temp->next;
    }
    temp->data=newElem;
    return p;
}
//输出链表的功能函数
void display(line *head)
{
    line *temp=head;
    while(temp)
    {
        if(temp->next==NULL)
        {
            printf("%d\n",temp->data);
        }
        else
        {
            printf("%d->",temp->data);
        }
        temp=temp->next;
    }
}

参考文献:http://c.biancheng.net/view/3343.html

好啦,以上就是本文的全部内容啦!创作不易,点个赞再走呗~文章来源地址https://www.toymoban.com/news/detail-412430.html

到了这里,关于双向链表(Double Linked List)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【数据结构篇】手写双向链表、单向链表(超详细)

    什么是链表 ? 链表(Linked List)是用链式存储结构实现的线性表。链表示意图: 链表的组成 : 数据域 + 引用域 (数据域和引用域合称结点或元素) 数据域存放数据元素自身的数据 引用域存放相邻结点的地址 链表的特点 : 链表中元素的联系依靠引用域 具有线性结构的特

    2024年02月11日
    浏览(30)
  • 数据结构与算法 | 链表(Linked List)

    链表(Linked List)是一种线性数据结构,它由一系列节点(Node)组成,每个节点包含两部分:数据和指向下(上)一个节点的引用(或指针)。链表中的节点按照线性顺序连接在一起(相邻节点不需要存储在连续内存位置),不像数组一样存储在连续的内存位置。链表通常由

    2024年02月08日
    浏览(36)
  • 数据结构day06(单向循环链表、双向链表)

    双向链表的练习代码 head.h fun.c main.c 今日思维导图哈 ​​​​​​​

    2024年02月10日
    浏览(28)
  • LeetCode 92. Reverse Linked List II【链表,头插法】中等

    本文属于「征服LeetCode」系列文章之一,这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁,本系列将至少持续到刷完所有无锁题之日为止;由于LeetCode还在不断地创建新题,本系列的终止日期可能是永远。在这一系列刷题文章中,我不仅会讲解多种解题思路及其优化,

    2024年02月09日
    浏览(30)
  • 【数据结构和算法】使用数组的结构实现链表(单向或双向)

    上文我们通过结构体的结构实现了队列 、以及循环队列的实现,我们或许在其他老师的教学中,只学到了用结构体的形式来实现链表、队列、栈等数据结构,本文我想告诉你的是,我们 可以使用数组的结构实现链表、单调栈、单调队列 目录 前言 一、用数组结构的好处 1.数

    2024年01月20日
    浏览(51)
  • 【LeetCode 算法】Linked List Cycle II 环形链表 II

    给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从

    2024年02月14日
    浏览(32)
  • 【STL源码分析】c++,List双向链表源码分析。自己实现list双向链表。

    参考链接:https://blog.csdn.net/man_sion/article/details/71003095? 先抽取要实现的功能,由于迭代器有些麻烦,就不使用了。要实现的功能有,push_back,pop_back,insert(指定位置,指定值),insert(指定位置,list,区间值),reverse,clear,getsize,begin,end,构造和析构函数,empty。 相关力扣题目:设计

    2024年02月03日
    浏览(32)
  • 数据结构之List(双向链表)的实现

    方法名 参数 功能 返回 find const T val, int n, listNode * p 区间查找 从p往前数n个节点 指针或NULL const T val, listNode * p 区间查找 从p往前到首节点 const T val 查找 Size void 链表规模 size empty void 判空 bool first void 返回首节点 首节点指针 clear void 清空链表 void insertAsFirst const T val 作为首节

    2024年02月16日
    浏览(36)
  • 算法竞赛基础:C++双向链表的结构和实现(普通链表、List、静态链表)

    本文将会介绍在算法竞赛中双向链表的几种使用方式,适合有一定基础的人阅读。 一般来说,普通的链表结构是这样的: next指针指向下一个链表,这样的结构只能够支持单向查询。 双向链表,顾名思义,就是可以支持双向的访问和查询。 也就是这样的: 这种链表为访问前

    2024年01月24日
    浏览(31)
  • Linked List

    补充知识 typedef 给类型换名字,比如 或者来一个结构体指针定义。 离散存储 离散的含义,任何一个点到其他点之间是有间距的。 n个节点离散分配,彼此通过指针相连接,每个节点只有一个前驱节点,每个节点只有一个后继节点,首节点没有前驱节点,尾节点没有后继节点

    2024年02月15日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包