手撕【双向链表】带头双向循环(2)

目录

Test.c

DList.h

DList.c

SLInsert

 SLErase

DList.c总代码

顺序表和链表的对比


今天继续再双向循环链表的基础上做修改。

❓提问:请你在10分钟内写一个带头双向循环链表。

其实我们只要把SLInsert 和 SLErase 写好就大功告成了!

Test.c

#include"Dlist.h"
int main()
{
	SL* phead = SLInit();
	//头插
	SLPushFront(phead, 7);
	SLPushFront(phead, 77);
	SLPushFront(phead, 9);
	SLPushFront(phead, 99);
	SLPrint(phead);
	//头删
	SLPopFront(phead);
	SLPopFront(phead);
	SLPrint(phead);
	//尾插
	SLPushBack(phead,8);
	SLPushBack(phead, 88);
	SLPrint(phead);
	//尾删
	SLPopBack(phead);
	SLPopBack(phead);
	SLPrint(phead);
	//
	SLDestory(phead);
	phead = NULL;
	return 0;
}

DList.h

#pragma once
#include
#include
#include
typedef int SLDataType;
typedef struct SListNode
{
	SLDataType val;
	struct SListNode* prev;
	struct SListNode* next;
}SL;
//初始化
SL* SLInit();
//打印数据
SL* SLPrint(SL* phead);
//查询
SL* SLFind(SL* phead, SLDataType x);
//头插
void SLPushFront(SL* phead, SLDataType x);
//头删
void SLPopFront(SL* phead);
//尾插
void SLPushBack(SL* phead, SLDataType x);
//尾删
void SLPopBack(SL* phead);
//在pos的前面插入
void SLInsert(SL* pos, SLDataType x);
//删除pos位置
void SLErase(SL* pos);
//销毁
void SLDestory(SL* phead);

DList.c

SLInsert

//在pos的前面插入
void SLInsert(SL* pos, SLDataType x)
{
	assert(pos);
	SL* cur = pos->prev;
	SL* newnode = Createnewnode(x);
	newnode->next = pos;
	pos->prev = newnode;
	cur->next = newnode;
	newnode->prev = cur;
}

 SLErase

//删除pos位置
void SLErase(SL* pos)
{
	assert(pos);
	SL* cur = pos->prev;
	SL* tail = pos->next;
	cur->next = tail;
	tail->prev = cur;
	free(pos);
	pos = NULL;
}

DList.c总代码

#include"Dlist.h"
//创建新的节点
SL* Createnewnode(SLDataType x)
{
	SL* newnode = (SL*)malloc(sizeof(SL));
	newnode->val = x;
	newnode->prev = NULL;
	newnode->next = NULL;
	return newnode;
}
//初始化
SL* SLInit()
{
	SL* phead = Createnewnode(-1);
	phead->prev = phead;
	phead->next = phead;
	return phead;
}
//打印
SL* SLPrint(SL* phead)
{
	assert(phead);
	assert(phead->next != phead);//不打印头节点
	SL* cur = phead->next;
	while (cur != phead)
	{
		printf("<=%d=>", cur->val);
		cur = cur->next;
	}
	printf("\n");
}
//查询
SL* SLFind(SL* phead, SLDataType x)
{
	assert(phead);
	SL* cur = phead->next;
	while (cur != phead)
	{
		if (cur->val == x)
		{
			return cur;
		}
	}
	return NULL;
}
//在pos的前面插入
void SLInsert(SL* pos, SLDataType x)
{
	assert(pos);
	SL* cur = pos->prev;
	SL* newnode = Createnewnode(x);
	newnode->next = pos;
	pos->prev = newnode;
	cur->next = newnode;
	newnode->prev = cur;
}
//删除pos位置
void SLErase(SL* pos)
{
	assert(pos);
	SL* cur = pos->prev;
	SL* tail = pos->next;
	cur->next = tail;
	tail->prev = cur;
	free(pos);
	pos = NULL;
}
//头插
void SLPushFront(SL* phead, SLDataType x)
{
	SLInsert(phead->next, x);
}
//头删
void SLPopFront(SL* phead)
{
	assert(phead->next != phead);//不删除头节点
	SLErase(phead->next);
}
//尾插
void SLPushBack(SL* phead, SLDataType x)
{
	SLInsert(phead, x);
}
//尾删
void SLPopBack(SL* phead)
{
	assert(phead->next != phead);//不删除头节点
	SLErase(phead->prev);
}
//销毁
void SLDestory(SL* phead)
{
	assert(phead);
	SL* cur = phead->next;
	while (cur != phead)
	{
		SL* tmp = cur->next;
		free(cur);
		cur = tmp;
	}
	free(phead);
	cur = NULL;
}

 手撕【双向链表】带头双向循环(2)_第1张图片

 是不是很简单,动手快速写一写吧!!

顺序表和链表的对比

手撕【双向链表】带头双向循环(2)_第2张图片

链表(双向)的优势:

  • 任意位置插入删除都是O(1)
  • 知道pos位置并且插入和删除,都是O(N)  //后期学习哈希可以达到O(1)
  • 按需求申请释放,合理利用空间,不存在浪费

链表(双向)劣势:

  • 下标随机访问不方便O(N) //不支持高效排序

顺序表优势:

  • 支持下标随机访问O(1)
  • CPU高速缓存命中率比较高 

 顺序表劣势:

  • 头部或者中间插入删除效率低,要挪动数据。O(N)
  • 空间不够需要扩容,扩容有一定的消耗,且可能存在一定的空间浪费
  • 只适合尾插尾删

有人可能问CPU高速缓存命中率比较高是什么?

 电脑中负责运算就是 CPUGPU(显卡等)。负责存储就是内存硬盘(磁盘/固态)。内存是带电暂时存储,速度相对较快硬盘是不带电,永久存储,读写速度相对慢。

当然除了内存和硬盘这两个存储介质,还有其他的存储介质。就是缓存  虽然内存速度相较于硬盘快,但是对于CPU来说还是慢了,于是就有围绕在CPU附近的缓存。

缓存中,缓存的存储数据越少,速度越快。所以,小的数据会放到寄存器大的数据会放到高速缓存中去。像顺序表/链表/数组这样的数据存储,当然是放到高速缓存中。

那么数据是怎样放入缓存,CPU怎样去访问高速缓存中的数据呢?

  • 首先CPU会到高速缓存中去查看需要访问的数据是否在缓存中
  • 如果在就访问成功(命中)
  • 如果不在(没命中)就把数据 加载 高速缓存中(不是一个一个加载,而是一段一段的加载)
  • 加载之后再去访问

对于顺序表来说,物理结构上的连续,加载和访问时的命中率更高

对于链表来说,只是逻辑上的连续,物理空间可能相隔很远,所以命中率相对没有那么高,而且很容易造成缓存污染(空间存储都是一些无用的数据)

这个也叫:局部性原理

手撕【双向链表】带头双向循环(2)_第3张图片

 想要更加深入的了解【戳一戳】:与程序员相关的CPU缓存知识 | 酷 壳 - CoolShell

✔✔✔✔✔最后感谢大家的阅读,若有错误和不足,欢迎指正!乖乖敲代码哦! 

代码---------→【唐棣棣 (TSQXG) - Gitee.com】

联系---------→【邮箱:[email protected]

你可能感兴趣的:(初阶数据结构,链表,数据结构,c语言)