没关系,我们今天就来学习一种更加完善的方法!
精彩预告:这种方法可谓是目前所有链表中优点最多,缺点最少的了❗️❗️❗️
打起精神,开始学习吧!💪💪💪
文章目录
一、🏆链表的分类
实际中链表的结构非常多样,以下情况组合起来就有8种链表结构
1.1🏅带头或不带头
1.2🏅单向或双向
1.3🏅循环或非循环
二、🏆带头双向循环链表的优点
先来看一下带头双向循环链表的结构:👇👇👇
接下来,就一起在接口的实现过程中体验它的优点吧🔥🔥🔥
三、🏆带头双向循环链表接口的实现
先来看一下接口实现索要包含的头文件、结构体定义和具体函数的声明👇👇👇
#define _CRT_SECURE_NO_WARNINGS
#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;//存储下一个结点的地址
}ListNode;
//链表的初始化
ListNode* ListInit();
//打印链表内容
void ListPrint(ListNode* phead);
//创建结点
ListNode* CreateNode(LTDataType x);
//尾插
void ListPushBack(ListNode* phead, LTDataType x);
//尾删
void ListPopBack(ListNode* phead);
//头插
void ListPushFront(ListNode* phead, LTDataType x);
//头删
void ListPopFront(ListNode* phead);
//在指定位置插入
void ListInsert(ListNode* pos, LTDataType x);
//在指定位置删除
void ListErase(ListNode* pos);
//查找
void ListFind(ListNode* phead, LTDataType x);
//链表的销毁
void ListDestory(ListNode* phead);
//退出程序
void Exit(ListNode* phead);
3.1🏅链表的初始化
ListNode* ListInit()
{
//为哨兵位开辟空间
ListNode* phead = (ListNode*)malloc(sizeof(ListNode));
if (phead == NULL)
{
printf("malloc failed!\n");
return;
}
else
{
phead->next = phead;//哨兵位的next和prev都指向自己,形成循环结构
phead->prev = phead;
}
}
3.2🏅创建新的结点
ListNode* CreateNode(LTDataType x)
{
ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
if (newnode == NULL)
{
printf("malloc failed!\n");
return;
}
newnode->data = x;
return newnode;
}
创建结点完毕之后,要将该结点返回,以便可以将该结点尾插到链表的最后。
3.3🏅打印链表内容
void ListPrint(ListNode* phead)
{
assert(phead);
if (phead->next == phead)
{
printf("链表为空!\n");
return;
}
ListNode* cur = phead->next;
while (cur != phead)
{
printf("%d ", cur->data);
cur = cur->next;
}
printf("\n");
}
3.4🏅链表的头插
void ListPushFront(ListNode* phead, LTDataType x)
{
assert(phead);
ListNode* newnode = CreateNode(x);
newnode->next = phead->next;
phead->next->prev = newnode;
newnode->prev = phead;
phead->next = newnode;
printf("头插成功!\n");
}
3.5🏅链表的头删
void ListPopFront(ListNode* phead)
{
assert(phead);
if (phead->next == phead)
{
printf("链表为空!\n");
return;
}
ListNode* newfirst = phead->next->next;
free(phead->next);
phead->next = NULL;
phead->next = newfirst;
newfirst->prev = phead;
printf("头删成功!\n");
}
3.6🏅链表的尾插
void ListPushBack(ListNode* phead, LTDataType x)
{
assert(phead);
ListNode* newnode = CreateNode(x);
newnode->prev = phead->prev;
phead->prev->next = newnode;
newnode->next = phead;
phead->prev = newnode;
printf("尾插成功!\n");
}
3.7🏅链表的尾删
void ListPopBack(ListNode* phead)
{
assert(phead);
if (phead->next == phead)
{
printf("链表为空!\n");
return;
}
ListNode* tail = phead->prev;
phead->prev = tail->prev;
tail->prev->next = phead;
free(tail);
tail = NULL;
printf("尾删成功!\n");
}
3.8🏅在指定位置插入
void ListInsert(ListNode* pos, LTDataType x)
{
assert(pos);
ListNode* newnode = CreateNode(x);
ListNode* posprev = pos->prev;
pos->prev = newnode;
newnode->next = pos;
newnode->prev = posprev;
posprev->next = newnode;
printf("插入成功!\n");
}
3.9🏅在指定位置删除
void ListErase(ListNode* pos)
{
assert(pos);
ListNode* posnext = pos->next;
ListNode* posprev = pos->prev;
posnext->prev = posprev;
posprev->next = posnext;
free(pos);
pos = NULL;
printf("删除成功!\n");
}
3.10🏅在链表中查找
void ListFind(ListNode* phead, LTDataType x)
{
assert(phead);
if (phead->next == phead)
{
printf("链表为空!\n");
return;
}
ListNode* cur = phead->next;
while (cur != phead)
{
if (cur->data == x)
{
printf("找到了!\n");
return;
}
cur = cur->next;
}
printf("没找到!\n");
}
3.11🏅链表的销毁
void ListDestory(ListNode* phead)
{
assert(phead);
free(phead);
phead = NULL;
printf("销毁成功!\n");
}
四、总结
加油吧❗️❗️❗️