栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

数据结构初阶——进阶链表

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

数据结构初阶——进阶链表

上一篇的单链表还存在许多的不方便,那么这一篇就来介绍一下更实用、更方便的链表吧。


目录

链表的分类

初始化链表

增加数据

        尾插

        头插

删除数据

        尾删

         头删

随机插入删除

        随机插入

        随机删除

结尾总结


链表的分类
实际中链表的结构非常多样,以下情况组合起来就有8种链表结构

上一篇单链表博客介绍的就是无头单向非循环链表,这一篇就来介绍带头双向循环链表。 


初始化链表

prev指向上一个节点,next指向下一个节点。

初始化函数的返回类型我们定义成结构体指针,如果返回值定义成void类型的话,那就需要传入二级指针。

BuyListNode函数用来申请空间,那么链表是带头的链表,初始化就是申请一块空间,也就是哨兵位,不存放有效数据,它的prev和next都指向自己因为是循环,prev和next意义也就是双向。

那BuyListNode函数

 

这样一来,哨兵位就写好了。 


增加数据

        尾插

这个尾插就不用传入二级指针,上一篇插入为什么会传入二级指针是因为需要改变链表。那传入的是哨兵位的地址,我们不需要改变哨兵位,改变的是哨兵位指向的内容,但是传入的是结构体的指针,这样就能插入删除。

 为了测试,再写一个打印函数

 

 

相比之下这个链表就要方便很多,不需要再一步步找尾节点,头节点的上一个直接就是尾。

        头插

 

看到这里就体现出这种链表的优势,插入都不需要写空链表的情况,这样写就可以包含空链表的情况。


删除数据

        尾删

         头删

 测试一下也没有问题。


随机插入删除

        随机插入

  

既然随机插入写好了,那头插和尾插也就可以复用了。

尾插复用

 

 

头插复用

 

 

        随机删除

 

同样,头删和尾删也可以复用

尾删复用

 

头删复用

 

 


结尾总结

       这就是双向带头循环链表的魅力,虽然是链表的进阶,那么结构就会更复杂,但是在操作的时候可以感觉到非常舒服,操作非常方便,尾插不需要一个一个找,而且提到复用,整个链表只需要把随即插入和删除写好,整个链表也就完成了,如果写的熟练的话5分钟就可以写一个链表。

那么所有的代码还是放到了结尾。

List.h文件

#include 
#include 
#include 

typedef int LTDataType;

typedef struct ListNode
{
	struct List* prev;
	struct List* next;
	LTDataType data;
}LTNode;

//初始化
LTNode* ListInit();

//打印
void ListPrint(LTNode* phead);

//尾插/头插/尾删/头删
void ListPushBack(LTNode* phead, LTDataType x);
void ListPushFront(LTNode* phead, LTDataType x);
void ListPopBack(LTNode* phead);
void ListPopFront(LTNode* phead);

//在pos位置之前插入x
void ListInsert(LTNode* pos, LTDataType x);
//删除pos位置
void ListErase(LTNode* pos);

List.c文件

#define _CRT_SECURE_NO_WARNINGS 1

#include"List.h"

LTNode* BuyListNode(LTDataType x)
{
	LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
	if (newnode == NULL)
	{
		perror("malloc");
		exit(-1);//直接退出程序
	}
	newnode->data = x;
	newnode->prev = NULL;
	newnode->next = NULL;

	return newnode;
}

LTNode* ListInit()
{
	LTNode* phead = BuyListNode(-1);
	phead->prev = phead;
	phead->next = phead;

	return phead;
}

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

}

void ListPushBack(LTNode* phead, LTDataType x)
{
	assert(phead);

	//LTNode* newnode = BuyListNode(x);
	//LTNode* tail = phead->prev;
	//tail->next = newnode;
	//newnode->prev = tail;
	//newnode->next = phead;
	//phead->prev = newnode;

	ListInsert(phead, x);

}

void ListPushFront(LTNode* phead, LTDataType x)
{
	assert(phead);

	//LTNode* newnode = BuyListNode(x);
	//LTNode* next = phead->next;
	//newnode->next = next;
	//next->prev = newnode;
	//newnode->prev = phead;
	//phead->next = newnode;

	ListInsert(phead->next, x);
}

void ListPopBack(LTNode* phead)
{
	assert(phead);
	assert(phead->next != phead);//证明链表为空,就不要删了
	//LTNode* tail = phead->prev;
	//LTNode* tailPrev = tail->prev;

	//free(tail);

	//tailPrev->next = phead;
	//phead->prev = tailPrev;

	ListErase(phead->prev);

}

void ListPopFront(LTNode* phead)
{
	assert(phead);
	assert(phead->next != phead);
	//LTNode* pos = phead->next;
	//LTNode* next = pos->next;

	//phead->next = next;
	//next->prev = phead;

	//free(pos);

	ListErase(phead->next);

}

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

}

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

	prev->next = next;
	next->prev = prev;

	free(pos);

}

同样如果想变得更好看可以自己手写一个菜单,这一篇就介绍到这里。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/874936.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号