目录
1.什么是带头双向循环链表?
2.实现增删查改功能:
2.1使用链表前必须对头节点初始化
2.2尾插
2.3尾删
2.4头插
2.5头删
2.8查找
2.7指定位置插入
2.8指定位置删除
2.9改变数据
编辑
2.10打印
2.11销毁
3.代码
1.什么是带头双向循环链表?
在一个节点中,存放着data数据,前驱指针和后继指针,所以是双向的,既可以从前往后遍历,也可以从后往前遍历;头节点充当哨兵位,所以使链表有了一个头,data不存放数据(通常初始化为-1),prev指向链表的最后一个节点,next指向第一个节点,使其整个链表成环,头节点不是第一个节点,当只存在一个头节点时,链表为空链表。
2.实现增删查改功能:
2.1使用链表前必须对头节点初始化
2.2尾插
2.3尾删
这里del可以不置为NULL,因为del是函数创建的临时变量,出函数后就销毁,只需释放空间即可,不释放空间会导致内存泄漏。
2.4头插
2.5头删
注意改变顺序。
2.6查找
2.7指定位置插入
2.8指定位置删除
2.9改变数据
2.10打印
2.11销毁
这里销毁的只有销毁了链表的节点,没有销毁头节点开辟的空间,所以在这层函数外部还需要手动释放头节点并置为空,这里函数形参也可以是LTNode** pphead,传入头节点的地址的地址,再在函数内部释放置空也是可以的,不过这里为了使形参一致,所以使用第一种方式。
3.代码
//List.h
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int LTDataType;
//带头双向循环链表
typedef struct ListNode
{
LTDataType data;
struct ListNode* prev;
struct ListNode* next;
}LTNode;
//创建结点
LTNode* LTBuyNode(LTDataType x);
//初始化
LTNode* LTInit();
//销毁
void LTDestroy(LTNode* phead);
//打印
void LTPrint(LTNode* phead);
//尾插
void LTPushBack(LTNode* phead, LTDataType x);
//尾删
void LTPopBack(LTNode* phead);
//头插
void LTPushFront(LTNode* phead, LTDataType x);
//头删
void LTPopFront(LTNode* phead);
//在pos位置之后插入数据
void LTInsert(LTNode* pos, LTDataType x);
//在pos位置之前插入数据
void LTInsertBef(LTNode* pos, LTDataType x);
删除pos位置的数据
void LTErase(LTNode* pos);
//查找
LTNode* LTFind(LTNode* phead, LTDataType x);
//改变数据
void LTDataChange(LTNode* phead);
//List.c
#include"List.h"
//创建结点
LTNode* LTBuyNode(LTDataType x)
{
LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
if (newnode == NULL)
{
perror("Malloc Fail!");
exit(1);
}
newnode->data = x;
newnode->next = newnode->prev = newnode;
return newnode;
}
//初始化烧饼位
LTNode* LTInit()
{
LTNode* phead = LTBuyNode(-1);
return phead;
}
//销毁
void LTDestroy(LTNode* phead)
{
assert(phead);
LTNode* pcur = phead->next;
while (pcur != phead)
{
LTNode* next = pcur->next;
free(pcur);
pcur = next;
}
}
//打印
void LTPrint(LTNode* phead)
{
assert(phead);
LTNode* pcur = phead->next;
while (pcur != phead)
{
printf("%d->", pcur->data);
pcur = pcur->next;
}
printf("\n");
}
//尾插
void LTPushBack(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* newnode = LTBuyNode(x);
phead->prev->next = newnode;
newnode->prev = phead->prev;
newnode->next = phead;
phead->prev = newnode;
}
//尾删
void LTPopBack(LTNode* phead)
{
assert(phead);
assert(phead->next != phead);
phead->prev->prev->next = phead;
LTNode* del = phead->prev;
phead->prev = phead->prev->prev;
free(del);
}
//头插
void LTPushFront(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* newnode = LTBuyNode(x);
phead->next->prev = newnode;
newnode->next = phead->next;
phead->next = newnode;
newnode->prev = phead;
}
//头删
void LTPopFront(LTNode* phead)
{
assert(phead);
assert(phead->next != phead);
LTNode* del = phead->next;
phead->next->next->prev = phead;
phead->next = phead->next->next;
free(del);
}
//在pos位置之前插入数据
void LTInsertBef(LTNode* pos, LTDataType x)
{
assert(pos);
LTNode* newnode = LTBuyNode(x);
pos->prev->next = newnode;
newnode->prev = pos->prev;
newnode->next = pos;
pos->prev = newnode;
}
//在pos位置之后插入数据
void LTInsert(LTNode* pos, LTDataType x)
{
assert(pos);
LTNode* newnode = LTBuyNode(x);
pos->next->prev = newnode;
newnode->next = pos->next;
pos->next = newnode;
newnode->prev = pos;
}
//删除pos位置的数据
void LTErase(LTNode* pos)
{
assert(pos);
pos->prev->next = pos->next;
pos->next->prev = pos->prev;
free(pos);
}
//查找
LTNode* LTFind(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* pcur = phead->next;
while (pcur != phead)
{
if (pcur->data == x)
{
return pcur;
}
pcur = pcur->next;
}
printf("Fail!\n");
return NULL;
}
//改变数据
void LTDataChange(LTNode* pos, LTDataType x)
{
assert(pos);
pos->data = x;
}
//Test.c
#define _CRT_SECURE_NO_WARNINGS
#include "List.h"
int main()
{
LTNode* plist = LTInit();
LTPushBack(plist,1);
LTPushBack(plist,2);
LTPushBack(plist,3);
LTPushBack(plist,4);
LTPushFront(plist, 5);
LTPushFront(plist, 6);
LTPushFront(plist, 7);
LTPushFront(plist, 8);
//LTPopBack(plist);
//LTPopBack(plist);
//LTPopBack(plist);
//LTPopBack(plist);
//LTPopBack(plist);
//LTPopBack(plist);
//LTPopBack(plist);
//LTPopBack(plist);
//LTPopBack(plist);
//LTPopFront(plist);
//LTPopFront(plist);
//LTPopFront(plist);
//LTPopFront(plist);
//LTPopFront(plist);
//LTPopFront(plist);
//LTPopFront(plist);
//printf("%d\n", LTFind(plist, 1)->data);
//LTInsert(LTFind(plist, 1), 9);
//LTInsert(LTFind(plist, 2), 10);
//LTInsert(LTFind(plist, 4), 11);
//LTInsert(LTFind(plist, 8), 12);
//LTErase(LTFind(plist, 1));
//LTErase(LTFind(plist, 8));
//LTErase(LTFind(plist, 2));
//LTDataChange(LTFind(plist, 8), 1111);
//LTDataChange(LTFind(plist, 4), 1111);
//LTDataChange(LTFind(plist, 2), 1111);
LTDataChange(LTFind(plist, 999), 1111);
//LTInsertBef(LTFind(plist, 8), 1111);
//LTInsertBef(LTFind(plist, 4), 1111);
//LTInsertBef(LTFind(plist, 2), 1111);
LTInsertBef(LTFind(plist, 999), 1111);
LTPrint(plist);
//销毁
LTDestroy(plist);
free(plist);
plist = NULL;
return 0;
}