带头结点的双向链表
之前用c语言写了单链表,单链表是每个结点结构体中包含一个指针,指向下一个结点,还有一个数据类型,用于存储当前结点的值。单链表的结构简单,所以会导致在有时候,它有一些弊端,比如需要访问使用某一个结点的前一个结点的时候,就需要重新遍历一次链表来查找这个结点。所以在大多数情况下我们都选择使用双向链表。
双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。
带头节点的双向链表一般就如下图所示:链表的最后一个有效元素指向NULL。头结点中不存储任何信息,只是便于管理,不需要考虑向第一个元素头插的特殊情况。
虽然双向链表的结构看着有些复杂,但是在使用的时候,会比较方便。插入时,只需要修改对应的三个结点的指针指向即可。
下面来看一下具体是怎么实现的:
DLinkList.h
#pragma once
//类型重定义char为链表中的数据类型
typedef char DLinkType;
//结点的结构体(指向前驱结点,后继结点,还有一个数据)
typedef struct DLinkNode {
DLinkType data;
struct DLinkNode* next;
struct DLinkNode* prev;
} DLinkNode;
//初始化一个链表
void DLinkListInit(DLinkNode** head);
//向链表的尾部插入
DLinkNode* DLinkListPushBack(DLinkNode* head, DLinkType value);
//从尾部删除一个结点
void DLinListPopBack(DLinkNode* head);
//往头结点后插入一个结点
void DLinkListPushFront(DLinkNode* head, DLinkType value);
//从头节点删除一个结点
void DLinkListPopFront(DLinkNode* head);
//在链表中查找某个指定结点
DLinkNode* DLinkListFind(DLinkNode* head, DLinkType to_find);
//往指定位置之前插入一个元素
void DLinkListInsert(DLinkNode* pos, DLinkType value);
// 往指定位置之后插入一个元素
void DLinkListInsertAfter(DLinkNode* pos, DLinkType value);
DLinkList.c
#include <stdio.h>
#include <assert.h>
#include <malloc.h>
#include"DLinkList.h"
//初始化一个双链表
//初始化需要做的工作是将头结点malloc出来。
void DLinkListInit(DLinkNode** head)
{
assert(head);
(*head) = (DLinkNode*)malloc(sizeof(DLinkNode));
(*head)->next = NULL;
(*head)->prev = NULL;
}
//创建一个结点
//封装一个函数,便于插入时直接使用。
DLinkNode* CreateNo