【数据结构】手把手带你玩转线性表

前言:

哈喽大家好,我是野生的编程萌新,首先感谢大家的观看。数据结构的学习者大多有这样的想法:数据结构很重要,一定要学好,但数据结构比较抽象,有些算法理解起来很困难,学的很累。我想让大家知道的是:数据结构非常有趣,很多算法是智慧的结晶,我希望大家在学习数据结构的过程是一种愉悦的心情感受。因此我开创了《数据结构》专栏,在这里我将把数据结构内容以有趣易懂的方式展现给大家。

 1.线性表的定义

线性表,听名字我们就能感受到,是具有线一样性质的的表。举个鲜明的例子,当我们在上体育课时,一个班的人都排好队,每一排都有一个打头的,一个收尾的,每个人都知道自己前一个是谁,后面一个是谁,这样就如同一根线一样将他们串在了一起,这就可以称为线性表。线性表是数据结构中最基本的一种,它是由n(n>=0)个具有相同类型的元素组成的有限序列。具体来说,线性表由多个元素组成,每个元素都有一个唯一的前驱元素(除第一个元素外)和唯一的后继元素(除最后一个元素外)。这里我们要强调两个点:

  1. 首先它是一个序列,也就是说,元素之间是有顺序的,若存在多个元素,则第一个元素无前驱,最后一个元素无后继,其他元素都有且仅有一个前驱和后继。如果我们在站队时有同学请假,他的位置将会空出来,那就不能排成一队了(没有补位滴情况)。
  2. 线性表还强调有限,我们的班级人数都是有限的,元素个数当然也是有限的。事实上,在计算机处理的对象都是有限的,那种无限的数列,只存在于数学的概念中。

线性表逻辑结构图大致如下:

 线性表有两种存储方式,一种是顺序存储结构,即将元素依次存储在一块连续的内存中;另一种是链式存储结构,即将元素存储在不连续的内存中,通过指针将它们连接起来。我们前面学过的数组也是顺序表类型,除数组外线性表应用场景还有链表、栈、队列等。线性表是一种常见的数据结构,它具有一对一的关系、存储方式灵活、操作简单高效等特点,广泛应用于各种领域。线性表的优点是操作简单、效率高,但是它的缺点是插入和删除操作需要移动大量的元素,时间复杂度较高。在这一篇博客中我们主要介绍线性表中的顺序存储结构中的顺序表。

2.顺序存储结构——顺序表

顺序表是一种线性数据结构,它通过一组连续的存储单元来存储数据元素,元素之间的关系是一对一的关系。顺序表中的元素在内存中是按照其逻辑顺序依次存放的,可以通过元素在顺序表中的位置(下标)来访问和操作元素。听着怎么感觉顺序表这么像数组呢?顺序表的底层结构就是数组,实现了对数组的封装,实现了常用的增删查改等操作,二者主要区别如下:

  1. 结构差异:顺序表是通过一段连续的存储空间存储元素的线性表,而数组则是一种普通的数据结构,可以存储不连续的元素
  2. 动态性:顺序表的长度可以动态调整,当元素数量超过当前存储空间时,可以进行扩容;而数组的长度是固定的,需要在初始化时指定长度。

  3. 访问效率:由于顺序表的元素是连续存储的,所以在存取元素时效率较高,可以通过下标直接访问;而数组由于是按照索引存储,需要通过索引值来访问元素。

  4. 插入和删除操作效率:顺序表的插入和删除操作需要移动元素,所以效率较低;而数组的插入和删除操作由于不需要移动元素,所以效率较高。

  5. 空间占用:顺序表的存储空间由于需要动态调整,所以可能存在一定的空间浪费;而数组的存储空间是固定的,不会出现空间浪费的情况。

 顺序表有两种实现方式:静态顺序表和动态顺序表。静态顺序表是指在程序设计时,为顺序表分配了一段固定大小的存储空间,不允许进行扩容或缩容的操作。由于静态顺序表的大小是固定的,所以需要在定义时预估数据的最大规模,这可能会导致存储空间的浪费或无法满足需求的问题。下面为静态顺序表:

 动态顺序表是指在程序运行时,可以根据实际的数据规模进行动态扩容或缩容的操作。动态顺序表可以根据需要动态调整存储空间的大小,有效地利用了内存空间。但是,在扩容或缩容时需要进行数据的搬迁,会带来一定的时间开销。下面为动态顺序表:

 顺序表适用于需要频繁访问元素或根据下标查找元素的场景。在元素的插入和删除操作较少,或者已知数据规模的情况下,使用静态顺序表更为合适。在元素的插入和删除操作较多,或者数据规模不确定的情况下,使用动态顺序表更为合适。因为静态顺序表的使用确实不常见,极少情况才会使用静态顺序表,在这里我着重和大家介绍动态顺序表。

3.动态顺序表的的实现

动态顺序表的实现我们需要些一些函数来完成顺序表的初始化、销毁,插入、删除等操作,所以这里我们采用多文件的方式来实现。每一部分的函数都会详细讲解。下面为顺序表的结构代码:

typedef int SLDataType;
typedef struct SeqList
{
	SLDataType* a;
	int size;  //顺序表有效的个数
	int capacity;  //顺序表的空间大小
}SL;

3.1顺序表的初始化和销毁

我们在主函数通过顺序表的结构来创建一个顺序表,创建完顺序表我们要干什么呢?当然是初始化啦,我们在初始化。在这里我们将顺序表的地址传递给创建的顺序表初始化函数,用一个指针接收顺序表的地址,通过对指针的解引用我们就可以修改顺序表。在顺序表初始化的时候我们要满足:将线性表的长度和容量都设置为0,表示线性表当前为空,将分配的内存空间的起始地址也置空处理。顺序表的初始化函数代码如下:

void SLInit(SL* ps)
{
	ps->a = NULL;
	ps->size = 0;
    ps->capacity = 0;
}

顺序表的销毁是指将顺序表中的数据元素清空,并释放顺序表占用的存储空间,使之成为一个空表。具体步骤为下:首先,释放顺序表中存储数据元素的内存空间,然后,清空顺序表中的数据元素。注意,顺序表的销毁操作可能会导致数据丢失,所以在执行销毁操作之前,应该确保不再需要使用该顺序表中的数据。顺序表的销毁函数代码如下:

void SLDestroy(SL* ps)
{
	if (ps->a)
		free(ps->a);
	ps->size =0;
    ps->capacity = 0;
}

3.2顺序表的插入和删除

在这一小节主要和大家讲解顺序表的尾插、尾删、头插、头删、任意位置插入、任意位置删除操作。我们在顺序表的插入操作时,我们要先判断顺序表是否已满。如果顺序表已满,则需要进行扩容操作,将顺序表的容量增加一定的大小。所以在介绍顺序表的插入之前我们先写一个函数来为我们判断顺序表是否已满。我们要怎样判断顺序表是否满了呢?只需要判断顺序表中的有效元素个数和空间容量是否相等,相等就是满了呗。这个函数实现如下:

void SLCheckcapacity(SL* ps)
{
	if (ps->size == ps->capacity)//空间已经不足以插入数据
	{
		int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		SLDataType* tmp = (SLDataType*)realloc(ps->a, newcapacity * sizeof(SLDataType));
		if (tmp == NULL)
		{
			perror("realloc");
			return 1;
		}
		ps->a = tmp;
		ps->capacity = newcapacity;
	}
}

在上面的代码中我们使用了一个三目运算符来判断顺序表的空间容量是否为0,如果为0,那么就将它的空间容量修改为4,若不是0,那么就将顺序表的空间容量进行2倍扩容(因为在C++的库中就存在顺序表扩容函数,它扩容就是扩大2倍,这里为了对标那个函数,所以就进行2倍扩容)。扩容不一定百分百成功,所以下面对扩容结果进行判断,如果扩容失败就返回realloc失败。

3.2.1顺序表的尾插和尾删

顺序表尾插操作是指将一个新元素插入到顺序表的末尾。顺序表的尾插步骤如下:

  1. 首先,判断顺序表是否已满,如果已满,则无法插入新元素,插入操作失败。
  2. 如果顺序表未满,则将待插入的新元素放入顺序表最后一个位置。
  3. 更新顺序表的长度数值,将长度加1。

 尾插操作的时间复杂度为O(1),即常数时间复杂度,因为无论顺序表的长度是多少,尾插操作都只需要进行一次操作即可完成。顺序表的尾插函数实现代码如下:

void SLpushBack(SL* ps,SLDataType x)
{
	assert(ps != NULL);//判断
	//1.空间足够用直接尾插
	//2.空间不够现申请空间,再进行尾插
	SLCheckcapacity(ps);
	ps->a[ps->size++] = x;//插入数据
}

顺序表的尾删操作指的是删除顺序表中的最后一个元素。顺序表的删除基本可以分为两个步骤:

  1. 找到最后一个元素的位置。顺序表的元素是按照顺序存储在内存中的,所以最后一个元素的位置就是顺序表的长度减一。
  2. 删除最后一个元素。将最后一个元素的位置上的元素删除,并将顺序表的长度减一。

为什么我会说基本可以分为两个步骤呢?当然是因为还有能偷懒的写法(●'◡'●),我们直接将顺序表的有效长度减一不直接就能实现了吗。 尾删时我们还要考虑一个因素顺序表是不是空的,所以我们写一个函数来判断一下:

bool SLisEmpty(SL* ps)
{
	assert(ps);
	return ps->size == 0;
}

首先老样子判断只想顺序表的指针是否指向空值,下面如果ps指向顺序表中的size等于0,那么返回true,否则返回false。我们来实现一下顺序表尾删函数:

void SLpopBack(SL* ps)
{
	assert(ps != NULL);
	assert(!SLisEmpty(ps));
	ps->size--;
}

 3.2.2顺序表的头插和头删

顺序表的头插操作即在顺序表的第一个位置插入一个元素。顺序表的头插步骤如下:

  1. 判断顺序表是否已满,如果已满则无法进行头插操作。
  2. 如果顺序表未满,则将顺序表中的所有元素向后移动一位,为要插入的元素腾出位置。从最后一个元素开始,将其移动到下一个位置,一直到第一个元素移动到第二个位置。
  3. 将要插入的元素放入顺序表的第一个位置。
  4. 更新顺序表的长度。

我们来实现一下顺序表的头插函数:

void SLpushFront(SL* ps, SLDataType x)
{
	assert(ps != NULL);//判断
	//插入情况和尾插相似
	SLCheckcapacity(ps);
	for (SLDataType i = ps->size; i > 0; i--)
	{
		ps->a[i] = ps->a[i - 1];
	}
	ps->a[0] = x;
	ps->size++;
}

 头插操作的时间复杂度为O(n),其中n为顺序表中已有元素的个数。因为需要将已有元素后移一位,所以操作的时间复杂度与顺序表中已有元素的个数成正比。

顺序表的头删操作是指删除顺序表中第一个元素的操作。顺序表的头删的步骤如下:

  1. 判断顺序表是否为空,如果为空则无法进行头删操作。
  2. 如果顺序表不为空,则将第一个元素移除。
  3. 将后面的元素依次往前移动一位,覆盖掉被删除元素的位置。从第二个元素开始,将其移动到前一个位置,一直到最后一个元素位置。
  4. 更新顺序表的长度。

 我们来实现一下顺序表的头删函数:

void SLpopFront(SL* ps)
{
	assert(ps != NULL);
	for (SLDataType i = 0; i < ps->size - 1; i++)
	{
		ps->a[i] = ps->a[i + 1];
	}
	ps->size--;
}

头删操作的时间复杂度也为O(n),因为需要将后面的元素往前移动一位,所以操作的时间复杂度与顺序表中已有元素的个数成正比。

3.2.3 顺序表的任意插入和任意删除

顺序表中的任意插入操作是指在任意位置插入一个元素。任意位置插入的具体步骤为下:

  1. 判断顺序表是否已满,如果已满则无法插入新元素,给出相应提示。
  2. 判断插入位置是否合法,即在顺序表的范围内,如果不合法则给出相应提示。
  3. 如果插入位置合法,需要将插入位置以及其后面的元素后移一个位置,为新元素腾出空间。
  4. 将要插入的元素放入插入位置。
  5. 更新顺序表的长度。

 我们来实现一下顺序表的任意插入函数:

void SLInsert(SL* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);
	SLCheckcapacity(ps);
	int end = ps->size;
	while (end >= pos)
	{
		ps->a[end] = ps->a[end-1];
		--end;
	}
	ps->a[pos-1] = x;
	ps->size++;
}

当然有的朋友喜欢任意位置之后插入,其实现代码如下:

void SLInsert(SL* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);
	SLCheckcapacity(ps);
	int end = ps->size-1;
	while (end >= pos)
	{
		ps->a[end+1] = ps->a[end];
		--end;
	}
	ps->a[pos] = x;
	ps->size++;
}

顺序表的任意位置删除操作是指在顺序表中删除指定位置的元素。任意位置删除的具体操作步骤如下:

  1. 首先判断删除位置的有效性。
  2. 将指定位置后面的所有元素向前移动一位。从删除位置开始,将删除位置后面的所有元素向前移动一位,覆盖掉删除的元素。可以使用一个循环来实现这个步骤。

  3. 将顺序表的长度减1,表示顺序表中元素的个数减少了一个。

我们来实现一下任意位置删除函数:

void SLErase(SL* ps, int pos)
{
	assert(ps != NULL);
	assert(pos >= 0 && pos < ps->size);
	for (SLDataType i = pos; i < ps->size - 1; i++)
	{
		ps->a[i-1] = ps->a[i];
	}
	ps->size--;
}

任意位置之后删除代码实现:

void SLErase(SL* ps, int pos)
{
	assert(ps != NULL);
	assert(pos >= 0 && pos < ps->size);
	for (SLDataType i = pos; i < ps->size - 1; i++)
	{
		ps->a[i] = ps->a[i + 1];
	}
	ps->size--;
}

4.多文件实现顺序表 

SeqList.h文件:

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int SLDataType;
typedef struct SeqList
{
	SLDataType* a;
	int size;  //顺序表有效的个数
	int capacity;  //顺序表的空间大小
}SL;
void SLInit(SL* ps);//顺序表初始化
void SLDestroy(SL* ps);//顺序表的删除
void SLpushBack(SL* ps,SLDataType x);//尾插数据
void SLpushFront(SL* ps, SLDataType x);//头插数据
void SLpopBack(SL* ps);//尾删数据
void SLpopFront(SL* ps);//头删数据
void SLInsert(SL* ps, int pos, SLDataType x);//任意位置插入数据
void SLErase(SL* ps, int pos);//任意位置删除数据

SeqList.c文件:

#include"SeqList.h"
void SLInit(SL* ps)
{
	ps->a = NULL;
	ps->size = ps->capacity = 0;
}
void SLDestroy(SL* ps)
{
	if (ps->a)
		free(ps->a);
	ps->size = ps->capacity = 0;
}
void SLCheckcapacity(SL* ps)
{
	if (ps->size == ps->capacity)//空间已经不足以插入数据
	{
		int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		SLDataType* tmp = (SLDataType*)realloc(ps->a, newcapacity * sizeof(SLDataType));
		if (tmp == NULL)
		{
			perror("realloc");
			return 1;
		}
		ps->a = tmp;
		ps->capacity = newcapacity;
	}
}
void SLpushBack(SL* ps,SLDataType x)
{
	assert(ps != NULL);//判断
	//1.空间足够用直接尾插
	//2.空间不够现申请空间,再进行尾插
	SLCheckcapacity(ps);
	ps->a[ps->size++] = x;//插入数据
}
void SLpushFront(SL* ps, SLDataType x)
{
	assert(ps != NULL);//判断
	//插入情况和尾插相似
	SLCheckcapacity(ps);
	for (SLDataType i = ps->size; i > 0; i--)
	{
		ps->a[i] = ps->a[i - 1];
	}
	ps->a[0] = x;
	ps->size++;
}
bool SLisEmpty(SL* ps)
{
	assert(ps);
	return ps->size == 0;
}
void SLpopBack(SL* ps)
{
	assert(ps != NULL);
	assert(!SLisEmpty(ps));
	ps->size--;
}
void SLpopFront(SL* ps)
{
	assert(ps != NULL);
	for (SLDataType i = 0; i < ps->size - 1; i++)
	{
		ps->a[i] = ps->a[i + 1];
	}
	ps->size--;
}
void print(SL* ps)
{
	for (int i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->a[i]);
	}
	printf("\n");
}
void SLInsert(SL* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);
	SLCheckcapacity(ps);
	int end = ps->size-1;
	while (end >= pos)
	{
		ps->a[end+1] = ps->a[end];
		--end;
	}
	ps->a[pos] = x;
	ps->size++;
}
void SLErase(SL* ps, int pos)
{
	assert(ps != NULL);
	assert(pos >= 0 && pos < ps->size);
	for (SLDataType i = pos; i < ps->size - 1; i++)
	{
		ps->a[i] = ps->a[i + 1];
	}
	ps->size--;
}

 test.c文件:

#include"SeqList.h"
void Test()
{
	SL sl;
	SLInit(&sl);
	SLpushBack(&sl, 1);
	SLpushBack(&sl, 2);
	SLpushBack(&sl, 3);
	SLpushBack(&sl, 4);
	SLpushBack(&sl, 5);
	print(&sl);
	SLErase(&sl, 2);
	print(&sl);
	SLInsert(&sl, 2, 6);
	print(&sl);
}
int main()
{
	Test();
	return 0;
}

我这里简单写一个函数来测试,测试结果为:

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

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

相关文章

Ubuntu 安装 samba 实现文件共享

1. samba的安装: sudo apt-get install samba sudo apt-get install smbfs2. 创建共享目录 mkdir /home/share sudo chmod -R 777 /home/share3. 创建Samba配置文件: 3.1 保存现有的配置文件 sudo cp /etc/samba/smb.conf /etc/samba/smb.conf.bak3.2 打开现有的文件 sudo…

基于小波交叉谱分析的地震波走时变化测量(MATLAB)

地震波在地球介质中传播&#xff0c;带来了丰富的地下介质物性的信息&#xff0c;为了解地球内部结构及运动变化提供了可能。地球内部地震波速度的差异是人们确定地球圈层结构和横向不均匀性的重要物理参数&#xff0c;地下介质应力的变化和积累是地震的孕育和发生的原因&#…

百面算法工程师 | 传统图像处理——OpenCV

本文给大家带来的百面算法工程师是传统图像处理的面试总结&#xff0c;文章内总结了常见的提问问题&#xff0c;旨在为广大学子模拟出更贴合实际的面试问答场景。在这篇文章中&#xff0c;我们将介绍一些集几何变换和图像平滑处理&#xff0c;并提供参考的回答及其理论基础&…

分布式与集群的区别

先说区别&#xff1a; 分布式是并联工作的&#xff0c;集群是串联工作的。 分布式中的每一个节点都可以做集群。而集群并不一定就是分布式的。 集群举例&#xff1a;比如新浪网&#xff0c;访问的人很多&#xff0c;他可以做一个集群&#xff0c;前面放一个相应的服务器&…

微软必应bing国内广告开户费用?如何开户投放?

当下搜索引擎广告无疑是企业触达潜在客户、提升品牌曝光度的重要途径之一&#xff0c;微软必应&#xff08;Bing&#xff09;作为全球第二大搜索引擎&#xff0c;尽管在国内市场份额上可能不敌某些本土巨头&#xff0c;但其独特的用户群体和国际影响力使其成为众多企业拓展市场…

【强化学习入门】基于DDPG的强化学习控制器设计

最近在看控制领域研究热门–强化学习相关的东西&#xff0c;跟着matlab官方强化学习教程一边看一边学&#xff0c;感觉入门门槛略高&#xff0c;需要补很多机器学习相关的知识&#xff0c;高数概率论那些&#xff0c;摸索了个把月感觉现在只大概会用&#xff0c;原理啥的还没搞…

git 常用命令 git怎么撤销命令 持续更新中!!!!

基本流程 # 拉取仓库 git clone 仓库地址 # 拉取最新版本 git pull # 本地提交 git add . git commit -m "本次提交信息&#xff01;" # 推送上云 git push分支 # 创建分支 git checkout -b cart # 删除本机的分支 git branch -d cart # 切换分支 本地切换到主分支…

热爱电子值得做的电子制作实验

加我zkhengyang&#xff0c;进嵌入式音频系统研究开发交流答疑群(课题组) AM/FM收音机散件制作&#xff0c;磁带随声听散件&#xff0c;黑白电视机散件制作&#xff0c;功放散件制作&#xff0c;闪光灯散件制作&#xff0c;声控灯散件&#xff0c;等等&#xff0c;可提高动手能…

postman常用功能超全使用教程

Postman 使用 一、Postman 简介 Postman是一个接口测试工具,在做接口测试的时候,Postman相当于一个客户端,它可以模拟用户发起的各类HTTP请求(如:get/post/delete/put…等等),将请求数据发送至服务端,获取对应的响应结果。 二、Postman 功能简介 三、Postman 下载安装 Post…

多模态模型Mini-Gemini:代码模型数据均开源,MiniCPM小钢炮2.0全家桶四连发,可以在Android 手机端上运行的大模型,效果还不错

多模态模型Mini-Gemini&#xff1a;代码模型数据均开源&#xff0c;MiniCPM小钢炮2.0全家桶四连发&#xff0c;可以在Android 手机端上运行的大模型&#xff0c;效果还不错。 多模态模型Mini-Gemini&#xff1a;代码模型数据均开源 香港中文大学终身教授贾佳亚团队提出多模态模…

如何将手写数学公式识别?识别工具在这里

如何将手写数学公式识别&#xff1f;在日常学习中&#xff0c;将手写数学公式识别出来可以极大地提高我们的学习效率。通过这一技术&#xff0c;我们能够快速、准确地将手写公式转化为可编辑的文本&#xff0c;省去了繁琐的输入过程。这不仅节约了时间&#xff0c;还减少了因输…

使用Python实现DataFrame中奇数列与偶数列的位置调换

目录 一、引言 二、背景知识 三、问题描述 四、解决方案 五、案例分析与代码实现 六、技术细节与注意事项 七、扩展与应用 八、封装为函数 九、错误处理与健壮性 十、性能优化 十一、总结与展望 一、引言 在数据处理和分析中&#xff0c;数据框&#xff08;DataFra…

Oracle count的优化-避免全表扫描

Oracle count的优化-避免全表扫描 select count(*) from t1; 这句话比较简单&#xff0c;但很有玄机&#xff01;对这句话运行的理解&#xff0c;反映了你对数据库的理解深度&#xff01; 建立实验的大表他t1 SQL> conn scott/tiger 已连接。 SQL> drop table t1 purge…

Windows下安装人大金仓数据库

1、点击安装包进行安装 2、双击进行安装 3、点击确定 4、接着选择下一步 5、勾选接收 6、选择授权文件 7、显示授权文件信息 8、选择安装位置 9、点击安装 10、点击下一步 11、正在进行安装 12、设置密码。123456 13、系统正在进行配置 14、安装完成 15、登…

17 【Aseprite 作图】参考图和颜色

参考图 Aseprite 作图&#xff0c;“打开 - 一张参考图”&#xff0c;再把参考图拉到右边&#xff0c;就可以得到参考图和缩略图 取消选区 通过“选择 - 取消选择”&#xff0c;可以 取消选区 复制参考图的颜色 打开参考图后&#xff0c;参考图的调色板就会出现参考图所有的…

【智能优化算法】白鲨智能优化算法(White Shark Optimizer,WSO)

白鲨智能优化算法(White Shark Optimizer,WSO)是期刊“KNOWLEDGE-BASED SYSTEMS”&#xff08;中科院一区期刊 IF8.6&#xff09;的2022年智能优化算法 01.引言 白鲨智能优化算法(White Shark Optimizer,WSO)的核心理念和基础灵感来自大白鲨的行为&#xff0c;包括它们在导航和…

Freepik图形资源网收购AI图像放大工具Magnific:图像放大技术的融合与创新

近日&#xff0c;全球最大的高质量图形资源网站Freepik宣布收购领先的AI图像放大工具Magnific&#xff0c;这一举措标志着Freepik在图像处理技术领域的重大突破与扩张。Magnific以其独特的高分辨率放大、细节重构与增强、创意滑块调整等功能&#xff0c;赢得了广泛的市场认可和…

vivado新版本兼容老版本,vitis classic兼容sdk教程

new version: vivado版本2023.2 和vitisv classic 2023.2 old version: vivado 2018.3以及之前的版本 打开工程 自动升级到当前版本&#xff0c;选择OK 点击Yes,合并当前的目录架构 点击OK 点击Report IP status 勾选要升级的IP核&#xff0c;点击升级 在项目工程文件夹…

如何编译不同目录下的两个文件

1.直接编译 2.打包成动静态库进行链接

【Redis】RDB持久化和AOF 持久化

分布式缓存 单点 Redis 的问题 数据丢失&#xff08;持久化&#xff09;并发能力不如集群&#xff08;主从集群、读写分离&#xff09;Redis宕机导致服务不可用&#xff08;Redis哨兵&#xff09;存储能力差&#xff08;分片集群&#xff09; Redis 持久化 RDB 持久化 什么…