双向链表的C语言实现

1️⃣ 用结构体定义一个节点

  • ❤️ 双向链表的结构体:
struct node
{
	int data;
	struct node *prev;//指向上一个节点
	struct node *next;//指向下一个节点
};

2️⃣ 建立一个双向链表

  • 双向链表结构
    在这里插入图片描述
  • 类似单链表的头插法,我们创建一个节点插在链表头节点前面成为新的头结点:
struct node *insertHead(struct node *head)
{
	struct node *new = (struct node *)malloc(sizeof(struct node));//为新节点开辟空间并初始化数据
    new->prev = NULL;
    new->next = NULL;
    printf("input your new node data:");
    scanf("%d", &(new->data)); //往新节点里键入数据

    if (head == NULL){ //若头节点为空,新节点即为头结点
        return new; //返回新节点的地址
    }else{
        head->prev = new;
        new->next = head;
        return new;//返回新节点的地址
    }
}
  • 当然我们也可以在链表的尾部添加节点,返回头指针
struct node *insertTail(struct node *head)
{
    struct node *end = head; //添加一个指向尾部的指针end
    struct node *new = (struct node *)malloc(sizeof(struct node));
    new->prev = NULL;
    new->next = NULL;
    printf("input your new node data:");
    scanf("%d", &(new->data)); //往新节点里键入数据

    if (head == NULL)
    {               //若头节点为空,创建第一个节点
        return new; //返回头指针
    }

    while (end->next != NULL)
    { //end一直走到最后一个节点
        end = end->next;
    }

    end->next = new; //让最后一个节点的指针指向新节点
    new->prev = end;
    return head;
}

3️⃣双向链表的遍历

  • 因为链表是双向的,所以我们可以从头和尾两个方向遍历
  • 从头节点开始遍历:
void printLinkH(struct node *head)
{
    if (head == NULL){
        printf("The list is empty.\n");
        return;
    }
    while (head != NULL){ //不是空就往下走
    	printf("%d\n", head->data);
        head = head->next;
    }
    putchar('\n');
}
  • 因为我们的创建函数返回的是头节点地址,所以我们写一个得到尾节点地址的函数(对复杂度有要求的小伙伴建议一开始就定义一个tail)
struct node *getTail(struct node *head)
{
    while (head->next != NULL)
    { //head一直走到最后一个节点
        head = head->next;
    }
    return head;
}
  • 从尾节点的遍历跟从头结点一样,只不过把next换成了prev
void printLinkT(struct node *tail)
{
    if (tail == NULL)
    {
        printf("The list is empty.\n");
        return;
    }
    while (tail != NULL) //不是空就往下走
    {
        printf("%d\n", tail->data);
        tail = tail->prev;
    }
    putchar('\n');
}
  • 下面放代码验证:
#include <stdio.h>
#include <stdlib.h>

struct node
{
    int data;
    struct node *prev; //指向上一个节点
    struct node *next; //指向下一个节点
};
struct node *insertHead(struct node *head)
{
    struct node *new = (struct node *)malloc(sizeof(struct node));
    new->prev = NULL;
    new->next = NULL;
    printf("input your new node data:");
    scanf("%d", &(new->data)); //往新节点里键入数据

    if (head == NULL)
    {               //若头节点为空,新节点为头节点
        return new; 
    }
    else
    {
        head->prev = new;
        new->next = head;
        return new;
    }
}

struct node *insertTail(struct node *head)
{
    struct node *end = head; //添加一个指向尾部的指针end
    struct node *new = (struct node *)malloc(sizeof(struct node));
    new->prev = NULL;
    new->next = NULL;
    printf("input your new node data:");
    scanf("%d", &(new->data)); //往新节点里键入数据

    if (head == NULL)
    {               //若头节点为空,新节点为头节点
        return new; 
    }

    while (end->next != NULL)
    { //end一直走到最后一个节点
        end = end->next;
    }

    end->next = new; //让最后一个节点的指针指向新节点
    new->prev = end;//新节点的前一个指针指向end指向的节点
    return head;
}
struct node *getTail(struct node *head)
{
    while (head->next != NULL)
    { //head一直走到最后一个节点
        head = head->next;
    }
    return head;
}

void printLinkH(struct node *head)
{
    if (head == NULL)
    {
        printf("The list is empty.\n");
        return;
    }
    while (head != NULL) //不是空就往下走
    {
        printf("%d\n", head->data);
        head = head->next;
    }
    putchar('\n');
}

void printLinkL(struct node *tail)
{
    if (tail == NULL)
    {
        printf("The list is empty.\n");
        return;
    }
    while (tail != NULL) //不是空就往前走
    {
        printf("%d\n", tail->data);
        tail = tail->prev;
    }
    putchar('\n');
}

int main()
{
    int i = 0;
    struct node *head1 = NULL;
    struct node *head2 = NULL;
    struct node *tail = NULL;

    for (i = 0; i < 5; i++)//头插法创建5个节点的双向链表link1
    {
        head1 = insertHead(head1);//从头结点遍历
    }
    printLinkH(head1);

    for (i = 0; i < 5; i++)//尾插法创建5个节点的双向链表link2
    {
        head2 = insertTail(head2);
    }
    tail = getTail(head2);//得到link2的尾节点地址
    printLinkH(head2);//从头结点遍历
    printLinkL(tail);//从尾结点遍历

    return 0;
}
  • 示意图在这里插入图片描述

  • 终端显示:

input your new node data:1
input your new node data:2
input your new node data:3
input your new node data:4
input your new node data:5
5
4
3
2
1

input your new node data:11
input your new node data:22
input your new node data:33
input your new node data:44
input your new node data:55
11
22
33
44
55

55
44
33
22
11

4️⃣删除第n个节点

  • 这里的方法很灵活,我的做法是用一个指针p遍历到第n个节点的后一个结点,然后把目标节点(p->prev)的prev赋值给p下节点的prev,把p的地址赋值给上上个节点的next,最后释放(free)掉目标节点就成了。
    在这里插入图片描述
struct node *delNode(struct node *head, int num)
{
    struct node *p = head;
    if (num == 1){	//头结点的情况
        head = head->next;//把第二个节点的地址给头指针
        free(p);//释放原来的头结点
        return head;//返回新的头指针
    }

    while (num--){
        if (p->next == NULL){  //尾节点也特殊照顾
            struct node *temp = p;//把最后一个节点地址给中间变量
            p->prev->next = NULL;//把倒数第二个节点的next设为NULL
            free(temp);//释放最后一个节点结点
            return head;//为了兼容头结点的情况返回头指针
        }

        p = p->next;
    }
    p->prev->prev->next = p;//把p的地址赋值给上上个节点的next
    struct node *temp = p->prev;//目标节点的地址给中间变量
    p->prev = p->prev->prev;//把目标节点地址给p的prev
    free(temp);//释放目标节点,完成删除

    return head;//为了兼容头结点的情况返回头指针
}
  • 代码验证:
#include <stdio.h>
#include <stdlib.h>

struct node
{
    int data;
    struct node *prev; //指向上一个节点
    struct node *next; //指向下一个节点
};

struct node *insertTail(struct node *head)//尾插法插入一个节点
{
    struct node *end = head;
    struct node *new = (struct node *)malloc(sizeof(struct node));
    new->prev = NULL;
    new->next = NULL;
    printf("input your new node data:");
    scanf("%d", &(new->data));

    if (head == NULL)
    {               
        return new; 
    }

    while (end->next != NULL)
    { 
        end = end->next;
    }

    end->next = new; 
    new->prev = end;
    return head;
}

void printLinkH(struct node *head)//从头指针遍历链表
{
    if (head == NULL)
    {
        printf("The list is empty.\n");
        return;
    }
    while (head != NULL) //不是空就往下走
    {
        printf("%d\n", head->data);
        head = head->next;
    }
    putchar('\n');
}

struct node *delNode(struct node *head, int num)//删除第n个节点
{
    struct node *p = head;
    if (num == 1){
        head = head->next;
        free(p);
        return head;
    }

    while (num--)
    {
        if (p->next == NULL){
            struct node *temp = p;
            p->prev->next = NULL;
            free(temp);
            return head;
        }

        p = p->next;
    }

    
    p->prev->prev->next = p;
    struct node *temp = p->prev;
    p->prev = p->prev->prev;
    free(temp);

    return head;
}

struct node *creatLink(struct node *head)//尾插法创建链表
{
    int num;
    printf("input node num:");//键入你想创建的节点数
    scanf("%d", &num);
    putchar('\n');
    while (num--){

        head = insertTail(head);
    }
    return head;
}

int main()
{
    int n;
    struct node *head = NULL;

    head = creatLink(head);//创建链表封装了一个函数
    printLinkH(head);//打印链表

    printf("input del num:");//键入你想删除的节点数
    scanf("%d", &n);

    head = delNode(head, n);
    putchar('\n');

    printLinkH(head);//打印链表

    return 0;
}
  • 终端显示:
input node num:6

input your new node data:1
input your new node data:2
input your new node data:3
input your new node data:4
input your new node data:5
input your new node data:6
1
2
3
4
5
6

input del num:4

1
2
3
5
6

5️⃣在第n个节点后插入一个节点

  • 创建一个新节点new,用一个指针p遍历到第n个节点的后一个节点,把new结点的地址给第n个节点(p->prev)的next,并让newt的prev指向n节点;把p的地址给new的next,最后再把new结点的地址给第p的prev就完成了
    在这里插入图片描述
  • 函数如下:
int insertnode(struct node *p, int num)
{
    struct node *new = (struct node *)malloc(sizeof(struct node));
    printf("input your new node data:");
    scanf("%d", &(new->data)); //往新节点里键入数据

    while (num--){
        if (p->next == NULL){ //走到最后一个节点的处理
			p->next = new;
            new->prev = p;
            new->next = NULL;
			return 0;
        }

        p = p->next;//p指针往下走
    }

    p->prev->next = new;
    new->prev = p->prev;
    new->next = p;
    p->prev = new;
}
  • 代码验证:
#include <stdio.h>
#include <stdlib.h>

struct node
{
    int data;
    struct node *prev; //指向上一个节点
    struct node *next; //指向下一个节点
};

struct node *insertTail(struct node *head)//尾插法插入一个节点
{
    struct node *end = head;
    struct node *new = (struct node *)malloc(sizeof(struct node));
    new->prev = NULL;
    new->next = NULL;
    printf("input your new node data:");
    scanf("%d", &(new->data));

    if (head == NULL)
    {               
        return new; 
    }

    while (end->next != NULL)
    { 
        end = end->next;
    }

    end->next = new; 
    new->prev = end;
    return head;
}

void printLinkH(struct node *head)//从头指针遍历链表
{
    if (head == NULL)
    {
        printf("The list is empty.\n");
        return;
    }
    while (head != NULL) //不是空就往下走
    {
        printf("%d\n", head->data);
        head = head->next;
    }
    putchar('\n');
}

int insertnode(struct node *p, int num)//在n节点后插入节点
{
    struct node *new = (struct node *)malloc(sizeof(struct node));
    printf("input your new node data:");
    scanf("%d", &(new->data)); //往新节点里键入数据

    while (num--){
        if (p->next == NULL){ //走到最后一个节点的处理
			p->next = new;
            new->prev = p;
            new->next = NULL;
			return 0;
        }

        p = p->next;//p指针往下走
    }

    p->prev->next = new;
    new->prev = p->prev;
    new->next = p;
    p->prev = new;
}

struct node *creatLink(struct node *head)//尾插法创建链表
{
    int num;
    printf("input node num:");//键入你想创建的节点数
    scanf("%d", &num);
    putchar('\n');
    while (num--){

        head = insertTail(head);
    }
    return head;
}

int main()
{
    int n;
    struct node *head = NULL;

    head = creatLink(head);//创建链表封装了一个函数
    printLinkH(head);//打印链表

    printf("input del num:");//键入你想删除的节点数
    scanf("%d", &n);

    insertnode(head, n);
    putchar('\n');

    printLinkH(head);//打印链表

    return 0;
}
  • 终端:
input node num:5

input your new node data:5
input your new node data:6
input your new node data:7
input your new node data:8
input your new node data:9
5
6
7
8
9

input insert num:3
input your new node data:666

5
6
7
666
8
9


  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

money的大雨

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

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

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

打赏作者

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

抵扣说明:

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

余额充值