一.概念
1.链表的分类。
链表有很多种**,有2^3种**
二、链表的图像。
1.单向或者双向 :
2. 带头或者不带头:
3.循环或者不循环:
三、双向链表(带头双向循环链表)
1.链表的实现:
1.****List.c文件(代码如下:)
cpp
#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;
}
//双向链表的初始化
void LTInit(LTNode** pphead)
{
//创建一个哨兵位(头节点)
*pphead = LTBuyNode(-1);
}
//打印链表
void LTPrint(LTNode* 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 newnode next phead->prev
newnode->next = phead;
newnode->prev=phead->prev;
phead->prev->next = newnode;
phead->prev = newnode;
}
//头插
void LTPushFront(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* newnode = LTBuyNode(x);
newnode->next = phead->next;
newnode->prev = phead;
phead->next->prev = newnode;
phead->next = newnode;
}
//判断链表是否为空
bool LTEmpty(LTNode* phead)
{
assert(phead);
return phead->next == phead;
}
//删除
//尾删
void LTPopBack(LTNode* phead)
{
assert(phead);
assert(!LTEmpty(phead));
LTNode* del = phead->prev;
LTNode* prev = del->prev;
prev->next = phead;
phead->prev = prev;
free(del);
del = NULL;
}
//头删
void LTPopFront(LTNode* phead)
{
assert(phead);
assert(!LTEmpty(phead));
LTNode* del = phead->next;
del->next->prev = phead;
phead->next = del->next;
free(del);
del = NULL;
}
//查找
LTNode* LTFind(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* pcur = phead->next;
while (pcur!=phead)
{
if (pcur->data == x)
{
return pcur;
}
pcur = pcur->next;
}
return NULL;
}
//指定pos位置之后插入数据
void LTInsert(LTNode* pos, LTDataType x)
{
assert(pos);
LTNode* newnode = LTBuyNode(x);
//pos newnode pos->next
newnode->next = pos->next;
newnode->prev = pos;
pos->next->prev = newnode;
pos->next = newnode;
}
//指定位置删除数据
void LTErase(LTNode* pos)
{
assert(pos);
//pos->prev pos pos->next
pos->prev->next = pos->next;
pos->next->prev = pos->prev;
free(pos);
pos = NULL;
}
//销毁
void LTDestory(LTNode** pphead)
{
assert(pphead && *pphead);
LTNode* pcur = (*pphead)->next;
while (pcur!=*pphead)
{
LTNode* Next = pcur->next;
free(pcur);
pcur = Next;
}
//销毁哨兵位
free(*pphead);
*pphead = NULL;
pcur = NULL;
}
2.List.h文件(代码如下:)
cpp
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
//定义双向链表结点的结构
typedef int LTDataType;
typedef struct ListNode
{
LTDataType data;
struct ListNode* next;
struct ListNode* prev;
}LTNode;
//双向链表的初始化
void LTInit(LTNode** pphead);
//第一个参数传一级还是二级,要看pphead指向的结点会不会发生改变
//如果发生改变,那么pphead的改变要影响实参,传二级
//如果不发生改变,那么pphead不会影响实参,传一级
//打印链表
void LTPrint(LTNode* phead);
//插入
//尾插
void LTPushBack(LTNode* phead, LTDataType x);
//头插
void LTPushFront(LTNode* phead, LTDataType x);
//删除
//尾删
void LTPopBack(LTNode* phead);
//头删
void LTPopFront(LTNode* phead);
//判断链表是否为空
bool LTEmpty(LTNode* phead);
//查找
LTNode* LTFind(LTNode* phead, LTDataType x);
//指定位置插入数据
void LTInsert(LTNode* pos, LTDataType x);
//指定位置删除数据
void LTErase(LTNode* pos);
//销毁
void LTDestory(LTNode** pphead);
3.test.c文件(代码如下:)
cpp
#include "List.h"
void ListTest01()
{
//创建双向链表变量
LTNode* Plist = NULL;
//初始化
LTInit(&Plist);
//尾插测试
LTPushBack(Plist,1);
LTPushBack(Plist,2);
LTPushBack(Plist,3);
LTPushBack(Plist,4);
LTPrint(Plist);
//查找
LTNode* pos = LTFind(Plist, 1);
if (pos == NULL)
{
printf("没有找到!\n");
}
else
{
printf("找到了!\n");
}
//指定pos位置之后插入数据
LTInsert(pos, 2);
LTPrint(Plist);//1->2->2->3->4->
//指定位置删除数据
LTErase(pos);
LTPrint(Plist);//2->2->3->4->
//头删
/*LTPopFront(Plist);
LTPrint(Plist);*/
//尾删
/*LTPopBack(Plist);
LTPrint(Plist);*/
//头插测试
/*LTPushFront(Plist,1);
LTPrint(Plist);
LTPushFront(Plist,2);
LTPrint(Plist);
LTPushFront(Plist,3);
LTPrint(Plist);
LTPushFront(Plist,4);
LTPrint(Plist);*/
//销毁
LTDestory(&Plist);
}
int main()
{
ListTest01();
return 0;
}