双链表有头节点

#ifndef __DOUBLE_H__
#define __DOUBLE_H__
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

typedef int Elemtype;
struct Node
{
    Elemtype data;     // 数据域
    struct Node *prev; // 指向上一个节点
    struct Node *next; // 指向下一个节点
};

struct Head
{
    struct Node *first;
    struct Node *last;
    int num;
};

extern struct Head *Create_Empty_DoubleLinkedListWithHead();
extern struct Head *Create_Empty_DoubleLinkedListWithHead_1();
extern struct Head *Create_Input_DoubleLinkedListWithHead();
extern bool Is_Head(struct Head *head);
extern void Print_DoubleLinkedListWithHead(struct Head *head);
extern struct Head *Insert_node_y(struct Head *head, Elemtype x, Elemtype y);
extern struct Head *Insert_node_y_2(struct Head *head, Elemtype x, Elemtype y);
extern void Delete_all_x(struct Head *head, Elemtype x);
extern void Delete_all_x_2(struct Head *head, Elemtype x);

#endif
#include "double.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

/*
        Create_Empty_DoubleLinkedListWithHead:创建一条带头结点的空双向链表

        返回值:
            返回头节点地址
*/
struct Head *Create_Empty_DoubleLinkedListWithHead()
{
    struct Head *p = malloc(sizeof(*p));
    if (p == NULL)
        return NULL;
    p->first = malloc(sizeof(*p));
    if (p->first == NULL)
    {
        free(p);
        return NULL;
    }

    p->first->prev = p->first->next = NULL;
    p->num = 0;
    return p;
}

struct Head *Create_Empty_DoubleLinkedListWithHead_1()
{
    struct Head *head = malloc(sizeof(*head));
    head->first = head->last = NULL;
    head->num = 0;
    return head;
}

/*
        从键盘上输入数据创建一条整型数据双向链表
        Create_Input_DoubleLinkedListWithHead:创建一条带头结点的空双向链表

        返回值:
            返回头节点地址
*/
struct Head *Create_Input_DoubleLinkedListWithHead()
{
    // 创建头结点
    struct Head *head = malloc(sizeof(*head));
    if (head == NULL)
        return NULL;
    head->first = head->last = NULL; // 初始化链表的第一个和最后一个节点为NULL
    head->num = 0;                   // 初始化链表节点数量为0

    int x;
    printf("请输入整型数据:");
    scanf("%d", &x);

    // 读取用户输入的整型数据,直到输入为0为止
    while (x != 0)
    {
        // 创建新的节点
        struct Node *p = malloc(sizeof(*p));
        if (p == NULL)
            return NULL;
        p->data = x;    // 将用户输入的数据存储到节点中
        p->next = NULL; // 初始化节点的下一个节点指针为NULL

        // 如果链表为空,则将新节点设置为第一个节点,并更新最后一个节点指针
        if (head->first == NULL)
        {
            head->first = p;
            head->last = p;
            p->prev = NULL; // 第一个节点的前一个节点指针为NULL
        }
        else
        {
            // 如果链表不为空,则将新节点连接到链表的最后一个节点,并更新最后一个节点指针
            head->last->next = p;
            p->prev = head->last;
            head->last = p;
        }
        p->next = NULL;  // 更新新节点的下一个节点指针为NULL
        head->num++;     // 更新链表节点数量
        scanf("%d", &x); // 继续读取用户输入的整型数据
    }
    return head; // 返回创建好的带头结点的双向链表
}

// 判空
bool Is_Head(struct Head *head)
{
    if (head->num == 0 && head->first == NULL && head->last == NULL)
        return true;
    return false;
}

/*
       Print_DoubleLinkedListWithHead:输出一条带头结点的整型双向链表
       @head:要输出的链表的头节点指针

       返回值:
           无
*/
void Print_DoubleLinkedListWithHead(struct Head *head)
{
    if (head == NULL)
        return;
    struct Node *p = head->first;
    printf("=========================\n");
    if (Is_Empty_LinkedListWithHead(head))
    {
        printf("num = %d\n", head->num);
    }
    else
    {
        printf("num = %d, first->data = %d, last->data = %d\n", head->num,
               head->first->data, head->last->data);
    }
    printf("Next:");
    while (p)
    {
        printf("%d ", p->data);
        p = p->next;
    }

    printf("\n");
    printf("Prev:");
    p = head->last;
    while (p)
    {
        printf("%d ", p->data);
        p = p->prev;
    }

    printf("\n");
}

/*
        Insert_node_y:在head指向的带头结点的双向链表中,找到值为x的节点,在其前面增加一个值为y的节点
        如果有多个值为x的节点则在第一个前面增加
        如果没有则增加在最后
        @head:
        @x:
        @y:

        返回值:
            无
*/
struct Head *Insert_node_y(struct Head *head, Elemtype x, Elemtype y)
{
    if (head == NULL)
        return head;
    // 创造新节点保存y
    struct Node *pnew = malloc(sizeof(*pnew));
    pnew->data = y;
    pnew->next = NULL;
    pnew->prev = NULL;

    // 查找
    struct Node *p = head->first; // 遍历指针,从链表的第一个节点开始遍历
    struct Node *pre = NULL;      // 前驱指针,用于记录当前节点的前一个节点
    while (p)
    {
        if (p->data == x)
            break;
        pre = p;
        p = p->next;
    }

    // 增加
    if (p) // 找到x
    {
        if (p == head->first) // x在首节点
        {
            pnew->next = p;
            head->first = pnew;
            p->prev = pnew;
        }
        else // x不在首节点
        {
            pnew->next = p;
            pre->next = pnew;
            p->prev = pnew;
            pnew->prev = pre;
        }
    }
    else // 未找到
    {
        if (Is_Head(head))
            head->first = head->last = pnew; // 首尾节点都指向新节点
        else
        {
            head->last->next = pnew;
            pnew->prev = head->last;
            head->last = pnew;
        }
    }
    head->num++;
    return head;
}

struct Head *Insert_node_y_2(struct Head *head, Elemtype x, Elemtype y)
{
    if (head == NULL)
        return head;

    // 创建新节点保存y
    struct Node *pnew = malloc(sizeof(*pnew)); // 创建新节点并分配内存空间
    pnew->data = y;                            // 设置新节点的数据为y
    pnew->next = NULL;                         // 设置新节点的下一个节点指针为NULL,表示当前节点为链表末尾节点
    pnew->prev = NULL;                         // 设置新节点的前一个节点指针为NULL,表示当前节点为链表首节点

    // 遍历链表查找值为x的节点
    struct Node *p = head->first; // 使用指针p遍历链表,从首节点开始
    while (p)
    {
        if (p->data == x) // 如果当前节点的数据等于x,则表示找到了目标节点
            break;
        p = p->next; // 否则继续向后遍历下一个节点
    }

    // 插入新节点
    if (p) // 如果找到了值为x的节点
    {
        if (p->prev) // 如果x节点不是首节点
        {
            p->prev->next = pnew; // 将新节点插入到x节点之前
            pnew->prev = p->prev;
        }
        else // 如果x节点是首节点
        {
            head->first = pnew; // 更新首节点为新节点
        }
        pnew->next = p; // 更新新节点的下一个节点为x节点
        p->prev = pnew; // 更新x节点的前一个节点为新节点
    }
    else // 如果未找到值为x的节点
    {
        if (head->last) // 如果链表非空
        {
            head->last->next = pnew; // 将新节点插入到链表末尾
            pnew->prev = head->last;
            head->last = pnew; // 更新链表末尾为新节点
        }
        else // 如果链表为空
        {
            head->first = pnew; // 更新首节点为新节点
            head->last = pnew;  // 更新末尾节点为新节点
        }
    }
    head->num++; // 增加链表节点数量
    return head; //
}

/*
       Delete_all_x:在head指向的带头结点的双向链表中,找到值为x的节点,将其删除
   如果有多个值为x的节点则全部删除
       如果没有则不删除
       @head:
       @x:
       @y:

       返回值:
           无
*/
void Delete_all_x(struct Head *head, Elemtype x)
{
    if (head == NULL)
    {
        return;
    }

    struct Node *p = head->first;
    struct Node *pre = NULL;

    while (p)
    {

        // 查找
        while (p)
        {
            if (p->data == x)
                break;
            pre = p;
            p = p->next;
        }

        // 删除
        if (p)
        {
            if (p == head->first) // 如果是首节点
            {
                if (head->first == head->last) // 如果只有一个
                {
                    head->last = NULL;
                }
                head->first = p->next;
                if (head->first != NULL)
                {
                    head->first->prev = NULL;
                }
                p->next = NULL;
                free(p);
                p = head->first;
            }

            else if (p == head->last) // 如果p在尾节点
            {
                head->last = pre;
                pre->next = NULL;
                p->prev = NULL;
                free(p);
                p = NULL;
            }

            else
            {
                pre->next = p->next;
                p->next->prev = pre;
                p->next = NULL;
                p->prev = NULL;
                free(p);
                p = pre->next;
            }
            head->num--;
        }
        printf("-------\n");
    }
}

void Delete_all_x_2(struct Head *head, Elemtype x)
{
    if (head == NULL)
    {
        return; // 如果链表为空,直接返回
    }

    struct Node *p = head->first; // 使用指针p遍历链表,从首节点开始
    struct Node *next = NULL;     // 用于暂存下一个节点
    struct Node *pre = NULL;      // 用于记录当前节点的前一个节点

    while (p != NULL)
    { // 循环查找和删除值为x的节点
        if (p->data == x)
        {                   // 如果当前节点的数据等于x,则删除该节点
            next = p->next; // 先保存下一个节点的指针
            if (p == head->first)
            { // 如果是首节点
                head->first = next;
                if (next != NULL)
                {
                    next->prev = NULL; // 更新新的首节点的前一个节点指针为NULL
                }
                else
                { // 如果只有一个节点
                    head->last = NULL;
                }
            }
            else
            {
                pre->next = p->next; // 将前一个节点的next指针指向下一个节点
                if (next != NULL)
                {
                    next->prev = pre; // 更新下一个节点的prev指针为前一个节点
                }
                else
                {                     // 如果是尾节点
                    head->last = pre; // 更新尾节点为前一个节点
                }
            }
            free(p);     // 释放当前节点的内存空间
            p = next;    // 移动到下一个节点
            head->num--; // 减少链表节点数量的计数器
        }
        else
        {
            pre = p;     // 记录当前节点为前一个节点
            p = p->next; // 移动到下一个节点
        }
    }
}

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值