带头循环双向链表详解

目录

一、什么是带头循环双向链表?

1.特点:

2.优点:

二、实现接口

1.前置准备

1.1需要的三个文件

1.2结构体的创建和头文件的引用

2.接口实现

2.1函数创建新节点

2.2打印链表内容

 2.3尾插新节点

2.4头插新节点

 2.5头删节点

2.6尾删节点

 2.7查找节点

2.8在指定位置前插入节点

2.9删除指定位置节点.

2.10摧毁链表

 三、全部代码

1.接口头文件

2.接口实现

3.测试文件


一、什么是带头循环双向链表?

1.特点:

1.带头:有哨兵位节点,它不用存储数据。对链表进行插入删除操作时也不会影响改节点。

2.双向:组成链表的结构体中的结构体成员有数据,上一个节点的地址和下一个节点的地址

3.循环:链表的头结点存储了尾结点的地址,链表的尾结点存储了头节点的地址。

2.优点:

相比单向链表,双向循环链表的优点在于它的尾插找尾巴非常的快    因为它的头节点同时存储了上一个节点的地址,头的上一个即尾。相比无头链表,带头链表的好处在于当没有节点的时候,可以直接通过访问结构体成员的方式来增加相应的指针,而无头的话需要直接对地址进行修改,传变量的时候还需要传递二级指针   不仅不好理解,还易在实现的时候出错。

二、实现接口

1.前置准备

1.1需要的三个文件

先创建两个.c文件,再创建一个头文件,分别命名为test.c,list.c,list.h

test.c用来测试写好的接口                                   list.c存放实现接口的代码

list.h则存放对应函数,头文件,结构体的声明,这样在想使用链表的接口时,直接引用list.h即可,不需要引用别的头文件。 

创建好的环境如图

1.2结构体的创建和头文件的引用

这些内容放在list.h的文件中,到时引用就可以一条龙带走,不需要再引用别的内容

#pragma once//防止头文件二次引用
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int LTDateType;
//这样创建结构体数据类型,不仅是为了和int做区分
//也是为了到时更好的替换,想换直接把int改了就行
typedef struct listnode
{
	struct listnode* prev;//存放上一个节点的地址
	struct listnode* next;//存放下一个节点的地址
	LTDateType data;//该节点存放的数据
}listnode;

2.接口实现

2.1函数创建新节点

创建节点,虽然简单,但我们在很多操作中都会用到,因此把它单独分装成一个接口

listnode* buy_listnode(LTDateType x)
{
	listnode*newnode=(listnode*)malloc(sizeof(listnode));
	if (newnode == NULL)
	{
		perror("buy_listnode");//错误提示
		exit(-1);//节点都没创建出来,直接退出程序
	}
	newnode->data = x;//将新节点的数据初始化成我们需要的
	newnode->next = NULL;//不清楚插入的方式,先初始化成空
	newnode->prev = NULL;
}

2.2打印链表内容

非常经典的操作,遍历一遍链表即可,唯一需要注意的便是,哨兵节点不是链表中真正的成员,它只能算是实现链表的辅助,因此跳过哨兵节点进行打印

void print_list(listnode* phead)
{
	assert(phead);//哨兵节点地址不可能为空
	listnode* head = phead->next;
	//哨兵位节点不存储有效数据,因此phead->next才是头节点
	printf("head<=>");//纯属美观
	while (head != phead)//当head和phead相等意味着已经遍历完一遍链表
	{
		printf("%d<=>", head->data);
		head = head->next;
	}
	printf("\n");
}

 2.3尾插新节点

void list_pushback(listnode*phead,LTDateType x)
//尾插一个新节点,此节点存储x
{
	listnode* newnode = buy_listnode(x);
	//创建一个我们需要的新节点
	listnode* tail = phead->prev;
	//先找尾,尾很显然是哨兵位节点的上一个节点
	tail->next = newnode;
	newnode->prev = tail;
	newnode->next = phead;
	phead->prev = newnode;
}

后面的4行代码是核心,单独在文章中解释,创建了一个新节点,要把它放到链表的末端,尾节点我们已经找到了,接下来就是链接即可

首先明确,新的尾巴是创建出来的新节点,但还没进行链接之前,尾巴还是之前的尾巴

原始链表

第一步: 

第二步: 

 

第三步:

 第四步:

测试代码:

#include"list.h"
void test1()
{
	listnode* plist=NULL;
	plist=init_listnode(plist);
	list_pushback(plist,1);
	list_pushback(plist,2);
	list_pushback(plist,3);
	list_pushback(plist,4);
	print_list(plist);
}
int main()
{
	test1();
}

 测试效果:

2.4头插新节点

这里我就不再画图了,自己画一遍比看别人画一万遍都来的快 

void list_pushfront(listnode* phead, LTDateType x)
{
	listnode* head = phead->next;//找到头节点
	listnode* newnode = buy_listnode(x);//创建新节点
	head->prev = newnode;
	newnode->next = head;
	phead->next = newnode;
	newnode->prev = phead;
}

测试代码:

void test2()
{
	listnode* plist = NULL;
	plist = init_listnode(plist);
	list_pushfront(plist, 1);
	list_pushfront(plist, 2);
	print_list(plist);
	list_pushfront(plist, 10086);
	print_list(plist);
}
int main()
{
	test2();
}

测试效果: 

 2.5头删节点

需要注意的一点便是,我们删的节点不是哨兵节点,哨兵节点是不存放有效数据的,我们删除的是头节点

void list_popfront(listnode*phead)
{
	assert(phead);
	if (phead->next == phead)
	{
		printf("链表为空,操作失败\n");//为空就别删了
		return;
	}
	listnode* head = phead->next;//找到头节点
	phead->next = head->next;
	head->next->prev = phead;
	free(head);//链接完成,彻底删除
}

测试代码:

void test3()
{
	listnode* plist = NULL;
	plist = init_listnode(plist);
	list_pushfront(plist, 1);
	list_pushfront(plist, 2);
	print_list(plist);
	list_pushfront(plist, 10086);
	print_list(plist);
	list_popfront(plist);
	print_list(plist);
	list_popfront(plist);
	print_list(plist);
	list_popfront(plist);
	print_list(plist);
	list_popfront(plist);
	print_list(plist);
}
int main()
{
	test3();
}

测试效果:

 

2.6尾删节点

没什么好说的,和之前的一样关键点在链接上,自己画了图什么都知道

void list_popback(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);
}

测试代码:

void test4()
{
	listnode* plist = NULL;
	plist = init_listnode(plist);
	list_pushfront(plist, 1);
	list_pushfront(plist, 2);
	list_pushfront(plist, 10086);
	print_list(plist);
	list_popback(plist);
	print_list(plist);
	list_popback(plist);
	print_list(plist);
	list_popback(plist);
	print_list(plist);
	list_popback(plist);
	print_list(plist);
}
int main()
{
	test4();
}

测试效果: 

 2.7查找节点

遍历一遍,找不到就返回NULL即可

listnode* list_find(listnode* phead, LTDateType x)
//哨兵节点和目标
{
	assert(phead);
	listnode* head = phead->next;//找到头节点
	while (head!=phead)//相等意味着已经遍历完了
	{
		if (head->data == x)
		//找到目标,直接返回
		{
			return head;
		}
		head = head->next;
	}
	return NULL;//遍历完还找不到,返回空指针
}

2.8在指定位置前插入节点

根据目标进行链接即可

void list_insert(listnode*pos,LTDateType x)
//目标位置,和在其前面插入数据为x的节点
{
	if (pos == NULL)//传空意味着没找到目标
	{
		printf("目标不存在,操作失败\n");
		return;
	}
	listnode*newnode=buy_listnode(x);//创建新节点
	newnode->next = pos;
	newnode->prev= pos->prev;
	pos->prev->next = newnode;
	pos->prev = newnode;
}

测试代码:

void test5()
{
	listnode* plist = NULL;
	plist = init_listnode(plist);
	list_pushfront(plist, 1);
	list_pushfront(plist, 2);
	list_pushfront(plist, 10086);
	print_list(plist);
	listnode*pos=list_find(plist,2);
	list_insert(pos, 888);//在2之前插入888
	print_list(plist);
	list_insert(plist->next, 666);
	//在头节点前插入666,与头插效用一致
	//可以在头插中复用这个函数
	print_list(plist);
	list_insert(plist, 520);
	//在哨兵节点前插入520,与尾插效用一致
	//可以在尾插中复用这个函数
	print_list(plist);


}
int main()
{
	test5();
}

测试效果:

2.9删除指定位置节点.

void list_erase(listnode* pos)
{
	assert(pos && pos->next != pos);
    //pos为空意味着不存在,pos->next==pos意味着为哨兵节点
	pos->next->prev = pos->prev;
	pos->prev->next = pos->next;
	free(pos);
}

测试代码:

void test6()
{
	listnode* plist = NULL;
	plist = init_listnode(plist);
	//list_erase(plist->prev);//尾删,测试报错
	list_pushfront(plist, 1);
	list_pushfront(plist, 2);
	list_pushfront(plist, 3);
	list_pushfront(plist, 4);
	list_pushfront(plist, 5);
	print_list(plist);
	listnode* pos = list_find(plist, 2);
	list_erase(pos);//把2删除
	print_list(plist);
	list_erase(plist->next);//头删
	print_list(plist);
	list_erase(plist->prev);//尾删
	print_list(plist);
}
int main()
{
	test6();
}

测试效果:

2.10摧毁链表

void destory_list(listnode* phead)
{
	listnode* tail = phead->prev;
	while (tail != phead)
	{
		listnode* tmp = tail;//存储尾
		tail = tail->prev;//从后往前遍历
		free(tmp);
		//不需要管什么链接了,直接摧毁就行

	}
	free(phead);//单独摧毁
}

 测试代码:
 

void test7()
{
	listnode* plist = NULL;
	plist = init_listnode(plist);
	//list_erase(plist->prev);//尾删,测试报错
	list_pushfront(plist, 1);
	list_pushfront(plist, 2);
	list_pushfront(plist, 3);
	list_pushfront(plist, 4);
	list_pushfront(plist, 5);
	destory_list(plist);
}
int main()
{
	test7();
}

测试效果:

从监视来看,确实全部释放

 三、全部代码

1.接口头文件

#pragma once//防止头文件二次引用
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int LTDateType;
//这样创建结构体数据类型,不仅是为了和int做区分
//也是为了到时更好的替换,想换直接把int改了就行
typedef struct listnode
{
	struct listnode* prev;//存放上一个节点的地址
	struct listnode* next;//存放下一个节点的地址
	LTDateType data;//该节点存放的数据
}listnode;
listnode* buy_listnode(LTDateType x);
listnode* init_listnode(listnode* phead);
void print_list(listnode* phead);
void list_pushback(listnode* phead, LTDateType x);
void list_pushfront(listnode* phead, LTDateType x);
void list_popfront(listnode* phead);
void list_popback(listnode* phead);
listnode* list_find(listnode* phead, LTDateType x);
void list_insert(listnode* pos, LTDateType x);
void list_erase(listnode* pos);
void destory_list(listnode* phead);

2.接口实现

#define _CRT_SECURE_NO_WARNINGS 1
#include"list.h"
listnode* buy_listnode(LTDateType x)
{
	listnode*newnode=(listnode*)malloc(sizeof(listnode));
	if (newnode == NULL)
	{
		perror("buy_listnode");//错误提示
		exit(-1);//节点都没创建出来,直接退出程序
	}
	newnode->data = x;//将新节点的数据初始化成我们需要的
	newnode->next = NULL;//不清楚插入的方式,先初始化成空
	newnode->prev = NULL;
}
listnode* init_listnode(listnode* phead)
{
	phead = buy_listnode(-1);	//-1是随便给的,初始化哨兵节点中的数据为-1,代表着没意义的数据
	phead->next = phead;//初始化哨兵节点,自己指向自己
	phead->prev = phead;
	return phead;
}
void print_list(listnode* phead)
{
	assert(phead);//哨兵节点地址不可能为空
	listnode* head = phead->next;
	//哨兵位节点不存储有效数据,因此phead->next才是头节点
	printf("head<=>");//纯属美观
	while (head != phead)//当head和phead相等意味着已经遍历完一遍链表
	{
		printf("%d<=>", head->data);
		head = head->next;
	}
	printf("\n");
}
void list_pushback(listnode*phead,LTDateType x)
//尾插一个新节点,此节点存储x
{
	listnode* newnode = buy_listnode(x);
	//创建一个我们需要的新节点
	listnode* tail = phead->prev;
	//先找尾,尾很显然是哨兵位节点的上一个节点
	tail->next = newnode;
	newnode->prev = tail;
	newnode->next = phead;
	phead->prev = newnode;
}
void list_pushfront(listnode* phead, LTDateType x)
{
	listnode* head = phead->next;//找到头节点
	listnode* newnode = buy_listnode(x);//创建新节点
	head->prev = newnode;
	newnode->next = head;
	phead->next = newnode;
	newnode->prev = phead;
}
void list_popfront(listnode*phead)
{
	assert(phead);
	if (phead->next == phead)
	{
		printf("链表为空,操作失败\n");//为空就别删了
		return;
	}
	listnode* head = phead->next;//找到头节点
	phead->next = head->next;
	head->next->prev = phead;
	free(head);//链接完成,彻底删除
}
void list_popback(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);
}
listnode* list_find(listnode* phead, LTDateType x)
//哨兵节点和目标
{
	assert(phead);
	listnode* head = phead->next;//找到头节点
	while (head!=phead)//相等意味着已经遍历完了
	{
		if (head->data == x)
		//找到目标,直接返回
		{
			return head;
		}
		head = head->next;
	}
	return NULL;//遍历完还找不到,返回空指针
}
void list_insert(listnode*pos,LTDateType x)
//目标位置,和在其前面插入数据为x的节点
{
	if (pos == NULL)//传空意味着没找到目标
	{
		printf("目标不存在,操作失败\n");
		return;
	}
	listnode*newnode=buy_listnode(x);//创建新节点
	newnode->next = pos;
	newnode->prev= pos->prev;
	pos->prev->next = newnode;
	pos->prev = newnode;
}
void list_erase(listnode* pos)
{
	assert(pos && pos->next != pos);
	pos->next->prev = pos->prev;
	pos->prev->next = pos->next;
	free(pos);
}
void destory_list(listnode* phead)
{
	listnode* tail = phead->prev;
	while (tail != phead)
	{
		listnode* tmp = tail;//存储尾
		tail = tail->prev;//从后往前遍历
		free(tmp);
		//不需要管什么链接了,直接摧毁就行

	}
	free(phead);//单独摧毁
}

3.测试文件

#define _CRT_SECURE_NO_WARNINGS 1
#include"list.h"
void test1()
{
	listnode* plist=NULL;
	plist=init_listnode(plist);
	list_pushback(plist,1);
	list_pushback(plist,2);
	list_pushback(plist,3);
	list_pushback(plist,4);
	print_list(plist);
}
void test2()
{
	listnode* plist = NULL;
	plist = init_listnode(plist);
	list_pushfront(plist, 1);
	list_pushfront(plist, 2);
	print_list(plist);
	list_pushfront(plist, 10086);
	print_list(plist);
}
void test3()
{
	listnode* plist = NULL;
	plist = init_listnode(plist);
	list_pushfront(plist, 1);
	list_pushfront(plist, 2);
	print_list(plist);
	list_pushfront(plist, 10086);
	print_list(plist);
	list_popfront(plist);
	print_list(plist);
	list_popfront(plist);
	print_list(plist);
	list_popfront(plist);
	print_list(plist);
	list_popfront(plist);
	print_list(plist);
}
void test4()
{
	listnode* plist = NULL;
	plist = init_listnode(plist);
	list_pushfront(plist, 1);
	list_pushfront(plist, 2);
	list_pushfront(plist, 10086);
	print_list(plist);
	list_popback(plist);
	print_list(plist);
	list_popback(plist);
	print_list(plist);
	list_popback(plist);
	print_list(plist);
	list_popback(plist);
	print_list(plist);
}
void test5()
{
	listnode* plist = NULL;
	plist = init_listnode(plist);
	list_pushfront(plist, 1);
	list_pushfront(plist, 2);
	list_pushfront(plist, 10086);
	print_list(plist);
	listnode*pos=list_find(plist,2);
	list_insert(pos, 888);//在2之前插入888
	print_list(plist);
	list_insert(plist->next, 666);
	//在头节点前插入666,与头插效用一致
	//可以在头插中复用这个函数
	print_list(plist);
	list_insert(plist, 520);
	//在哨兵节点前插入520,与尾插效用一致
	//可以在尾插中复用这个函数
	print_list(plist);
}
void test6()
{
	listnode* plist = NULL;
	plist = init_listnode(plist);
	//list_erase(plist->prev);//尾删,测试报错
	list_pushfront(plist, 1);
	list_pushfront(plist, 2);
	list_pushfront(plist, 3);
	list_pushfront(plist, 4);
	list_pushfront(plist, 5);
	print_list(plist);
	listnode* pos = list_find(plist, 2);
	list_erase(pos);//把2删除
	print_list(plist);
	list_erase(plist->next);//头删
	print_list(plist);
	list_erase(plist->prev);//尾删
	print_list(plist);
}
void test7()
{
	listnode* plist = NULL;
	plist = init_listnode(plist);
	//list_erase(plist->prev);//尾删,测试报错
	list_pushfront(plist, 1);
	list_pushfront(plist, 2);
	list_pushfront(plist, 3);
	list_pushfront(plist, 4);
	list_pushfront(plist, 5);
	destory_list(plist);
}
int main()
{
	test7();
}

好了,今天的分享到这里就结束了,感谢各位友友来访,祝各位友友前程似锦O(∩_∩)O

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/57122.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用mysql容器创建主从同步

1、主数据库设置 创建主数据库容器&#xff1a; docker run -d --restartalways --name mysql-master -p 3306:3306 -v /home/apps/mysql-master/conf:/etc/mysql/conf.d -v /home/apps/mysql-master/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD123456 mysql:8.0.16 --lower…

elasticsearch 配置用户名和密码

无密码的其他配置项在&#xff1a;https://blog.csdn.net/Xeon_CC/article/details/132064295 elasticsearch.yml配置文件&#xff1a; xpack.security.enabled: true xpack.security.http.ssl.enabled: true xpack.security.http.ssl.keystore.path: /path/to/elastic-certi…

eNSP interface g0/0/0 报错解决办法

文章目录 1 报错截图2 解决办法2.1 排查设备是否有 GM 接口2.2 更换适合的路由器&#xff0c;并验证 1 报错截图 2 解决办法 2.1 排查设备是否有 GM 接口 查看下设备是否支持 GM 接口&#xff08;GigabitEthernet&#xff09; 方式一&#xff1a;右键路由器设备 - 设置 - 查看…

Redis数据库 | 事务、持久化

&#x1f497;wei_shuo的个人主页 &#x1f4ab;wei_shuo的学习社区 &#x1f310;Hello World &#xff01; Redis事务操作 Redis事务是一组命令的集合&#xff0c;这些命令会作为一个整体被执行&#xff0c;要么全部执行成功&#xff0c;要么全部执行失败&#xff1b;Redis事…

DASCTF 2023 0X401七月暑期挑战赛web复现

目录 <1> Web (1) EzFlask(python原型链污染&flask-pin) (2) MyPicDisk(xpath注入&文件名注入) (3) ez_cms(pearcmd文件包含) (4) ez_py(django框架 session处pickle反序列化) <1> Web (1) EzFlask(python原型链污染&flask-pin) 进入题目 得到源…

VSCode SSH远程连接与删除

1.ubuntu设置 安装SSH服务并获取远程访问的IP地址 在Ubuntu系统中&#xff0c;“CtrlAltT”打开终端工具&#xff0c;执行如下命令安装SSH服务。 sudo apt-get install openssh-server如果安装失败则先安装依赖项。 2.VS Code 设置 2.1安装与设置Remote SSH 打开Windows系…

初识集合和背后的数据结构

目录 集合 Java集合框架 数据结构 算法 集合 集合&#xff0c;是用来存放数据的容器。其主要表现为将多个元素置于一个单元中&#xff0c;用于对这些元素进行增删查改。例如&#xff0c;一副扑克牌(一组牌的集合)、一个邮箱(一组邮件的集合&#xff09;。 Java中有很多种集…

软件测试自动化selenuim的常用方法和属性总结

selenuim其实主要就是使用webdriver实例对象的方法和属性。 常用属性 1 driver.current_url 当前网页的请求地址 2 driver.current_window_handle 句柄&#xff0c;用于页面切换 3 driver.page_source 网页源代码 4 driver.title 网站的title&#xff0c;tab栏上显示的内容…

C# 图表控件库 ScottPlot

推荐使用ScottPlot原因&#xff1a; 1.图形界面简洁&#xff0c;样式丰富 2.代码较少 3.官方提供多种实例源码&#xff0c;并可以直接通过图形界面查看&#xff0c;便于快速开发 Github源码链接&#xff1a;https://github.com/ScottPlot/ScottPlot 官网WindowFrom Demo实例…

132个心理性格趣味测试ACCESS\EXCEL数据库

今天又遇到了一个心理测试的数据库&#xff0c;这个数据库在表结构的设置上很直观&#xff0c;属于那种好的数据库结构&#xff0c;共分三个表&#xff0c;一个是测试项目描述表、一个是测试题选项得分表、一个是根据得分区间解析表&#xff0c;表与表之间通过“question_id”字…

【基础类】—三栏页面布局的方案和优缺点

一、假设高度已知&#xff0c;中间宽度自适应&#xff0c;三栏&#xff08;列&#xff09;布局的方案有哪些&#xff1f; float浮动、absolute绝对定位、flex弹性盒子、table表格布局、grid网格布局 浮动 float <style>* {margin: 0;padding: 0;}.container {width: 1…

pytorch(6)——神经网络基本骨架nn.module的使用

1 神经网络框架 1.1 Module类的使用 NN (Neural network): 神经网络 Containers: 容器 Convolution Layers: 卷积层 Pooling layers: 池化层 Padding Layers: 填充层 Non-linear Activations (weighted sum, nonlinearity): 非线性激活 Non-linear Activations (other): 非线…

Kubernetes (k8s)理论介绍

一&#xff1a;K8s 简介 1、K8s作用 2、K8s 来历 3、为什么要用 K8S? 4、Kubernetes 功能 二&#xff1a;Kubernetes 集群架构与组件 1、Kubernetes 集群架构与组件 2、核心组件 -Master 组件 &#xff08;1&#xff09;Kube-apiserver &#xff08;2&#xff09;Kube…

python爬虫(五)_urllib2:Get请求和Post请求

本篇将介绍urllib2的Get和Post方法&#xff0c;更多内容请参考:python学习指南 urllib2默认只支持HTTP/HTTPS的GET和POST方法 urllib.urlencode() urllib和urllib2都是接受URL请求的相关参数&#xff0c;但是提供了不同的功能。两个最显著的不同如下&#xff1a; urllib仅可以…

【Apollo学习笔记】—— Cyber RT之调度

文章目录 前言相关代码整理 调度介绍Cyber RT的改进实时操作系统资源限制&优先级协程 Cyber RT调度策略任务窃取两种任务类型componen组件自定义任务 Cyber调度实践配置文件DAG文件cyber_launch文件component组件BUILD文件 问题参考 前言 本文是对Cyber RT的学习记录,文章可…

Kafka的零拷贝

传统的IO模型 如果要把磁盘中的某个文件发送到远程服务器需要经历以下几个步骤 (1) 从磁盘中读取文件的内容&#xff0c;然后拷贝到内核缓冲区 (2) CPU把内核缓冲区的数据赋值到用户空间的缓冲区 (3) 在用户程序中调用write方法&#xff0c;把用户缓冲区的数据拷贝到内核下面…

【普通人维护windows的方法,不中毒,不弹窗,不卡顿】

前言 IT人也是普通人&#xff0c;我就说说普通人维护电脑的方法。 我的电脑配置 给大家看看&#xff0c;配置一般&#xff0c;运行软件和游戏&#xff0c;可以保持基本流程 日常维护措施 我不太喜欢设定一些非主流的配置&#xff0c;下了一个360卫士,360其他的套餐可以不用下…

Python开发环境Spyder介绍

前言 嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 Spyder简介 Spyder (前身是 Pydee) 是一个强大的交互式 Python 语言开发环境&#xff0c; 提供高级的代码编辑、交互测试、调试等特性&#xff0c;支持包括 Windows、Linux 和 OS X 系统。 &#x1f447; &#x1f44…

备忘录模式——撤销功能的实现

1、简介 1.1、概述 备忘录模式提供了一种状态恢复的实现机制&#xff0c;使得用户可以方便地回到一个特定的历史步骤。当新的状态无效或者存在问题时&#xff0c;可以使用暂时存储起来的备忘录将状态复原。当前很多软件都提供了撤销&#xff08;Undo&#xff09;操作&#xf…

Google Search Central (Google搜索支持的结构化数据标记)SEO开发设置

Google会根据结构化数据了解网页上的椰蓉&#xff0c;从而优化SEO排名。搜索引擎优化 (SEO) 是提高网站网页在搜索引擎上的曝光度以吸引更多相关流量的过程。 应用场景 海外独立站新闻网站所有需要SEO排名的网站基本都试用当然众多关于SEO的方法这只是其中一点&#xff0c;合理…