IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 【数据结构】线性表之双向带头循环链表 -> 正文阅读

[数据结构与算法]【数据结构】线性表之双向带头循环链表


在这里插入图片描述

双向链表的概念

在前面学习链表的时候,不知道大家有没有过感受,链表是通过next链接起来的,这种链接是头去链接尾,但是在尾部就不是那么好往前找到头。
在这里插入图片描述
比如这么一个结构,如果说现在让输出1,2,3,4,5是不是很容易,直接顺序遍历,然后打印data域即可,但是如果需要反着打印的时候大家是不是就难受了,心想:如果5到4有链接,4到3有链接,3到2有链接,2到一有链接,如果是这样的结构,就打印十分方便了。
上面心中所想的结构其实就是双向链表了。
如下:在这里插入图片描述
至于双向带头循环的链表:就是将头尾相连的双向链表了,这种链表结构就非常强大了,我们可以从任一点出发找到别的点。
在这里插入图片描述

算了来张百度百科的图片
在这里插入图片描述
现在来创建一个双向链表的结构:
其实就是多了一个prev指针的链表结构。

typedef struct ListNode
{
	struct ListNode* next;
	struct ListNode* prev;
	LDataType data;
}ListNode;

双向链表的相关函数

初始化创建

注意创建就是指需要有一个头节点,对于双向链表来说,起码得有一个节点的,不然的话那算?算空气。这个节点首先就是自己链接自己的。

ListNode* ListCreate()
{
	ListNode* phead = BuyListNode(0);
	phead->next = phead;
	phead->prev = phead;
	return phead;
}

新建一个节点

ListNode* BuyListNode(LDataType x)
{
	ListNode* node = (ListNode*)malloc(sizeof(ListNode));
	node->next = NULL;
	node->prev = NULL;
	node->data = x;
	return node;
}

头插

头插的两种方式,一种是复用后面的在pos位置插入(对于头插来说pos就是phead->next,注意这里不是phead,phead->next才是指头插),另一种直接实现

复用

void ListPushFront(ListNode* phead, LDataType x)
{
	assert(phead);
	ListInsert(phead->next, x);
}

不复用

void ListPushFront(ListNode* phead, LDataType x)
{
	assert(phead);
	assert(phead->next != phead);//只有一个头节点的时候不要删除了
	ListNode* tail = phead->prev;
	ListNode* tailPrev = tail->prev;
	free(tail);
	tailPrev->next = phead;
	phead->prev = tailPrev;
}

尾插

尾插也是两种实现,依旧是使用pos插入,此时pos是phead,头是连着尾的

复用

void ListPushBack(ListNode* phead, LDataType x)
{
	assert(phead);
	ListInsert(phead, x);
}

不复用

void ListPushBack(ListNode* phead, LDataType x)
{
	assert(phead);
	ListNode* tail = phead->prev;
	ListNode* newnode = BuyListNode(x);
	tail->next = newnode;
	newnode->prev = tail;
	newnode->next = phead;
	phead->prev = newnode;
}

头删

头删的时候注意要讨论不要删除最后的一个节点

复用


void ListPopFront(ListNode* phead)
{
	ListErase(phead->next);//复用头删
}

不复用

void ListPopFront(ListNode* phead)
{
	assert(phead);
	assert(phead->next != phead);
	ListNode* first = phead->next;
	ListNode* firstNext = first->next;
	phead->next = firstNext;
	firstNext->prev = phead;
	free(first);
}

尾删

尾删同理,至少保留一个节点~~

void ListPopBack(ListNode* phead)
{
	ListErase(phead->prev);
}
void ListPopBack(ListNode* phead)
{
	assert(phead);
	assert(phead->next != phead);
	ListNode* tail = phead->prev;
	ListNode* tailPrev = tail->prev;
	free(tail);
	tailPrev->next = phead;
	phead->prev = tailPrev;
}

打印节点

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

查找

ListNode* ListFind(ListNode* phead, LDataType x)
{
	assert(phead);
	ListNode* cur = phead->next;//指向头节点的next才是真实的值域
	while (cur != phead)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

pos处插入节点

前面使用的头插尾插就是复用这个地方,对于为什么头插是phead->next,尾插是phead
在这里插入图片描述

void  ListInsert(ListNode* pos, LDataType x)
{
	assert(pos);
	ListNode* prev = pos->prev;
	ListNode* newNode = BuyListNode(x);
	prev->next = newNode;
	newNode->prev = prev;
	pos->prev = newNode;
	newNode->next = pos;
}

pos处删除节点

void  ListErase(ListNode* pos)
{
	assert(pos);
	ListNode* prev = pos->prev;
	ListNode* next = pos->next;
	free(pos);
	prev->next = next;
	next->prev = prev;
}

判断是否为空

int ListEmpty(ListNode* phead)
{
	return phead->next == phead ? 1 : 0;
}

判断大小

int ListSize(ListNode* phead)
{
	assert(phead);
	int len = 0;
	ListNode* cur = phead->next;//指向头节点的next才是真实的值域
	while (cur != phead)
	{
		len++;
		cur = cur->next;
	}
	return len;
}

销毁操作

void ListDestory(ListNode* phead)
{
	assert(phead);
	ListNode* cur = phead->next;
	while (cur != phead)
	{
		ListNode* next = cur->next;
		free(cur);
		cur = next;
	}
	free(phead);
}
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-01-04 13:41:40  更:2022-01-04 13:41:43 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 17:51:54-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码