首页 > 其他分享 >双向链表C语言实现

双向链表C语言实现

时间:2024-01-16 09:22:06浏览次数:29  
标签:Node head prev cur next 链表 双向 C语言 节点

双向链表实现(带头结点版)

双向链表的实现与单链表类似,在这里使用C语言实现,主要包括头插法插入节点,删除节点以及创建空链表

抽象数据结构ADT定义

双向链表与单链表的区别在于多了一个指向上一个节点的指针prev

typedef struct _Node {
    int data;
    struct _Node* next;
    struct _Node* prev;
}Node;

typedef Node* Link;

创建空链表

基于上次单链表的demo中碰到的问题,为了避免使用二级指针,使用带头结点的头指针方式实现,因此创建一个新的空链表代码如下:

Link CreateLink() {
    //使用malloc函数返回一个不存放内容的头结点head
    Link head = (Link)malloc(sizeof(Node));
    if(head == NULL)
    {
        printf("Link create error\n");
        exit(1);
    }
    head->next = NULL;
    head->prev = NULL;
    return head;
}

插入新节点--头插法

带头结点的链表的实现逻辑与单链表略有不同,首先是函数的参数,只需传入指向头结点的指针Link head和值int value。最主要的还是插入新节点的逻辑,假设原链表顺序为head->A,我们需要插入新节点B:

(1) 首先是设置B的nextprev指针,next指向A,prev指向头结点

(2) 接着依次断开head与A之间的nextprev指针,并插入新节点B。在这里需要考虑两种情况:

  • 如果链表是空的,也就是只有一个头结点,这时A=NULL,如果想改变节点A的指针prev指向新节点B显然不现实,此时则不需要对A节点的prev指针设置
  • 如果链表非空也就是head->A->...->NULL的情况,此时头插法设置A的prev指向新节点B
  • 最后设置头结点head的next指向新节点B,头插法结束
/*新增节点--头插法*/
int Insert(Link head, int value) {
    Node* temp = (Node*)malloc(sizeof(Node));
    Node* cur = head;
    temp->data = value;

    if(head == NULL) {
        return -1;
    }

    //设置新节点的首尾指针
    temp->next = cur->next;
    temp->prev = cur;
    //断开原链表的链接,并链接新节点
    if(cur->next != NULL)
    {
        cur->next->prev = temp;
    }
    cur->next = temp;

    return 1;
}

删除指定下标的节点

删除节点的逻辑都是相同的,先遍历至该节点处或该节点的前一个节点,由于是双向链表,因此两种都可以,这里是直接遍历到要删除的节点处

(1) 链表判空

(2) 遍历到要删除的节点处

(3) 修改前一个节点的next指向下一个节点,下一个节点的prev指向前一个节点

(4) 最后将当前节点的指针回收即可完成删除

/*删除指定下标节点*/
int Delete(Link head, int index) {
    int i = 0;
    //从第一个节点开始,注意不是头结点,而是head->next
    Node* cur = head->next;

    if(head == NULL || cur == NULL)
        return -1;
    
    //遍历到要删除的节点,因此条件为(i < index - 1)
    while(cur && i < index - 1) 
    {
        cur = cur->next;
        i++;
    }
    cur->prev->next = cur->next;
    if(cur->next != NULL)
        cur->next->prev = cur->prev;
    cur->next = NULL;
    cur->prev = NULL;

    return 1;
}

完整代码

#include <stdio.h>
#include <stdlib.h>

typedef struct _Node {
    int data;
    struct _Node* next;
    struct _Node* prev;
}Node;

typedef Node* Link;

Link CreateLink() {
    Link head = (Link)malloc(sizeof(Node));
    if(head == NULL)
    {
        printf("Link create error\n");
        exit(1);
    }
    head->next = NULL;
    head->prev = NULL;
    return head;
}

/*新增节点--头插法*/
int Insert(Link head, int value) {
    Node* temp = (Node*)malloc(sizeof(Node));
    Node* cur = head;
    temp->data = value;

    if(head == NULL) {
        return -1;
    }

    //设置新节点的首尾指针
    temp->next = cur->next;
    temp->prev = cur;
    //断开原链表的链接,并链接新节点
    if(cur->next != NULL)
    {
        cur->next->prev = temp;
    }
    cur->next = temp;

    return 1;
}
/*删除指定下标节点*/
int Delete(Link head, int index) {
    int i = 0;
    Node* cur = head->next;

    if(head == NULL || cur == NULL)
        return -1;
    
    while(cur && i < index - 1) 
    {
        cur = cur->next;
        i++;
    }
    cur->prev->next = cur->next;
    if(cur->next != NULL)
        cur->next->prev = cur->prev;
    cur->next = NULL;
    cur->prev = NULL;

    return 1;
}

/*打印链表*/
void Print(Link head) {
    Node* node = head->next;
    if(head == NULL) {
        printf("head is null\n");
        return;
    }
    while (node != NULL)
    {
        printf("%d\n", node->data);
        node = node->next;
    }
    return;
}



int main() {
    int flag = 0;
    Node* head = CreateLink();
    Insert(head, 1);
    Insert(head, 2);
    Insert(head, 3);
    Insert(head, 4);
    Print(head);
    flag = Delete(head, 2);
    if(flag < 0) printf("delete error\n");
    Print(head);
    return 0;
}

标签:Node,head,prev,cur,next,链表,双向,C语言,节点
From: https://www.cnblogs.com/six-years/p/17966818

相关文章

  • 【算法】【线性表】【链表】随机链表的复制
    1 题目给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random......
  • 【算法】【线性表】【链表】环形链表
    1 题目给你一个链表的头节点 head ,判断链表中是否有环。如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从0开始)。注意:pos 不作为参数进行传递 。仅......
  • 【数据结构】C语言实现共享栈
    共享栈通过C语言实现导言大家好,很高兴又和大家见面啦!!!在上一篇内容中,我们介绍了如何通过C语言实现顺序栈,并且在介绍顺序栈的进栈操作时有提到过我们可以通过选择数组的首元素或者尾元素作为栈底,来进行栈的创建,以及栈的另一种形式——链栈。根据前面的介绍,我们知道了顺序栈是通过静......
  • C语言用数组实现三子棋
    //game.hdefineROW3defineCOL3include<stdio.h>voidInitBoard(charboard[ROW][COL],introw,intcol);voidDisplayBoard(charboard[ROW][COL],introw,intcol);//game.cinclude"game.h"voidInitBoard(charboard[ROW][COL],introw......
  • C语言学习随笔-07 auto关键字
    1、在C中auto是一个存储类的关键字。     -auto存储类:auto存储类是所有局部变量默认的存储类。     -auto可以在声明变量的时候根据变量的初始值的类型自动为此变量选择匹配的类型。2、注意事项     -auto声明的变量必须要初始化,否则编译器不能判断变量......
  • C语言---Day6
    15、enum枚举---枚举是C语言中的一种基本数据类型,用于定义一组具有离散值的常量,它可以让数据更简洁,更易读;通常用于为程序中的一组相关的常量取名字,以便于程序的可读性和维护性---声明枚举类型enumDay{MON=1,TUE,WED,THU,FRI,SAT,SUN};---枚举变量的定义:先......
  • leetcode 19.删除链表的倒数第N个节点
    leetcode19.删除链表的倒数第N个节点第十九题:删除链表的倒数第N个节点在对链表进行操作时,一种常用的技巧是添加一个哑节点(dummynode),它的next指针指向链表的头节点。这样一来,我们就不需要对头节点进行特殊的判断了。例如,在本题中,如果我们要删除节点y,我们需要知道节点y的前......
  • Arduino部分C语言含义之--“::”
    "::“在C++中表示作用域,和所属关系。”::"是运算符中等级最高的。有三种作用。1.作用域符号例如:A,B表示两个类,在A,B中都有成员member。那么:A::member就表示类A中的成员member。B::member就表示类B中的成员member。2.全局作用域符号charzhou;//全局变量voids......
  • 【数据结构】C语言实现顺序栈
    顺序栈的C语言实现导言大家好,很高兴又和大家见面啦!!!在上一个篇章中,我们介绍了栈的基本概念,以及栈中的重要术语。通过介绍我们知道了栈的本质也是一种线性表,只不过它是一种操作受限的线性表。因此栈的实现方式与线性表的实现实际上是大同小异的。下面我们就来介绍一下如何通过C语言......
  • 每日一题 2024-1-15 删除排序链表中的重复元素Ⅱ
    1.题目(中等)原题链接给定一个已排序的链表的头\(head\),删除原始链表中所有重复数字的节点,只留下不同的数字。返回已排序的链表。示例1:输入:head=[1,2,3,3,4,4,5]输出:[1,2,5]示例2:输入:head=[1,1,1,2,3]输出:[2,3]提示:链表中节点数目在范围\([0,300]\)......