双向链表的定义及相关功能实现

本文详细介绍了双向链表的概念,包括其逻辑结构和接口实现,如定义双向链表的结构体、创建空链表、插入节点以及处理头尾指针。展示了如何在指定位置插入数据,以及删除和查找操作的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. 单向链表
    1. 有头
    2. 无头
  1. 单向循环链表
  2. 链式栈(无头单向链表)
  3. 链式队列(有头单向链表)

以上链表均只能从头往后找。即结点只有数据域和一个指向后继结点的指针域next

双向链表即可以从前往后或者从后往前找,这就意味着链表的结点就不能只有一个指针域next了,还需要一个指向前期结点的指针域prior

1.概念

  1. 逻辑结构:线性结构
  2. 存储结构:链式存储

2. 接口实现

2.1. 定义操作双向链表的结构体

双向链表结点结构体

typedef int DLLNDataType;

typedef struct DoubleLinkListNode
{
    DLLNDataType data;
    struct DoubleLinkListNode *next;
    struct DoubleLinkListNode *prior;
}LLN, *LL;

想要遍历该双向链表的话,除了拿到头指针后通过next从前往后遍历,还可以拿到尾指针通过prior从后往前遍历。

这样就意味着操作双向链表又需要两个指针,一个head头指针,一个tail尾指针,类比链式队列,将头尾指针放到一个操作双向链表的结构体里面去。

操作双向链表的结构体

typedef struct DoubleLinkList
{
    LL head;	// 头指针
    LL tail;	// 尾指针
    int len;    // 记录链表长度
} DLL;

假如链表有一百个结点那么长,我想删除98位结点,如果结构体中有链表的长度,可以更加方便的使用尾指针进行操作。

2.2. 创建空的双向链表

2.3. 插入

插入位置结点与其前驱以及新结点三者之间建立联系示意图:

向双向链表指定位置插入数据

// 3. 向双向链表指定位置插入数据
int DLLInsert(DLL *PD, int post, DLLNDataType data)
{
    // 3.1 容错判断 [0, PD->len]
    if (post < 0 || post > PD->len)
    {
        printf("DLLInsert failed, post not at [0, PD->len].\n");
        return -1;
    }

    // 3.2 创建新节点保存插入数据
    LL PNew = (LL)malloc(sizeof(LLN));
    if (NULL == PNew)
    {
        printf("DLLInsert failed, PNew malloc err.\n");
        return -1;
    }
    PNew->data = data;
    PNew->next = PNew->prior = NULL;

    // 3.3 判断插入位置(三种情况)
    // 3.3.1 尾插(尾结点和新结点互相指)
    if (post == PD->len)
    {
        // 互相指
        PNew->prior = PD->tail;
        PD->tail->next = PNew;
        // 尾指针tail后移
        PD->tail = PNew;
        // 长度++
        PD->len++;
    }
    // 3.3.2 中间插
    else
    {
        // 定义伪指针,代替头指针PD->head或尾指针PD->tail去移动
        LL PTemp = NULL;
        // 中间插前半段,PTemp为伪头指针,代替头指针移动。
        if (post < PD->len / 2)
        {
            // PTemp代替头指针移动
            PTemp = PD->head;
            // 移动伪头指针
            for (int i = 0; i <= post; i++)
                PTemp = PTemp->next;
        }
        // 中间插后半段,PTemp为伪尾指针,代替尾指针移动。
        else
        {
            // PTemp代替尾指针移动
            PTemp = PD->tail;
            // 移动伪尾指针
            for (int i = PD->len-1; i > post; i--)
                PTemp = PTemp->prior;
        }
        // 进行插入动作,先前再后
        // 前
        PNew->prior = PTemp->prior;
        PTemp->prior->next = PNew;
        // 后
        PNew->next = PTemp;
        PTemp->prior = PNew;

        // 插入完成后长度+1
        PD->len++;
    }
    return 0;
}

DoubleLinkList.h文件

双向链表功能函数

插入函数int DLLInsert(DLL *PD, int post, DLLNDataType data);
打印函数void DLLPrint(DLL PD);
删除函数(按位置)int DLLDeletePost(DLL *PD, int post);
查找内容函数(返回下标)int DLLFind(DLL PD, DLLNDataType data);
修改内容函数int DLLModify(DLL *PD , int post , DLLNDataType data);
删除函数(按内容)void DLLDeleteData(DLL *PD, DLLNDataType data);
#ifndef _DOUBLELINKLIST_H_
#define _DOUBLELINKLIST_H_

#include<stdio.h>
#include<stdlib.h>
typedef int DLLNDataType;

typedef struct DoubleLinkListNode
{
    DLLNDataType data;
    struct DoubleLinkListNode *next;
    struct DoubleLinkListNode *prior;
}LLN, *LL;

typedef struct DoubleLinkList
{
    LL head;
    LL tail;
    int len;
}DLL;

DLL *DLLInit();
int DLLInsert(DLL *PD, int post, DLLNDataType data);
void DLLPrint(DLL PD);
int DLLDeletePost(DLL *PD, int post);
int DLLFind(DLL PD, DLLNDataType data);
int DLLModify(DLL *PD , int post , DLLNDataType data);
void DLLDeleteData(DLL *PD, DLLNDataType data);
#endif

DoubleLinkList.c文件

#include "DoubleLinkList.h"

DLL *DLLInit()
{
    DLL *PD = (DLL *)malloc(sizeof(DLL));
    if (NULL == PD)
    {
        printf("DLLInit failed, PD malloc err.\n");
        return NULL;
    }
    PD->head = PD->tail = (LL)malloc(sizeof(LLN));
    if (NULL == PD->head || NULL == PD->tail)
    {
        printf("DLLInit failed, PD->head or PD->tail malloc err.\n");
        return NULL;
    }
    PD->head->next = PD->head->prior = NULL;
    PD->len = 0;
    return PD;
}

int DLLInsert(DLL *PD, int post, DLLNDataType data)
{
    if (post < 0 || post > PD->len)
    {
        printf("DLLInsert failed, post illegal.\n");
        return -1;
    }
    LL PNew = (LL)malloc(sizeof(LLN));
    if (NULL == PNew)
    {
        printf("DLLInsert failed, PNew malloc err.\n");
        return -1;
    }
    PNew->data = data;
    PNew->next = PNew->prior = NULL;
    if (post == PD->len) //尾插
    {
        PD->tail->next = PNew;
        PNew->prior = PD->tail;
        PD->tail = PNew;
        PD->len++;
    }
    else //中间插入
    {
        LL PTemp = NULL;
        if (post < PD->len / 2) //len前半段插入
        {
            PTemp = PD->head;
            for (int i = 0; i <= post; i++)
                PTemp = PTemp->next;
        }
        else
        {
            PTemp = PD->tail;
            for (int i = PD->len - 1; i > post; i--) //i = 0 ; i<len-post-1;i++;
                PTemp = PTemp->prior;
        }
        PTemp->prior->next = PNew;
        PNew->prior = PTemp->prior;
        PTemp->prior = PNew;
        PNew->next = PTemp;
        PD->len++;
    }
    return 0;
}

void DLLPrint(DLL PD)
{
    if (PD.head == PD.tail)
    {
        printf("DLLPrint failed, DLL is empty.\n");
        return;
    }
    printf("DoubleLinkList data is ");
    while (PD.head != PD.tail)
    {
        PD.head = PD.head->next;
        printf("%d ", PD.head->data);
    }
    putchar(10);
}

int DLLDeletePost(DLL *PD, int post)
{
    if (post < 0 || post >= PD->len)
    {
        printf("DLLDeletePost failed, post illegal.\n");
        return -1;
    }
    if (post == PD->len - 1) //尾删
    {
        PD->tail = PD->tail->prior;
        free(PD->tail->next);
        PD->tail->next = NULL;
    }
    else
    {
        LL PTemp = NULL;
        if (post < PD->len / 2) //len前半段删除
        {
            PTemp = PD->head;
            for (int i = 0; i <= post; i++)
                PTemp = PTemp->next;
        }
        else
        {
            PTemp = PD->tail;
            for (int i = 0; i < PD->len - post - 1; i++)
                PTemp = PTemp->prior;
        }
        PTemp->prior->next = PTemp->next;
        PTemp->next->prior = PTemp->prior;
        free(PTemp);
        PTemp = NULL;
        PD->len--;
    }
    return 0;
}

int DLLFind(DLL PD, DLLNDataType data)
{
    if (PD.head == PD.tail)
    {
        printf("DLLFind failed, DLL is empty.\n");
        return -1;
    }
    int post = 0;
    while (PD.head != PD.tail)
    {
        PD.head = PD.head->next;
        if (data == PD.head->data)
        {
            printf("data %d's post is %d\n", data, post);
        }
        post++;
    }
    return -1;
}

int DLLModify(DLL *PD, int post, DLLNDataType data)
{
    if (post < 0 || post >= PD->len)
    {
        printf("DLLDeletePost failed, post illegal.\n");
        return -1;
    }
    LL PTemp = NULL;
    if (post < PD->len / 2) //len前半段删除
    {
        PTemp = PD->head;
        for (int i = 0; i <= post; i++)
            PTemp = PTemp->next;
    }
    else
    {
        PTemp = PD->tail;
        for (int i = 0; i < PD->len - post - 1; i++)
            PTemp = PTemp->prior;
    }
    PTemp->data = data;
    return 0;
}

void DLLDeleteData(DLL *PD, DLLNDataType data)
{
    LL H = PD->head->next;
    while (H)
    {
        if (H->data == data)
        {
            if (H == PD->tail)
            {
                PD->tail = PD->tail->prior;
                free(PD->tail->next);
                PD->tail->next = NULL;
            }
            else
            {
                H->prior->next = H->next;
                H->next->prior = H->prior;
                LL PDel = H;
                H = H->next;
                free(PDel);
                PDel = NULL;
                PD->len--;
            }
        }
        else
            H = H->next;
        
    }
}

test.c文件

#include "DoubleLinkList.h"

int main(int argc, char const *argv[])
{
    DLL *PD = DLLInit();
    DLLInsert(PD, 0, 101);
    DLLInsert(PD, 0, 102);
    DLLInsert(PD, 0, 103);
    DLLInsert(PD, 0, 104);
    DLLInsert(PD, 0, 105);
    DLLInsert(PD, 0, 101);
    DLLInsert(PD, 0, 101);
    DLLInsert(PD, 0, 101);
    DLLInsert(PD, 0, 101);
    DLLInsert(PD, 0, 101);
    DLLPrint(*PD);
    DLLInsert(PD, 5, 102);
    DLLInsert(PD, 6, 103);
    DLLInsert(PD, 7, 104);
    DLLInsert(PD, 8, 105);
    DLLPrint(*PD);
    DLLDeletePost(PD, 0);
    DLLPrint(*PD);
    DLLFind(*PD, 102);
    DLLModify(PD, 3, 200);
    DLLPrint(*PD);
    DLLDeleteData(PD,101);
    DLLPrint(*PD);
    return 0;
}

运行结果

makefile文件

CC=gcc
OBJS=test.o DoubleLinkList.o
CFLAGS=-c -g -Wall
# CC=none-linux-gnueabi-gcc
test:$(OBJS)
	$(CC) -o test $(OBJS)
%.o:%.c
	$(CC) $(CFLAGS) $< -o $@
.PHONY:clean
clean:
	$(RM) *.o test

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值