一.链表的分类
链表大致分为以下的几种类型
以上的组合一共8种,其中最常用的是不带头单向不循环链表,也就是我们说的单链表,在前面的文章中已经提到了,还有一种就是我们今天提到的带头双向循环链表
带头:
在链表中,我们会定义一个里面没有有效数据的节点,有时候在写的代码的时候运用它会很方便的,这个就叫带头
不带头:
第一个节点是有效节点的叫不带头,单链表就是不带头
循环和不循环
循环
不循环的就是首尾不相连接的
单向和双向链表
二.说明(有点重要)
单向链表传递参数用的是二级指针,带头双向链表传递参数用的是一级指针
单向链表无头,用二级指针是为了应对空链表的时候,在单链表有节点的情况下,其实传一级指针也行,双向链表已经有头了,所以,用一级指针即可。注意,pphead->next里面的箭头是解引用的意思的哈
三.带头双向链表
定义
typedef int SLdatetype;
typedef struct ListNode
{
SLdatetype val;
struct ListNode* next;
struct ListNode* prev;
}ListNode;
初始化链表
ListNode* ListNodeinit()
{
ListNode* phead = (ListNode*)malloc(sizeof(ListNode));
phead->val = -1;//个人习惯,可以是任何数字,不放数字也可以
phead->next = phead;
phead->prev = phead;//刚开始的时候只有一个节点,由于是带头双向链表,前驱和后继节点都指向自己
return phead;
}
四.打印链表
void ListNodeprint(ListNode* phead)
{
assert(phead);
assert(phead->next);
ListNode* pcur = phead->next;
while (pcur!= phead)
{
printf("%d->",pcur->val);
pcur = pcur->next;
}
printf("\n");
}
五.申请一个节点
ListNode* buynode(SLdatetype x)
{
ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
newnode->val = x;
newnode->next = newnode->prev = newnode;
return newnode;
}
六.尾插一个节点
void ListNodepushback(ListNode* phead, SLdatetype x)
{
assert(phead);
ListNode* newnode = buynode(x);
phead->prev->next = newnode;
newnode->prev = phead->prev;
phead->prev = newnode;
newnode->next = phead;
}
七.头插一个节点
void ListNodepushfront(ListNode* phead, SLdatetype x)
{
assert(phead);
ListNode* newnode = buynode(x);
phead->next->prev = newnode;
newnode->next = phead->next;
phead->next = newnode;
newnode->prev = phead;
}
八.尾删一个节点
void ListNodepopback(ListNode* phead)
{
assert(phead);
assert(phead->next);
ListNode* del = phead->prev;
ListNode* prev = del->prev;
phead->prev = prev;
prev->next = phead;
}
九.头删一个节点
void ListNodepopfront(ListNode* phead)
{
assert(phead);
assert(phead->next);
ListNode* del = phead->next;
ListNode* next = del->next;
phead->next = next;
next->prev = phead;
free(del);
del = NULL;
}
十.查找一个节点
ListNode* ListNodefind(ListNode* phead, SLdatetype x)
{
assert(phead);
ListNode* pcur = phead->next;
while (pcur != phead)
{
if (pcur->val == x)
{
return pcur;
}
pcur = pcur->next;
}
return NULL;
}
十一.在pos后面插入一个数据
void ListNodepushpos(ListNode* pos, SLdatetype x)
{
assert(pos);
ListNode* push = buynode(x);
pos->next->prev = push;
push->next = pos->next;
pos->next = push;
push->prev = pos;
}
十二.删除pos位置的节点
void ListNodeerasepos(ListNode* pos)
{
assert(pos);
ListNode* pre = pos->prev;
ListNode* next = pos->next;
pre->next = next;
next->prev = pre;
free(pos);
pos = NULL;
}
十三.摧毁整个链表
void ListNodedestory(ListNode* phead)
{
assert(phead);
ListNode* pcur = phead->next;
while (pcur!=phead)
{
ListNode* next = pcur->next;
free(pcur);
pcur = next;
}
}
注意:在摧毁链表的时候如果要把头节点摧毁的话,必须要使用二级指针,但是为了保持接口的一致性,通常使用一级指针,头节点的释放可以在主函数里面操作
十三.完整的代码
//头文件
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLdatetype;
typedef struct ListNode
{
SLdatetype val;
struct ListNode* next;
struct ListNode* prev;
}ListNode;
//初始化链表,定义一个无效的头节点
ListNode* ListNodeinit();
//链表的打印
void ListNodeprint(ListNode* phead);
//创建一个节点
ListNode* buynode(SLdatetype x);
//尾插一个节点
void ListNodepushback(ListNode* phead, SLdatetype x);
//头插一个节点
void ListNodepushfront(ListNode* phead, SLdatetype x);
//尾删一个节点
void ListNodepopback(ListNode* phead);
//头删一个节点
void ListNodepopfront(ListNode* phead);
//查找一个节点
ListNode* ListNodefind(ListNode* phead, SLdatetype x);
//在pos位置之后插入数据
void ListNodepushpos(ListNode* pos, SLdatetype x);
//删除pos位置的数据
void ListNodeerasepos(ListNode* pos);
//摧毁链表
void ListNodedestory(ListNode* phead);
//源文件
#define _CRT_SECURE_NO_WARNINGS 1
#include"ListNode.h"
ListNode* ListNodeinit()
{
ListNode* phead = (ListNode*)malloc(sizeof(ListNode));
phead->val = -1;
phead->next = phead;
phead->prev = phead;
return phead;
}
void ListNodeprint(ListNode* phead)
{
assert(phead);
assert(phead->next);
ListNode* pcur = phead->next;
while (pcur!= phead)
{
printf("%d->",pcur->val);
pcur = pcur->next;
}
printf("\n");
}
ListNode* buynode(SLdatetype x)
{
ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
newnode->val = x;
newnode->next = newnode->prev = newnode;
return newnode;
}
void ListNodepushback(ListNode* phead, SLdatetype x)
{
assert(phead);
ListNode* newnode = buynode(x);
phead->prev->next = newnode;
newnode->prev = phead->prev;
phead->prev = newnode;
newnode->next = phead;
}
void ListNodepushfront(ListNode* phead, SLdatetype x)
{
assert(phead);
ListNode* newnode = buynode(x);
phead->next->prev = newnode;
newnode->next = phead->next;
phead->next = newnode;
newnode->prev = phead;
}
void ListNodepopback(ListNode* phead)
{
assert(phead);
assert(phead->next);
ListNode* del = phead->prev;
ListNode* prev = del->prev;
phead->prev = prev;
prev->next = phead;
}
void ListNodepopfront(ListNode* phead)
{
assert(phead);
assert(phead->next);
ListNode* del = phead->next;
ListNode* next = del->next;
phead->next = next;
next->prev = phead;
free(del);
del = NULL;
}
ListNode* ListNodefind(ListNode* phead, SLdatetype x)
{
assert(phead);
ListNode* pcur = phead->next;
while (pcur != phead)
{
if (pcur->val == x)
{
return pcur;
}
pcur = pcur->next;
}
return NULL;
}
void ListNodepushpos(ListNode* pos, SLdatetype x)
{
assert(pos);
ListNode* push = buynode(x);
pos->next->prev = push;
push->next = pos->next;
pos->next = push;
push->prev = pos;
}
void ListNodeerasepos(ListNode* pos)
{
assert(pos);
ListNode* pre = pos->prev;
ListNode* next = pos->next;
pre->next = next;
next->prev = pre;
free(pos);
pos = NULL;
}
void ListNodedestory(ListNode* phead)
{
assert(phead);
ListNode* pcur = phead->next;
while (pcur!=phead)
{
ListNode* next = pcur->next;
free(pcur);
pcur = next;
}
}
//测试文件
#define _CRT_SECURE_NO_WARNINGS 1
#include"ListNode.h"
void test()
{
ListNode* phead = ListNodeinit();
ListNodepushback(phead, 1);
ListNodeprint(phead);
ListNodepushback(phead, 2);
ListNodepushback(phead, 3);
ListNodepushback(phead, 4);
ListNodepushback(phead, 5);
ListNodeprint(phead);
ListNodepopfront(phead);
ListNodeprint(phead);
ListNode* pfind = ListNodefind(phead, 3);
if (pfind != NULL)
{
printf("找到了");
}
printf("\n");
ListNodepushpos(pfind, 100);
ListNodeerasepos(pfind);
ListNodeprint(phead);
ListNodedestory(phead);
}
int main()
{
test();
return 0;
}