【数据结构】堆的实现(向下调整和向上调整法)和堆排序的实现

 

目录

一、堆的概念引入

二、小堆的实现

首先,我们会跟线性表一样建立一个动态数组来存堆的数据

①、堆的初始化--HeapInit

②、小堆的向下调整法的实现

③、堆排序的实现

 ④、堆的插入和向上调整法

 ⑤、删除堆顶数据

⑥、获取堆顶

三、时间复杂度总结:


注:本文logN表示以2为底N的对数,其次本文只实现小堆,因为大小堆的实现方式极其相似

一、堆的概念引入

普通的二叉树不适合用数组来存储的,因为可能会存在大量的空间浪费。而完全二叉树(满二叉树属于完全二叉树的一种)更适合使用顺序结构存储。现实中我们通常把堆(一种二叉树)使用顺序结构的数组来存储,需要注意的是这里的堆和操作系统虚拟进程地址空间中的堆是两回事,一个是数据结构,一个是操作系统中管理内存的一块区域分段。

 堆的概念及结构:

大堆(大根堆):1、完全二叉树  2、每个父亲>=孩子

小堆(小根堆):1、完全二叉树  2、每个父亲<=孩子

将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。

堆就像一个完全二叉树+数组来存储,只是在这个基础上分大根堆和小根堆(简称大堆和小堆)

而关于左右孩子谁大谁小完全无关


堆的意义:

用来选数,因为比如大堆,父亲就是最大的,以后讲的堆排序就是用的这个特征,大堆特点:根(堆顶)就是最大值,小堆特点:根(堆顶)就是最小值。实际应用比如选出哪个地方好评最好的食品,就用到了堆。

堆的性质:

  • 堆中某个节点的值总是不大于或不小于其父节点的值;
  • 堆总是一棵完全二叉树。

例题:

 下列关键字序列为堆的是(A)

A、100,60,70,50,32,65

B、60,70,65,50,32,100

C、65,100,70,32,50,60

D、70,65,100,32,50,60

思路:因为堆的完全二叉树按照数组来存储,则从第一个往后每一层的节点数为1、2、4、6......

比如A:

二、小堆的实现

本质就是一个完全二叉树用数组来存,我们用一个动态数组就好

分为三个文件:Heap.h    Heap.c    test.c

关键:

逻辑结构是完全二叉树,物理结构是数组,本质上逻辑结构只是想象出来的,物理结构才是我们真实操作的,所以针对数组,我们真实的是操作它的下标。

如果想构建小堆:

首先,我们会跟线性表一样建立一个动态数组来存堆的数据

typedef int HPDataType;
typedef struct Heap
{
	HPDataType* _a;
	int _size;
	int _capacity;
}Heap;

①、堆的初始化--HeapInit

①、数组应该存堆的数据,而数据是源于你传入的数据,用动态数组拷贝数据,才方便后续操作

②、数组建堆要用向下调整法,满足树中所有父亲节点均小于孩子,向下调整法在后面有讲

void HeapInit(Heap* php, HPDataType* a, int n)
{
	//php: hp代表heap,前面多个p表示指针
	php->_a = (HPDataType*)malloc(sizeof(HPDataType) * n);
	if (php->_a == NULL)
	{//一般malloc很少会失败,为了严谨最好检查一下
		printf("malloc fail!\n");
		exit(-1);
	}
	memcpy(php->_a, a, sizeof(HPDataType) * n);
	//把需要的数据拷贝到堆中,拷贝后才方便动态进行
	//因为传给我们的数组a,它是静态的,不便于后续操作
	php->_size = n;//堆的特点就是本来堆中就有n个数据
	php->_capacity = n;

	//构建堆
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)
	{//从最后的叶子结点的父节点开始向下调整
		AdjustDown(php->_a, php->_size, i);
	}

}

②、小堆的向下调整法的实现

向下调整法:

  • 前提:如果一棵树中左右子树都是小堆,只有根节点不满足,那么就可使用向下调整算法。(这个方法很重要,以后讲的堆排序都要用到这个算法)数组建堆主要依赖的就是向下调整法
  • 基础知识:对于完全二叉树而言,已知父亲节点的下标为i,则他的左孩子下标为2*i+1,右孩子下标为2*i+2
  • 思路:找出左右孩子中小的那一个,然后与父亲节点交换,然后再找下一个父亲和孩子,再次找出左右孩子中小的那一个,不断比较并交换,直到最后的下标超出了数组的范围。

下面是只有一个左子树的情况元素个数n=10,此时数值为37的下标为9,9+1会造成越界

 因为向下调整法是构建在左右子树都是小堆的前提下,那怎么使左右子树是小堆

只有一个节点时既可看作小堆也可看作大堆,那对于一个完全二叉树,只看叶子结点肯定保证是小堆了(可看做是小堆),那只需从叶子结点的父亲开始调整为小堆,其下标为(n-1-1)/2(因为向下调整法只要在左右子树是小堆,根节点不保证是小堆的下用,那么叶子结点可以看做是左右子树),然后在判断它的前一个元素(只需要下标-1就找到上一个元素了),不断往上调整,直到调完最上面的根节点就结束了,最上面的根节点的下标为0

综上,调整终止条件有两个:

  • 当二叉树是满二叉树:child < n循环(调整)才会继续
  • 当二叉树的最后某一节点只有左子树(不可能只有右子树,因为是完全二叉树),child+1<n循环(调整)才会继续,否则这种情况会越界
  • 交换过程中满足孩子大于父亲了,说明此次无需交换了
//向下调整算法。前提:左右子树都是小堆
void AdjustDown(HPDataType* a, int n, int root)
{
	//找出左右孩子中小的那一个,默认认为左孩子是小的那一个,否则就加以调整即可
	int parent = root;
	int child = parent * 2 + 1;//先默认child是左孩子,我们的目的是让child成为小的那一个
	while (child < n)
	{//当孩子的下标<n的时候才会一直比较交换,越界就说明堆构建完了
		if (child + 1 < n && a[child + 1] < a[child])//判断还要有一个只有左子树的情况
		{//如果右孩子比左孩子还小,就让child变成右孩子,即小标+1即可
			child++;
		}
		//如果孩子小于父亲就交换
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;//进行下一次的比较判断
			child = parent * 2 + 1;
		}
		else
		{
			break;//因为孩子已经>=父亲了,满足小堆的条件了,就无须继续往下判断,
			//因为在调整的过程中可能就存在在越界之前,孩子>=父亲的情况
            //谨记向下调整法用于只有堆顶不满足,而左右子树满足堆的性质的时候使用
		}
		//仅交换一次还不能够满足小堆,应该持续比较并交换,所以应该是个循环
	}

}

当然也可以用递归来写,但是一般除了练习,最好不要用递归,最好用迭代

向下调整法的时间复杂度:

因为对于堆来说,按最糟糕的情况来算,那就是每一层就要交换一次节点,那么整个堆就要交换高度次,即log(N+1) (以2为底N+1的对数),故时间复杂度:O(logN)

那分析一下向下调整法建堆的时间复杂度:

③、堆排序的实现

利用向下调整法建小堆可以找出最小的一个,但为了排序,如何找到次小的?正常逻辑是除了这个最大的其他节点再次建小堆,因为再次建小堆就可以再次找到最小的,但是这个方法时间复杂度比较大,为O(N*N)

排降序:建小堆

排升序:建大堆

那么如何减少时间复杂度?

思路:

 已知建堆的时间复杂度为O(N),而在排序过程中,由于要每次选出剩余数中最大的数,并保存到每次最后的节点,并要再执行一次向下调整算法,总共需要进行N次,而向下调整算法的时间复杂度为O(log2N),进行N次就是O(N*log2N),即堆排序的时间复杂度

void HeapSort(int* a, int n)
{
	//1、数组建堆
	for (int i = (n - 1 - 1) / 2; i >= 0; --i)
	{
		AdjustDown(a, n, i);
	//当然i也可初始化为n-1,即从叶子结点开始调,但是这么做肯定没有从叶子结点
	//的父节点开始调高效
	}
	//2、找次小,排序
	int end = n - 1;
	while (end > 0)
	{
		Swap(&a[0], &a[end]);
		
		//再继续选次小的
		AdjustDown(a, end, 0);
		--end;
//没有真的删除最后一个数据,只是说我下次再找小交换,最后一个数据
//不被看作堆里面的,不造成影响
	}
}

 ④、堆的插入和向上调整法

 插入数据,为了保持堆(小堆或大堆)的性质,它与普通线性表的插入还不完全相同,因为它插入的数据可能会使原来是小堆变成不是小堆,即它比他的父亲还小,就需要重新调整。

头插可以吗?头插会导致关系变乱,原来是父子关系的两节点,会出现父子变兄弟,第二,头插需要挪动数据(因为用的是数组),会导致效率低下,所以用尾插。尾插需要用到向上调整法

向上调整法思路如下: 

 也就是从最后插入的数据跟它的父亲比大小,比父亲小就交换,比父亲大就说明不用交换了,满足小堆

void AdjustUp(HPDataType* a, int n, int child)//child表示从最后底开始的下标,因为是从下往上调
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{//这里的循环判断条件不应该看父节点,父节点不管怎么都可以>=0,比如child=0,(0-1)/2=0
	//如果以父亲<0作为循环终止条件是判断不出来的
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;//孩子比父亲大,就无须调整了
		}
	}
}
void HeapPush(Heap* php, HPDataType x)
{
	assert(php);
	if (php->_capacity == php->_size)
	{
		php->_capacity *= 2;
		HPDataType* tmp = (HPDataType*)realloc(php->_a, sizeof(HPDataType) * php->_capacity);
		if (tmp != NULL)
		{
			php->_a = tmp;
		}
	}
	php->_a[php->_size++] = x;//先插入x
	//然后利用向上调整法再调节为小堆
	AdjustUp(php->_a, php->_size, php->_size - 1);
}

 ⑤、删除堆顶数据

直接删堆顶不行,因为关系会变乱,比如原来的父子关系会变成兄弟,那这里和堆排序的思路差不多,第一个数据与最后一个交换,但是这里最后一个数据是真删,然后再向下调整法,就可以把堆顶删掉了。这里不需要尾删,因为简单且没意义,我们一般都会删除堆顶,不断找次小的数。

void HeapPop(Heap* php)
{
	assert(php);
	assert(php->_size > 0);

	Swap(&php->_a[0], &php->_a[php->_size - 1]);//堆顶与最后一个元素交换
	php->_size--;//删除堆顶

	AdjustDown(php->_a, php->_size, 0);//再次向下调整法,使其为小堆
}

⑥、获取堆顶

HPDataType HeapTop(Heap* php)
{
	assert(php);
	assert(php->_size > 0);

	return php->_a[0];
}

Heap.h:

#pragma once

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>

typedef int HPDataType;
typedef struct Heap
{
	HPDataType* _a;
	int _size;
	int _capacity;
}Heap;

//堆的初始化
void HeapInit(Heap* php, HPDataType* a, int n);
//堆的销毁
void HeapDestroy(Heap* php);
//数据插入
void HeapPush(Heap* php,HPDataType x);//与线性表不同的是插入数据后,要保持堆的特性
//删除堆顶的数据
void HeadPop(Heap* php);//并不是删除那么简单,删除完数据还是要保持堆的特性
//获得堆顶的数据
HPDataType HeapTop(Heap* php);

Heap.c:

#define _CRT_SECURE_NO_WARNINGS 1
#include"Heap.h"

void Swap(HPDataType* p1, HPDataType* p2)
{
	HPDataType tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

//向下调整算法。前提:左右子树都是小堆
void AdjustDown(HPDataType* a, int n, int root)
{
	//找出左右孩子中小的那一个,默认认为左孩子是小的那一个,否则加以调整即可
	int parent = root;
	int child = parent * 2 + 1;//先默认child是左孩子的下标,我们的目的是让child成为小的那一个
	while (child < n)
	{//当孩子的下标(每一轮循环child下标都会被更新为左孩子的下标)<n的时候才会一直比较交换,越界就说明堆构建完了
		if (child + 1 < n && a[child + 1] < a[child])//判断还要有一个只有左子树的情况
		{//如果右孩子比左孩子还小,就让child变成右孩子,即小标+1即可
			child++;
		}
		//如果孩子小于父亲就交换
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;//进行下一次的比较判断
			child = parent * 2 + 1;//再次假设小的孩子是左孩子,进行下一次循环
		}
		else
		{
			break;//满足小堆的条件了,无须继续往下判断,
			//因为在调整的过程中,可能出现孩子>=父亲的情况
		}
		//仅交换一次还不能够满足小堆,应该持续比较并交换,所以应该是个循环
	}

}

//向上调整法
void AdjustUp(HPDataType* a, int n, int child)//child表示从最后底开始的下标,因为是从下往上调
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{//这里的循环判断条件不应该看父节点,父节点不管怎么都可以>=0,比如child=0,(0-1)/2=0
	//如果以父亲<0作为循环终止条件是判断不出来的
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;//孩子比父亲大,就无须调整了
		}
	}
}
void HeapInit(Heap* php, HPDataType* a, int n)
{
	//php: hp代表heap,前面多个p表示指针
	php->_a = (HPDataType*)malloc(sizeof(HPDataType) * n);
	if (php->_a == NULL)
	{//一般malloc很少会失败,为了严谨最好检查一下
		printf("malloc fail!\n");
		exit(-1);
	}
	memcpy(php->_a, a, sizeof(HPDataType) * n);
	//把需要的数据拷贝到堆中,拷贝后才方便动态进行
	//因为传给我们的数组a,它是静态的,不便于后续操作
	php->_size = n;//堆的特点就是本来堆中就有n个数据
	php->_capacity = n;

	//构建堆
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)
	{//从最后的叶子结点的父节点开始向下调整
		AdjustDown(php->_a, php->_size, i);
	}

}

//堆的销毁
void HeapDestroy(Heap* php)
{
	assert(php);
	free(php->_a);
	php->_a = NULL;
	php->_capacity = php->_size = 0;
}

//堆排序的实现
void HeapSort(int* a, int n)
{
	//1、数组建堆
	for (int i = (n - 1 - 1) / 2; i >= 0; --i)
	{
		AdjustDown(a, n, i);
	//当然i也可初始化为n-1,即从叶子结点开始调,但是这么做肯定没有从叶子结点
	//的父节点开始调高效
	}
	//2、找次小,排序
	int end = n - 1;
	while (end > 0)
	{//最后临界条件是end=0,即只剩下一个元素,就无须再排了
		Swap(&a[0], &a[end]);//把建好的堆的最小元素换到和最后的一个元素换
		
		//再继续选次小的
		AdjustDown(a, end, 0);//传入了n-1个元素,相当于把最后的一个元素除去了
		--end;
	}
}

//从堆尾部插入数据
void HeapPush(Heap* php, HPDataType x)
{
	assert(php);
	if (php->_capacity == php->_size)
	{
		php->_capacity *= 2;
		HPDataType* tmp = (HPDataType*)realloc(php->_a, sizeof(HPDataType) * php->_capacity);
		if (tmp != NULL)
		{
			php->_a = tmp;
		}
	}
	php->_a[php->_size++] = x;//先插入x
	//然后利用向上调整法再调节为小堆
	AdjustUp(php->_a, php->_size, php->_size - 1);
}

//从删除堆顶数据
void HeapPop(Heap* php)
{
	assert(php);
	assert(php->_size > 0);

	Swap(&php->_a[0], &php->_a[php->_size - 1]);//堆顶与最后一个元素交换
	php->_size--;//删除堆顶

	AdjustDown(php->_a, php->_size, 0);//再次向下调整法,使其为小堆
}

//获取堆顶
HPDataType HeapTop(Heap* php)
{
	assert(php);
	assert(php->_size > 0);

	return php->_a[0];
}

test.c:

#define _CRT_SECURE_NO_WARNINGS 1
#include"Heap.h"

int main()
{
	int a[] = { 27,15,19,18,28,34,65,49,25,37 };
	Heap hp;
	HeapInit(&hp, a, sizeof(a) / sizeof(a[0]));
	HeapPush(&hp, 19);
	printf("堆顶为%d\n", HeapTop(&hp));
	HeapDestroy(&hp);

	return 0;
}

三、时间复杂度总结:

向上调整法复杂度=向下调整法时间复杂度=O(logN)

向下建堆的时间复杂度:O(N)

堆排序的时间复杂度:O(N*logN)

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

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

相关文章

网络安全进阶学习第六课——服务器解析漏洞

文章目录 1、概念2、Apache解析漏洞 CVE-2017-157153、Apache AddHandler解析漏洞4、IIS6 解析漏洞&#xff08;;&#xff09;5、IIS6 解析漏洞&#xff08;*.asp/目录&#xff09;6、IIS7 解析漏洞&#xff08;ISAP或CGI的模式下&#xff09;7、nginx解析漏洞&#xff08;cgi.…

2023年6月第4周大模型荟萃

2023年6月第4周大模型荟萃 2023.6.30版权声明&#xff1a;本文为博主chszs的原创文章&#xff0c;未经博主允许不得转载。 1、腾讯云首次公布大模型进展 6月19日&#xff0c;腾讯云召开行业大模型及智能应用技术峰会&#xff0c;首次公布腾讯云行业大模型研发进展&#xff0…

QT下载太慢,在线安装太慢的解决方案

实现效果 步骤1 下载在线安装的客户端&#xff0c;可以从qt.io&#xff08;qt-unified-windows-x64-4.6.0-online.exe&#xff09;下载&#xff0c;速度稍慢&#xff0c;但是大小也才38MB左右。 觉得下载太慢的小伙伴可以使用我提供的代下载版本&#xff0c;你们可以校验文件…

峰会来袭 | CAD模型转换工具选择的难点和关键点解答

作为世界顶尖的3D软件开发SDK和CAD模型转换工具——HOOPS Exchange已问世十多年&#xff0c;深受开发者好评&#xff0c;并在工业测量、机械加工、造船设计等领域都有广泛的应用。 本次峰会将围绕CAD软件造型技术的多样性、CAD模型数据解析的难点、3D模型转换的经典问题等&…

IDEA+springboot+jpa+Layui+Mysql销售考评系统源码

IDEAspringbootjpaLayuiMysql销售考评系统源码 一、系统介绍1.环境配置 二、系统展示1. 管理员登录2.评分结果3.评分管理4.添加评分5.用户管理6.添加用户7.角色管理8.添加角色8.销售管理9.添加销售 三、部分代码UserDao.javaUserController.javaUser.java 四、其他获取源码 一、…

黑芝麻智能科技、上海紫先面试(部分)(未完全解析)

黑芝麻智能科技 Hystrix可以限流吗&#xff1f;客户端限流&#xff0c;是限制对下游&#xff08;被调用方&#xff09;的访问&#xff0c;不是对本服务限流。从HystrixCommand的.withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)也可以看出来&#xff0c…

STM32外设系列—ESP8266(WIFI)

文章目录 一、ESP8266简介二、固件库烧录三、常用AT指令四、访问API4.1 获取IP地址4.2 GET天气信息4.3 访问结果展示 五、实战项目5.1 串口配置5.2 检测WIFI模块连接状态5.3 发送配置指令5.4 解析天气信息 六、成果展示 一、ESP8266简介 ESP8266是嵌入式和物联网开发中常用的模…

MySQL子查询

&#x1f607;作者介绍&#xff1a;一个有梦想、有理想、有目标的&#xff0c;且渴望能够学有所成的追梦人。 &#x1f386;学习格言&#xff1a;不读书的人,思想就会停止。——狄德罗 ⛪️个人主页&#xff1a;进入博主主页 &#x1f5fc;专栏系列&#xff1a;进入MySQL专栏知…

Jenkins邮件配置报错com.sun.mail.smtp.SMTPSenderFailedException: 501

Jenkins邮件配置&#xff0c;配置完成各种信息之后&#xff0c;“通过发送测试邮件测试配置”点击Test configuration&#xff0c;报错 1、报错信息 com.sun.mail.smtp.SMTPSenderFailedException: 501 mail from address must be same as authorization userat com.sun.mail…

Xcode 15 beta 3 (15A5195k) 发布下载 - Apple 平台 IDE

Xcode 15 beta 3 (15A5195k) 发布下载 - Apple 平台 IDE (visonOS 1 beta 已发布) 7 月 5 日&#xff08;北京时间今日凌晨&#xff09;已发布。 IDE for iOS/iPadOS/macOS/watchOS/tvOS/visonOS 请访问原文链接&#xff1a;https://sysin.org/blog/apple-xcode-15/&#xf…

Flutter生命周期小结

Flutter 中的生命周期&#xff0c;包含以下几个阶段&#xff1a; createState &#xff0c;在 StatefulWidget 中创建 State 的方法&#xff0c;当 StatefulWidget 调用时会触发 createState 。initState &#xff0c;在 State 初始化时调用&#xff0c;因此可以在此期间执行 …

Python 基于招聘数据可视化系统

1 简介 Python 基于招聘数据可视化系统&#xff0c;视频效果如下&#xff1a; 基于Python的招聘信息可视化系统&#xff0c;附源码 随着国内的经济不断的快速发展&#xff0c;现在学生的就业压力也在逐年增加&#xff0c;网络上的招聘信息非常的丰富&#xff0c;但是对于学生而…

Flutter基础控件

Text:文字 Text("Flutter") Text是最常用也是最基础的&#xff0c;目前学习阶段只用来加载文字数据&#xff0c;更多属性和样式设置请查看源码自己探索。 Button:按钮 ElevatedButton:普通按钮 ElevatedButton(onPressed: () {if (kDebugMode) {print("Elevat…

安装和配置nginx(含https)

文章目录 安装Nginx配置单独的配置&#xff1a;https配置 nginx为什么可以处理高并发 安装Nginx sudo yum update sudo yum install epel-release sudo yum install nginx sudo systemctl start nginx安装好后可以打开自己的域名 看一下默认的页面 配置 具体参考Link 位置 …

软件工程——第7章实现知识点整理

本专栏是博主个人笔记&#xff0c;主要目的是利用碎片化的时间来记忆软工知识点&#xff0c;特此声明&#xff01; 文章目录 1.实现由哪两个部分组成&#xff1f; 2.编码是什么&#xff1f;所选用的程序设计语言对程序的哪些特性有着深远影响&#xff1f; 3.软件测试在软件生…

Python编程实现针对回撤的交易策略

在金融交易市场上&#xff0c;回撤是一个常见的现象。因此&#xff0c;对于投资者来说&#xff0c;研究和设计针对回撤的交易策略是非常必要的。本文将介绍如何使用Python编程实现针对回撤的交易策略&#xff0c;以帮助投资者更好地进行交易。 一、回撤分析 在设计针对回撤的…

Cisco Catalyst 9000 Series Switches, IOS-XE Release Dublin-17.11.1 ED

Cisco Catalyst 9000 Series Switches, IOS-XE Release Dublin-17.11.1 ED Cisco Catalyst 9000 交换产品系列 请访问原文链接&#xff1a;https://sysin.org/blog/cisco-catalyst-9000/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;…

Basler相机一丢包就断开问题解决

问题描述&#xff1a; 两个相机&#xff0c; 一个相机aca2500-14gm连接电脑主板100M网卡没问题&#xff0c;帧率3帧&#xff0c;但是不会断。 一个相机aca2500-14gm连接USB转网口&#xff08;千兆&#xff09;&#xff0c;pylon Viewer采图丢包严重并且几秒后相机断开。 解决…

Centos 7 下安装Redis

官网地址&#xff08;英文&#xff09;&#xff1a;Redis 官网地址&#xff08;中文&#xff09;&#xff1a;CRUG网站 or redis中文文档 Redis源码地址&#xff1a;GitHub - redis/redis: Redis is an in-memory database that persists on disk. The data model is key-v…

数据结构-排序

数据结构排序 1 知识框架2 插入排序2.1 直接插入排序2.2 折半插入排序2.3 希尔排序 3 交换排序3.1 冒泡排序3.2 快排 4 选择排序4.1 简单选择排序4.2 堆排序 5 归并和基数排序5.1 归并排序5.2 基数排序 1 知识框架 算法的稳定性&#xff1a;&#xff1b;两个相同的元素在排序算…