一 . 概念与结构
1.原名:带头双向循环链表
注意:这⾥的“带头”跟前面说的“头结点”是两个概念,实际前⾯的在单链表阶段称呼不严谨,但是为了更好的理解就直接称为单链表的头结点。
2.带头链表⾥的头结点,实际为“哨兵位”,哨兵位结点不存储任何有效元素,只是站在这⾥“放哨的”,是占位的。
3.双向链表的每一个结点中三种“元素”,一个是存放的数据,一个是指向下一个结点的指针,一个是指向上一个结点的指针。双向链表中头结点指向上一个结点的指针指向尾结点,尾结点指向下一个结点的指针指向头结点,因此是循环的。
4.定义双向链表:
typedef int LTDataType;
typedef struct ListNode
{
struct ListNode* next; //指针保存下⼀个结点的地址
struct ListNode* prev; //指针保存前⼀个结点的地址
LTDataType data;
}LTNode;
二. 双向链表的实现
SList.h ----头文件
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
//链表由一个一个的结点组成,因此定义链表就是定义结点,而一个结点有两个部分组成:存储的数据和指针(指向下一个结点的地址)
//定义链表(结点)的结构
typedef int SLTDataType;
typedef struct SListNode
{
SLTDataType data;
struct SListNode* next;
}SLTNode;
//链表的打印
void SLTPrint(SLTNode* phead); //phead指向node1
//插入数据
//二级指针
void SLPushBack(SLTNode** pphead,SLTDataType x);//尾插
void SLPushFront(SLTNode** pphead,SLTDataType x);//头插
void SLTInsert(SLTNode** pphead, SLTNode pos, SLTDataType x);//在指定位置之前插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x);//在指定位置之后插入数据
//删除数据
void SLPopBack(SLTNode** pphead); //尾删
void SLPopFront(SLTNode** pphead); //头删
void SLTErase(SLTNode** pphead, SLTNode* pos);//删除pos结点
void SLTEraseAfter(SLTNode* pos);//删除pos之后的结点
//销毁链表
void SListDestroy(SLTNode** pphead);
SLTNode* SLTFind(SLTNode* phead, SLTDataType x);
SList.c-----源文件
#include"SList.h"
void SLTPrint(SLTNode* phead) //phear指向链表的第一个结点的地址
{
SLTNode* pcur = phead; //pcur指向的是第一个结点的指针
while (pcur)
{
printf("%d->", pcur->data);
pcur = pcur->next;
}
printf("NULL\n");
}
//定义一个申请新结点的函数
SLTNode* SLTBuyNode(SLTDataType x)
{
SLTNode* node = (SLTNode*)malloc(sizeof(SLTNode));
if (node == NULL)
{
perror("malloc fail");
exit(1);
}
node->data = x;
node->next = NULL;
return node;
}
//尾部插入函数 //二级指针
void SLPushBack(SLTNode** pphead, SLTDataType x)
{
assert(pphead);
//pphead接收的是&plist(plist就是指向第一个节点的指针)
// *pphead=plist(解引用pphead)
//申请新结点
SLTNode* newnode = SLTBuyNode(x);
//用链表尾结点指向定义的新结点从而来插入数据
//找尾结点
SLTNode* pcur = *pphead; //此时pcur和phear都为NULL
if (*pphead == NULL)
{
*pphead = newnode;
}
else
{
while (pcur->next)
{
pcur = pcur->next;//pcur下一个指向地址给当前pcur指针;
}
//连接pucr和newnode
pcur->next = newnode;
}
}
//头部插入函数
void SLPushFront(SLTNode** pphead, SLTDataType x)
{
assert(pphead);
SLTNode* newnode = SLTBuyNode(x);
//让新结点newnode的next指针 指向头结点*pphead
newnode->next = *pphead;
*pphead = newnode;
}
//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
assert(pphead);
assert(pos);
if (pos == *pphead)
{
SLPushFront(pphead, x);
}
else
{
SLTNode* newnode = SLTBuyNode(x);
SLTNode* prev = *pphead; //找pos的前一个结点prev(需要从头开始遍历)
while (prev->next != pos)
{
prev = prev->next;//这里是继续循环的操作,prev要一个一个往下找
}
//以上操作已经找到了prev和pos,现在需要在二者中间插入newnode
newnode->next = pos->next;
prev->next = newnode;
}
}
//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{
//要先让新插入的结点newnode指向指定位置的下一个结点pos->next,再让pos->next指针指向newnode
assert(pos);
SLTNode* newnode = SLTBuyNode(x);
newnode = pos->next;
pos->next = newnode;
}
//删除数据
//删除pos结点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
assert(pphead && *pphead);
assert(pos);
//pos为头结点时,要头删
if (pos == *pphead)
{
SLPopFront(pphead);
}
else
{
SLTNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
prev->next = pos->next;
free(pos);
pos = NULL;
}
}
//删除pos之后的结点
void SLTEraseAfter(SLTNode* pos)
{
assert(pos && pos->next);
SLTNode* del = pos->next;//这里为什么要保存pos->next结点?记得看回放
pos->next = pos->next->next;
free(del);
del = NULL;
}
//尾部删除数据
void SLPopBack(SLTNode** pphead)
{
assert(pphead && *pphead); //pphead意味着传的参数不为空,*pphead表示链表不为空
//处理只有一个结点的情况:要删除的就是头结点
if ((*pphead)->next == NULL)
{
free(*pphead);
*pphead = NULL;
}
else
{
//找尾结点的前一个prev和尾结点ptail
SLTNode* prev = NULL;
SLTNode* ptail = *pphead;
while (ptail->next)
{
prev = ptail;
ptail = ptail->next;
}
prev->next = NULL;
free(ptail);
ptail = NULL;
}
}
//头部删除数据
void SLPopFront(SLTNode** pphead)
{
assert(pphead && *pphead);
SLTNode* next = (*pphead)->next;
free(*pphead);
*pphead = next;
}
//销毁链表
void SListDestroy(SLTNode** pphead)
{
assert(pphead && *pphead);
SLTNode* pcur = *pphead;
while (pcur)
{
SLTNode* next = pcur->next;
free(pcur);
pcur = next;
}
*pphead = NULL;
}
//查找数据
SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{
assert(phead);
SLTNode* pcur = phead;
while (pcur)
{
if (pcur->data == x)
{
return pcur;
}
pcur = pcur->next;
}
//没有找到
return NULL;
}