首先创建三个文件,如下图
list.h包含了需要声明的头文件,当在本项目内的文件需要时,直接声明
#include "list.h"即可;
list.c文件包含了函数执行程序
test.c 文件包含main函数
头文件声明一个结构体,包含一个指向下一个节点的指针(
next
),一个指向上一个节点的指针(prev
),一个数据的类型(data
);及各个执行函数的声明
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int LTDataType;
typedef struct ListNode
{
struct ListNode* next;
struct ListNode* prev;
LTDataType data;
}LTNode;
//malloc一个节点
LTNode* BuyListNode(LTDataType x);
//初始化
LTNode* ListInit();
//打印
void Print(LTNode* phead);
//尾插
void LTPushBack(LTNode* phead, LTDataType x);
//尾删
void LTPopBack(LTNode* phead);
//头插
void LTPushFront(LTNode* phead, LTDataType x);
//头删
void LTPopFront(LTNode* phead);
//查找
LTNode* LTFind(LTNode* phead, LTDataType x);
// 在pos前面进行插入
void LTInsert(LTNode* pos, LTDataType x);
// 删除pos位置的节点
void LTErase(LTNode* pos);
//判断是否只有一个头节点
bool LTEmpty(LTNode* phead);
//求节点长度
size_t LTSize(LTNode* phead);
//销毁
void LTDestroy(LTNode* phead);
开辟一个新的节点
LTNode* BuyListNode(LTDataType x)
{
struct ListNode* node = (LTNode*)malloc(sizeof(LTNode));
if (node == NULL)//若新节点等于NULL,则新节点开辟失败
{
perror("BuyListNode;;malloc");
exit(-1);//退出
}
node->data = x;
node->next = NULL;
node->prev = NULL;
return node;
}
初始化
将next指向自己
将prev指向自己
LTNode* ListInit()
{
struct ListNode* guard = BuyListNode(0);
guard->next= guard ;
guard->prev= guard ;
return guard;
}
打印节点
void Print(LTNode* phead)
{
assert(phead);//哨兵位不能为空
struct ListNode* cur = phead->next;//从哨兵为下一个开始打印
while (cur!=phead)
{
printf("%d ", cur->data);
cur=cur->next;
}
printf("\n");
}
头插
void LTPushFornt(LTNode* phead, LTDataType x)
{
assert(phead);
struct ListNode* newnode = BuyListNode(x);
struct ListNode* first = phead->next;//记录头的下一个节点
newnode->next = first;
phead->next = newnode;
newnode->prev = phead;
first->prev=newnode;
//LTInsert(phead->next, x);
}
尾插
void LTPushBack(LTNode* phead, LTDataType x)
{
assert(phead);
struct ListNode* newnode = BuyListNode(x);
struct ListNode* tail = phead->prev;
newnode->prev = tail;
tail->next = newnode;
newnode->next = phead;
phead->prev=newnode;
//LTInsert(phead, x);
}
尾删
void LTPopBack(LTNode* phead)
{
assert(phead);
assert(phead->next != phead);//只有头节点不能删
struct ListNode* tail = phead->prev;
struct ListNode* tailPrev = tail->prev;
tailPrev->next = phead;
phead->prev = tailPrev;
free(tail);
//LTErase(phead->prev);
}
头删
void LTPopFront(LTNode* phead)
{
assert(phead);
assert(phead->next != phead);
struct ListNode* second = phead->next;
struct ListNode* cur = second;
phead->next = second->next;
phead->next->prev = phead;
free(second);
//LTErase(phead->next);//从头的下一个开始删
}
查找
LTNode* LTFind(LTNode* phead, LTDataType x)
{
struct ListNode* cur = phead->next;//从头的下一个开始查找
while (cur != phead)
{
if (cur->data == x)
{
printf("%d", cur->data);
printf("\n");
return cur;
}
cur = cur->next;
}
return NULL;
}
在pos的前面插入节点
void LTInsert(LTNode* pos, LTDataType x)
{
assert(pos);
struct ListNode* posPrev = pos->prev;
struct ListNode* newnode = BuyListNode(x);
pos->prev = newnode;
posPrev->next = newnode;
newnode->next = pos;
newnode->prev = posPrev;
}
删除pos位置的节点
void LTErase(LTNode* pos)
{
assert(pos);
struct ListNode* posPrev = pos->prev;
struct ListNode* next = pos->next;
free(pos);
posPrev->next = next;
next->prev = posPrev;
}
判断是否为头节点
bool LTEmpty(LTNode* phead)
{
assert(phead);
struct ListNode* cur = phead;
//if (cur->next == phead)
//{
// return true;
//}
//else
//{
// return false;
//}
return cur->next == phead;
}
求节点长度
size_t LTSize(LTNode* phead)
{
struct ListNode* cur = phead;
size_t count = 0;
while (cur != phead)
{
count++;
cur = cur->next;
}
return count;
}
销毁链表
void LTDestroy(LTNode* phead)
{
assert(phead);
struct ListNode* cur = phead->next;//从头的下一个开始释放
struct ListNode* next =cur->next;
while (cur!=phead)//直接释放,不需要链接,记得保存下一个的地址
{
free(cur);
cur = next;
cur = cur->next;
}
free(phead);//最后释放头节点
}