C语言数据结构:双向链表的操作实现

        双向链表(Doubly Linked List)是一种常见的线性数据结构。与单链表不同,双向链表的每个节点不仅包含指向下一个节点的指针(next),还包含一个指向前一个节点的指针(prev)。这种结构使得双向链表可以从两个方向遍历,操作更加灵活。

双向链表的特点:

1.双向遍历:可以从头到尾或从尾到头遍历链表。

2.插入和删除更方便:由于有前驱指针,可以更方便地操作节点的前驱和后继。

3.占用更多内存:每个节点需要额外存储一个前驱指针。

对双向链表的操作有:头插法,尾插法,清空链表,遍历链表,得到尾结点,特定位置插入,特定位置删除。

接下来我们通过代码来看对双向链表的操作。

#include <stdio.h>
#include <stdlib.h>
typedef int Elemtype; // 元素类型取别名方便后续更改
// #define Max 100//定义最大链表长度
typedef struct D_link // 结点
{
    // 数据域
    int data;
    // 指针域
    struct D_link *prev; // 指向上一个结点
    struct D_link *next; // 指向下一个结点
} DL;
int insertHead(DL *head, Elemtype e);                  // 头插法
DL *insertTail(DL *head, Elemtype e);                  // 尾插法
void freeList(DL *head);                               // 清空链表
void listNode(DL *head);                               // 遍历链表
DL *gettail(DL *head);                                 // 得到尾结点
int insertDL(DL *head, Elemtype location, Elemtype e); // 特定位置插入
int deleteDL(DL *head, Elemtype location);             // 特定位置删除
DL *head;//声明头结点
int main(int argc, char const *argv[])
{
    head = (DL *)malloc(sizeof(DL));
    insertHead(head, 1);        // 头插法
    DL *tail = gettail(head);   // 建立并得到尾指针
    tail = insertTail(tail, 2); // 尾插法插入并更新尾指针
    tail = insertTail(tail, 3);
    tail = insertTail(tail, 4);
    insertDL(head, 2, 10); // 在第二个位置插入
    listNode(head);        // 遍历链表
    deleteDL(head, 3);     // 删除第三个元素
    listNode(head);        // 遍历链表
    return 0;
}
int insertHead(DL *head, Elemtype e)
{
    if (head == NULL)
    {
        return 0; // 如果 head 是 NULL,插入失败
    }
    DL *p = (DL *)malloc(sizeof(DL));//创建新结点
    p->data = e;//为新结点赋值
    p->prev = head;//新结点指向头结点
    p->next = head->next;//新结点指向头结点的原下一个结点(原第一个元素)
    if (head->next != NULL)//判断链表是否为空
    {
        head->next->prev = p;//不为空时,让原第一个结点的前驱指针指向新结点
    }
    head->next = p;//头结点指针域更新
    return 1;
}
DL *insertTail(DL *tail, Elemtype e)
{
    DL *p = (DL *)malloc(sizeof(DL));//建立新结点
    p->prev = tail;//新结点的前驱指针指向原最后一个结点
    p->data = e;//新结点赋值
    tail->next = p;//原尾结点指向新尾结点
    p->next = NULL;//新尾结点指针域赋空
    return p;//返回新的尾指针
}
void freeList(DL *head)
{
    DL *p = head->next;//创建新指针指向首元节点
    DL *q;//创建用于标记链表的指针
    while (p->next != NULL)//判断是否到尾结点
    {
        q = p->next;//q指针标记链表的下一个释放结点
        free(p);//释放p所指结点的空间
        p = q;//p更新到下一个结点
    }
    head->next = NULL;//头指针指向空
}
void listNode(DL *head)
{
    DL *p = head->next;//遍历指针
    while (p != NULL)//判断是否到尾结点
    {
        printf("%d ", p->data);//先打印结点的数据
        p = p->next;//再更新指针位置
    }
    printf("\n");
}
DL *gettail(DL *head)
{
    DL *p = head;
    while (p->next != NULL)//判断是否到尾结点
    {
        p = p->next;
    }
    return p;
}
int insertDL(DL *head, Elemtype location, Elemtype e)
{
    DL *p = head;
    for (int i = 0; i < location - 1; i++)//寻找插入位置的前一个结点
    {
        p = p->next;
        if (p == NULL)//如果到尾,则插入位置有误,返回
        {
            return 0;
        }
    }
    DL *q = (DL *)malloc(sizeof(DL));//创建新结点
    q->data = e;//新结点赋值
    q->next = p->next;//连接原位置结点
    q->prev = p;//连接前驱结点
    if (p->next != NULL)//判断是否再尾部
    {
        p->next->prev = q;//不在尾部时,将原位置结点的前驱指针指向新结点
    }
    p->next = q;//前趋结点后向指针指向新结点
    return 1;
}
int deleteDL(DL *head, Elemtype location)
{
    DL *p = head;
    for (int i = 0; i < location - 1; i++)//找到删除位置的上一个结点
    {
        p = p->next;
        if (p->next == NULL)//删除位置错误,返回
        {
            return 0;
        }
    }
    DL *q;//新建指针用来释放删除结点
    q = p->next;//q指向目标结点
    p->next = q->next;//目标结点前驱和后继连接
    q->next->prev = p;//目标结点下节点前驱指针指向目标节点的前驱结点
    free(q);//释放目标结点
    return 1;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值