【数据结构】带头双向循环链表基本操作的实现(C语言)
创始人
2024-01-21 00:01:44

🚀 作者简介:一名在后端领域学习,并渴望能够学有所成的追梦人。
🐌 个人主页:蜗牛牛啊
🔥 系列专栏:🛹初出茅庐C语言、🛴数据结构
📕 学习格言:博观而约取,厚积而薄发
🌹 欢迎进来的小伙伴,如果小伙伴们在学习的过程中,发现有需要纠正的地方,烦请指正,希望能够与诸君一同成长! 🌹


文章目录

  • 一、概念与结构
  • 二、基本操作的实现
    • 1.创建结点
    • 2.初始化链表
    • 3.打印链表
    • 4.尾插
    • 5.尾删
    • 6.头插
    • 7.头删
    • 8.查找某个数并返回其指针
    • 9.在某个位置之前插入
    • 10.删除某个位置
    • 11.判断链表是否为空
    • 12.计算链表中有效值的个数
    • 13.销毁链表
  • 三、测试代码

一、概念与结构

无头单向非循环链表结构简单,一般不会单独用来存数据。实际中更多的是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。而带头双向循环链表的结构较为复杂,一般用在单独存储数据。实际中使用的链表数据结构,都是带头双向循环链表,虽然它的结构复杂但是因为结构优势用代码实现起来会变得简单。

结构

二、基本操作的实现

1.创建结点

LTNode* BuyListNode(ListDataType x)
{LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));if (newnode == NULL){perror("malloc");exit(-1);}newnode->val = x;newnode->prev = NULL;newnode->next = NULL;return newnode;
}

2.初始化链表

void ListInit(LTNode** pphead)//初始化
{*pphead = (LTNode*)malloc(sizeof(LTNode));*pphead = BuyListNode(-1);(*pphead)->next = *pphead;(*pphead)->prev = *pphead;
}
//LTNode* ListInit()//初始化
//{
//	LTNode* phead = BuyListNode(-1);//初始化时将头结点置为-1;
//	phead->next = phead;
//	phead->prev = phead;
//	return phead;
//}

初始化链表有两种方式,一种是有返回类型(注释部分),另一种是在初始化函数中给结构体开辟空间(不过注意参数要为二级指针)。因为是带头结点的循环链表,所以prevnext指针都指向自己。

3.打印链表

void ListPrint(LTNode* phead)//打印
{assert(phead);LTNode* cur = phead->next;while (cur != phead){printf("%d ", cur->val);cur = cur->next;}printf("\n");
}

注意while循环的结束条件,保证能够打印链表中的所有有效值。要对头结点进行assert判断,不能为空。

4.尾插

void ListPushBack(LTNode* phead, ListDataType x)//尾插
{assert(phead);LTNode* newnode = BuyListNode(x);LTNode* tail = phead->prev;newnode->next = tail->next;phead->prev = newnode;newnode->prev = tail;tail->next = newnode;//ListInsert(phead, x);}

5.尾删

void ListPopBack(LTNode* phead)//尾删
{assert(phead);assert(phead->next != phead);LTNode* prevnode = phead->prev;prevnode->prev->next = phead;phead->prev = prevnode->prev;free(prevnode);//ListErase(phead->prev);
}

尾删时要注意判断phead->next != phead,不能删除头结点,同时记得要free(prevnode)释放删除后的空间。

6.头插

void ListPushFront(LTNode* phead, ListDataType x)//头插
{assert(phead);LTNode* tail = phead->next;LTNode* newnode = BuyListNode(x);tail->prev = newnode;newnode->next = tail;newnode->prev = phead;phead->next = newnode;//ListInsert(phead->next,x);
}

7.头删

void ListPopFront(LTNode* phead)//头删
{assert(phead);assert(phead->next != phead);LTNode* tail = phead->next;phead->next = tail->next;tail->next->prev = phead;//ListErase(phead->next);
}

8.查找某个数并返回其指针

LTNode* ListFind(LTNode* phead, ListDataType x)//找某个数返回其指针
{assert(phead);LTNode* cur = phead->next;while (cur != phead){if (cur->val == x){return cur;}cur = cur->next;}return NULL;
}

9.在某个位置之前插入

void ListInsert(LTNode* pos, ListDataType x)//在pos之前插入
{assert(pos);LTNode* newnode = BuyListNode(x);LTNode* tail = pos->prev;tail->next = newnode;newnode->prev = tail;newnode->next = pos;pos->prev = newnode;
}

10.删除某个位置

void ListErase(LTNode* pos)//删除pos位置
{assert(pos);LTNode* prevnode = pos->prev;LTNode* nextnode = pos->next;free(pos);prevnode->next = nextnode;nextnode->prev = prevnode;/*pos->next->prev = pos->prev;pos->prev->next = pos->next;free(pos);*/
}

11.判断链表是否为空

bool ListEmpty(LTNode* phead)//判断是否为空,如果是空,返回true
{assert(phead);return phead->next == phead;
}

12.计算链表中有效值的个数

size_t ListSize(LTNode* phead)//计算链表中有效值的个数
{assert(phead);size_t size = 0;LTNode* tail = phead->next;while (tail != phead){size++;tail = tail->next;}return size;
}

13.销毁链表

void ListDestroy(LTNode* phead)//销毁链表 
{assert(phead);LTNode* tail = phead->next;while (tail != phead){LTNode* nextnode = tail->next;free(tail);tail = nextnode;}free(phead);
}

销毁链表时要注意要保证每个结点都释放,同时最后也要将头结点释放free(phead)

三、测试代码

#define _CRT_SECURE_NO_WARNINGS 1
#include 
#include 
#include 
#include 
typedef int ListDataType;
typedef struct ListNode {ListDataType val;struct ListNode* prev;struct ListNode* next;
}LTNode;
LTNode* BuyListNode(ListDataType x)
{LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));if (newnode == NULL){perror("malloc");exit(-1);}newnode->val = x;newnode->prev = NULL;newnode->next = NULL;return newnode;
}
void ListInit(LTNode** pphead)//初始化
{*pphead = (LTNode*)malloc(sizeof(LTNode));*pphead = BuyListNode(-1);(*pphead)->next = *pphead;(*pphead)->prev = *pphead;
}
//LTNode* ListInit()//初始化
//{
//	LTNode* phead = BuyListNode(-1);//初始化时将头结点置为-1;
//	phead->next = phead;
//	phead->prev = phead;
//	return phead;
//}void ListPrint(LTNode* phead)//打印
{assert(phead);LTNode* cur = phead->next;while (cur != phead){printf("%d ", cur->val);cur = cur->next;}printf("\n");
}
void ListPushBack(LTNode* phead, ListDataType x)//尾插
{assert(phead);LTNode* newnode = BuyListNode(x);LTNode* tail = phead->prev;newnode->next = tail->next;phead->prev = newnode;newnode->prev = tail;tail->next = newnode;//ListInsert(phead, x);
}
void ListPopBack(LTNode* phead)//尾删
{assert(phead);assert(phead->next != phead);LTNode* prevnode = phead->prev;prevnode->prev->next = phead;phead->prev = prevnode->prev;free(prevnode);//ListErase(phead->prev);
}
void ListPushFront(LTNode* phead, ListDataType x)//头插
{assert(phead);LTNode* tail = phead->next;LTNode* newnode = BuyListNode(x);tail->prev = newnode;newnode->next = tail;newnode->prev = phead;phead->next = newnode;//ListInsert(phead->next,x);
}
void ListPopFront(LTNode* phead)//头删
{assert(phead);assert(phead->next != phead);LTNode* tail = phead->next;phead->next = tail->next;tail->next->prev = phead;//ListErase(phead->next);
}
LTNode* ListFind(LTNode* phead, ListDataType x)//找某个数返回其指针
{assert(phead);LTNode* cur = phead->next;while (cur != phead){if (cur->val == x){return cur;}cur = cur->next;}return NULL;
}
void ListInsert(LTNode* pos, ListDataType x)//在pos之前插入
{assert(pos);LTNode* newnode = BuyListNode(x);LTNode* tail = pos->prev;tail->next = newnode;newnode->prev = tail;newnode->next = pos;pos->prev = newnode;
}
void ListErase(LTNode* pos)//删除pos位置
{assert(pos);LTNode* prevnode = pos->prev;LTNode* nextnode = pos->next;free(pos);prevnode->next = nextnode;nextnode->prev = prevnode;/*pos->next->prev = pos->prev;pos->prev->next = pos->next;free(pos);*/
}
bool ListEmpty(LTNode* phead)//判断是否为空,如果是空,返回true
{assert(phead);return phead->next == phead;
}
size_t ListSize(LTNode* phead)//计算链表中有效值的个数
{assert(phead);size_t size = 0;LTNode* tail = phead->next;while (tail != phead){size++;tail = tail->next;}return size;
}
void ListDestroy(LTNode* phead)//销毁链表 
{assert(phead);LTNode* tail = phead->next;while (tail != phead){LTNode* nextnode = tail->next;free(tail);tail = nextnode;}free(phead);
}
void TestList()
{//LTNode* plist = ListInit(&plist);LTNode* plist = NULL;ListInit(&plist);ListPushBack(plist, 100);ListPushBack(plist, 200);ListPushBack(plist, 300);ListPushBack(plist, 400);ListPushBack(plist, 500);ListPopBack(plist);ListPopBack(plist);ListPopBack(plist);ListPrint(plist);ListPushFront(plist, 1000);ListPushFront(plist, 2000);ListPushFront(plist, 3000);ListPopFront(plist);ListPopFront(plist);ListPrint(plist);LTNode* pos = ListFind(plist, 1000);if (pos != NULL){ListInsert(pos, 500);ListErase(pos);}ListPrint(plist);if (!ListEmpty(plist))printf("%d\n", ListSize(plist));
}
int main()
{TestList();return 0;
}

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
进口奶粉的排名 荷兰奶粉十大排... 越来越乱的国内奶粉市场让很多宝妈宝爸都不知道该如何选择奶粉品牌,宝宝的安全是第一位,奶粉的质量以及口...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
不用扬鞭自奋蹄 乘势而上千帆竞... 思明区正全力向“两个进位”目标发起冲刺,努力为建设高素质高颜值现代化国际化的厦门作出“思明贡献”。(...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...