排序算法(基础)大全

一、排序算法的作用:

排序算法的主要作用是将一组数据按照特定的顺序进行排列,使得数据更加有序和有组织。

1. 查找效率通过将数据进行排序,可以提高查找算法的效率。在有序的数据中,可以使用更加高效的查找算法,如二分查找、插值查找等,减少了查找的时间复杂度。

2. 统计分析:在排序过程中,可以对数据进行各种统计分析,如计算各种统计量、查找中位数、众数等。有序的数据更加便于进行统计分析和数据挖掘。

3. 数据压缩和编码:排序算法可以将数据重新排列,进而提供更好的数据压缩和编码方式,减少存储空间和传输带宽。

4. 数据归并和合并:在某些应用中,需要将多个有序的数据集合进行归并或合并,排序算法提供了这样的功能。例如,在合并两个有序的数组时,可以使用归并排序算法。

5. 数据的可视化和展示:有序的数据更容易进行可视化展示,可以更加直观地表达数据的分布和关系。

6. 数据库和文件系统中的索引:数据库和文件系统中的索引结构通常需要对数据进行排序,以提高查询和检索的效率。

总之,排序算法能够对数据进行有序排列,提高数据的组织性和可读性,提高查找和统计等操作的效率,是计算机科学和实际应用中的基础算法之一。

二、基础排序算法: 

(1)选择排序:

故名思义,选择排序算法就是有选择地进行排序。其算法思想是:
1、将数组分成【已排序区】【待排序区】
2、每一轮从【待排序区】中选择一个最小的元素放到【已排序区】
3、直到【待排序区】没有元素为止

其算法的时间复杂度无论好坏都为O(n^2)

稳定性:不稳定

其过程如图:

关键代码实现: 
#define swap(a,b){\ //交换a,b
	__typeof(a) __c=(a);\  //将a赋值给__c,同时,__c的类型与a的类型一样
	(a)=(b);\ //将b赋值给a
	(b)=__c;\ //将__c赋值给b
}
void selection_sort(int *arr,int l,int n){ //选择排序
	for(int i=l;i<n-1;i++){ //从下标0开始
		int ind=i; //假设下标为ind的数组元素最小
		for(int j=i+1;j<n;j++){
			if(arr[ind]>arr[j])ind=j; //如果有比下标ind更小的,则更新下标ind
		}
		swap(arr[i],arr[ind]); //将两个元素交换
	}
	return;
}
(2)插入排序:

故名思义,插入排序就是不断进行插入调整的排序。其算法思想是:
1、将数组分成【已排序区】和【待排序区】
2、将【待排序区】后面第一个元素,向前插入到【已排序区】并进行调整
3、直到【待排序区】没有元素为止
其算法的时间复杂度最好的情况下为O(n),最坏的情况下或平均情况下为O(n^2)

稳定性:稳定

其过程如图:

关键代码实现:
#define swap(a,b){\ //交换a,b
	__typeof(a) __c=(a);\
	(a)=(b);\
	(b)=__c;\
}
void insert_sort(int *arr,int b,int n){ //插入排序,b=0
	for(int i=b+1;i<n;i++){ //待排序区从1开始
		int j=i; //记录已排序区的最大下标
		while(j>b&&arr[j]<arr[j-1]){ //对新插入到已排序区的元素进行排序
			swap(arr[j],arr[j-1]);
			j-=1;
		}
	}
	return;
}
(3)希尔排序:

希尔排序(Shell Sort)是插入排序的一种改进版本,也称为递减增量排序。它通过将原始数组分割成多个子序列,对每个子序列进行插入排序,然后逐步缩小子序列的范围,最终完成排序。

希尔排序的基本算法思想:

  1. 选择一个增量序列,通常选择n/2、n/4、n/8...,直到增量为1。

  2. 对每个增量进行插入排序,将间隔为增量的元素分为一组,对每组进行插入排序

  3. 缩小增量,重复第2步的操作,直到增量为1,即进行最后一次插入排序。

其算法的时间复杂度最好的情况下是O(nlogn),最坏的情况下是O(n^2)

稳定性:不稳定

其过程如图:

 关键代码实现:
#define swap(a,b){\ //交换a,b
	__typeof(a) __c=(a);\ //将__c的类型在编译时,转换为与a相同的类型并赋值
	(a)=(b);\ //赋值交换
	(b)=__c;\ //赋值交换
}
void insert_sort(int *arr,int b,int n,int step){ //插入排序,b为起始下标,n为最大下标
	int ind=b; //记录要开始进行插入排序的点
	for(int i=b+step;i<n;i+=step){ //每次对间隔为step的元素排序
		if(arr[i]<arr[ind])ind=i;    //记录数组下标大而数据小的元素
	}
	while(ind>b){ 
		swap(arr[ind],arr[ind-step]); //交换元素
		ind-=step; //每次对间隔为step的元素进行排序
	}
	for(int i=b+2*step;i<n;i+=step){
		int j=i;
		while(arr[j]<arr[j-step]){
			swap(arr[j],arr[j-step]);
			j-=step;
		}
	}
	return;
}
void shell_sort(int *arr,int b,int n){
	int k=2,bc=(n-b),step;
	do{
		step=bc/k==0?1:(bc/k);
		for(int i=b,I=b+step;i<I;i++){
			insert_sort(arr,i,n,step);
		}
		k*=2;
	}while(step!=1);
	return;
}
(4)快速排序: 

快速排序是通过选择一个基准元素,将数组分成两个子数组,一组小于基准元素,另一组大于基准元素。然后对两个子数组分别递归地进行快速排序,最终将整个数组排序。

快速排序的基本算法思想:
1. 选择一个基准元素,通常选择数组的第一个最后一个元素。
2. 定义两个指针,一个指向数组的第一个元素,一个指向数组的最后一个元素。
3. 移动左指针,直到找到一个大于等于基准元素的元素。
4. 移动右指针,直到找到一个小于等于基准元素的元素。
5. 交换左指针和右指针所指向的元素。
6. 重复步骤3-5,直到左指针和右指针相遇
7. 将基准元素与左指针所指向的元素互换位置。
8. 进行递归,对基准元素左边的子数组和右边的子数组进行快速排序。

其算法的时间复杂度最好的情况为O(nlogn),最坏的情况为O(n^2)。

其稳定性:不稳定

其过程如图:

关键代码实现: 
#define swap(a,b){\
	__typeof(a) __c=(a);\
	(a)=(b);\
	(b)=__c;\
}
void quick_sort(int *arr,int l,int r){
	if(r-l<=2){
		if(r-l<=1)return;
		if(arr[l]>arr[l+1])swap(arr[l],arr[l+1]);
		return;
	}
	int x=l,y=r-1,z=arr[l];
	while(x<y){
		while(x<y&&z<=arr[y])--y;
		if(x<y)arr[x++]=arr[y];
		while(x<y&&arr[x]<=z)++x;
		if(x<y)arr[y]=arr[x];
	}
	arr[x]=z;
	quick_sort(arr,l,x);
	quick_sort(arr,x+1,r);
	return;
}
int main(){
(5)归并排序:

归并排序(Merge sort)是一种经典的排序算法,它采用分治法的思想将问题分解为更小的子问题,并且通过递归的方式解决这些子问题。然后将子问题的解合并起来,最终得到原问题的解。

归并排序的基本算法思想:

1. 每次将数组不断地二分为两个子数组,直到每个子数组只剩下一个元素。
2. 然后将两个子数组逐个合并起来,形成一个有序的新数组。

3.合并的方式是比较两个子数组的第一个元素,将较小的元素放入新数组中,并移动指针,继续比较下一个元素。
4. 重复上述步骤,直到将所有的子数组都合并起来,得到最终的有序数组。

归并排序的时间复杂度:最好的情况下:O(nlogn);最坏的情况下:O(nlogn)。

这是一种稳定的排序算法,适用于各种数据类型。但是归并排序需要额外的存储空间来存储临时数组,空间复杂度为O(n)。

其过程如图:

原数组:[5,4,2,7,1,6,8,3]

关键代码实现:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<string.h>
#define SMALL 1000000
__attribute__((constructor))
void __init_Rand__(){
	srand(time(0));
}
bool check(int *arr,int l,int r){
	for(int i=l+1;i<r;i++){
		if(arr[i]<arr[i-1])return false;
	}
	return true;
}
#define swap(a,b){\
	__typeof(a) __c=(a);\
	(a)=(b);\
	(b)=__c;\
}
#define TEST(func,arr,n){\
	printf("TEST:%s",#func);\
	int *temp=(int *)malloc(sizeof(int)*n);\
	memcpy(temp,arr,sizeof(int)*n);\
	long long b=clock();\
	func(temp,0,n);\
	long long e=clock();\
	if(check(temp,0,n)){\
		printf("\tOK");\
	}else{\
		printf("\tNO");\
	}\
	printf("\t%lldms\n",(e-b)*1000/CLOCKS_PER_SEC);\
	free(temp);\
}
int *getRandData(int n){
	int *arr=(int *)malloc(sizeof(int)*n);
	for(int i=0;i<n;i++){
		arr[i]=rand()%100+1;
	}
	return arr;
}
int *buff; //额外存储空间
void merge_sort(int *arr,int l,int r){ r为数组长度,l为开始位置,初始为0
	if(r-l<=1)return; //如果只有一个元素,返回结果
	int mid=(l+r)/2; //每次都将数组二分
	merge_sort(arr,l,mid); //递归二分前半段的数组
	merge_sort(arr,mid,r); //递归二分后半段的数组
	int p1=l,p2=mid,k=0;//p1记录第一个数组元素下标,p2记录中间元素下标,k记录当前位置,便于排序
	while(p1<mid||p2<r){ //前半段数组范围、后半段数组范围
		if(p2==r||(p1<mid&&arr[p1]<=arr[p2])){ 
			buff[k++]=arr[p1++];
		}else{
			buff[k++]=arr[p2++];
		}
	}
	for(int i=l;i<r;i++)arr[i]=buff[i-l];
	return;
}
int main(){
	int *arr=getRandData(SMALL);
	buff=(int *)malloc(sizeof(int)*SMALL);
	TEST(merge_sort,arr,SMALL);
	free(buff);
	return 0;
}
(6)基数排序:

基数排序是一种非比较型的排序算法,它将数据按照位数进行分组,分别对每个位数进行排序,直到最高位数排序完毕。基数排序可以用于对非负整数进行排序。

基数排序的基本算法思想如下:

1. 将待排序的数据从最低位开始,按照个位数进行分组。
2. 对每个分组进行计数排序,将数据按照个位数的大小进行排序。
3. 将所有分组的数据按照排序结果进行合并
4. 重复步骤1-3,按照位数、位数等依次进行排序,直到最高位数排序完毕。

基数排序的时间复杂度:最好的情况下:O(k*n);最坏的情况下:O(k*n)。其中k是最大数的位数,n是待排序数据的个数。

基数排序的空间复杂度是O(n+k)。

基数排序的优点是稳定性好,适用于数据量较大且每个数位数较小的情况。然而,基数排序的缺点是需要占用大量的额外空间,且对于负数无法直接排序。

基数排序过程如图:

关键代码实现:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<string.h>
#define K 65536
#define SMALL 1000000
__attribute__((constructor))
void __init_Rand__(){
	srand(time(0));
}
#define swap(a,b){\
	__typeof(a) __c=(a);\
	(a)=(b);\
	(b)=__c;\
}
bool check(int *arr,int l,int r){
	for(int i=l+1;i<r;i++){
		if(arr[i]<arr[i-1])return false;
	}
	return true;
}
#define TEST(func,arr,n){\
	printf("TEST:%s",#func);\
	int *temp=(int *)malloc(sizeof(int)*n);\
	memcpy(temp,arr,sizeof(int)*n);\
	long long b=clock();\
	func(temp,0,n);\
	long long e=clock();\
	if(check(temp,0,n)){\
		printf("\tOK");\
	}else{\
		printf("\tNO");\
	}\
	printf("\t%lldms\n",(e-b)*1000/CLOCKS_PER_SEC);\
	free(temp);\
}
int *getRandData(int n){
	int *arr=(int *)malloc(sizeof(int)*n);
	for(int i=0;i<n;i++){
		arr[i]=rand()%100+1;
	}
	return arr;
}
void radix_sort(int *arr,int l,int r){
	int *cnt=(int *)malloc(sizeof(int)*K);
	int *temp=(int *)malloc(sizeof(int)*r);
	memset(cnt,0,sizeof(int)*K);
	for(int i=0;i<r;i++)cnt[arr[i]%K]+=1;
	for(int i=1;i<K;i++)cnt[i]+=cnt[i-1];
	for(int i=r-1;i>=l;i--)temp[--cnt[arr[i]%K]]=arr[i];
	memcpy(arr,temp,sizeof(int)*r);
	memset(cnt,0,sizeof(int)*K);
	for(int i=0;i<r;i++)cnt[arr[i]/K]+=1;
	for(int i=1;i<K;i++)cnt[i]+=cnt[i-1];
	for(int i=r-1;i>=l;i--)temp[--cnt[arr[i]/K]]=arr[i];
	memcpy(arr,temp,sizeof(int)*r);
	free(temp);
	free(cnt);
	return;
}
int main(){
	int *arr=getRandData(SMALL);
	TEST(radix_sort,arr,SMALL);
	free(arr);
	return 0;
}

文章到此结束!

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

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

相关文章

《Java核心技术 卷I》用户界面AWT事件继承层次

AWT事件继承层次 EventObject类有一个子类AWTEvent&#xff0c;它是所有AWT事件类的父类。 Swing组件会生成更多其他事件对象&#xff0c;都直接拓展自EventObject而不是AWTEvent。 AWT将事件分为底层(low-level)事件和语义事件。 语义事件&#xff1a;表示用户的动作事件&…

24-Ingest Pipeline Painless Script

将文档中的tags字段按照逗号&#xff08;,&#xff09;分隔符进行分割。 同时为文档&#xff0c;增加一个字段。blog查看量 DELETE tech_blogs#Blog数据&#xff0c;包含3个字段&#xff0c;tags用逗号间隔 PUT tech_blogs/_doc/1 {"title":"Introducing big …

node.js下载安装步骤整理

>> 进入node.js下载页面下载 | Node.js 中文网 >>点击 全部安装包 >>删除网址node后面部分&#xff0c;只保留如图所示部分&#xff0c;回车 >>点击进入v11.0.0/版本 >>点击下载node-v11.0.0-win-x64.zip(电脑是windows 64位操作系统适用) >…

【HAProxy09】企业级反向代理HAProxy高级功能之压缩功能与后端服务器健康性监测

HAProxy 高级功能 介绍 HAProxy 高级配置及实用案例 压缩功能 对响应给客户端的报文进行压缩&#xff0c;以节省网络带宽&#xff0c;但是会占用部分CPU性能 建议在后端服务器开启压缩功能&#xff0c;而非在HAProxy上开启压缩 注意&#xff1a;默认Ubuntu的包安装nginx开…

右键添加获取可供WSL使用的路径,对windows文件夹也适用,即获取符合Linux规范的路径内容给WSL

文章目录 1. 功能展示1.1. 对 WSL 文件/文件夹/目录空白位置 使用1.2. 对 Windows 文件/文件夹/目录空白位置 使用1.3. Fin 2. 方法3. 文件内容3.1. AddWSLPath.reg3.2. CopyPath.vbs 4. 念念碎 1. 功能展示 1.1. 对 WSL 文件/文件夹/目录空白位置 使用 输出 /etc 1.2. 对 Wi…

数据分析——Python绘制实时的动态折线图

最近在做视觉应用开发&#xff0c;有个需求需要实时获取当前识别到的位姿点位是否有突变&#xff0c;从而确认是否是视觉算法的问题&#xff0c;发现Python的Matplotlib进行绘制比较方便。 目录 1.数据绘制2.绘制实时的动态折线图3.保存实时数据到CSV文件中 import matplotlib.…

Chrome 浏览器开启打印模式

打开开发者工具ctrl shift p输入print 找到 Emulate CSS print media type

小米运动健康与华为运动健康在苹手机ios系统中无法识别蓝牙状态 (如何在ios系统中开启 蓝牙 相册 定位 通知 相机等功能权限,保你有用)

小米运动健康与华为运动健康在苹手机ios系统中无法识别蓝牙状态 &#xff08;解决方案在最下面&#xff0c;参考蓝牙权限设置方式举一反三开启其它模块的权限&#xff09; 最近买了一台小米手表s4&#xff0c;但是苹手机ios系统中的 “小米运动健康” app 始终无法识别我手机…

不用来回切换,一个界面管理多个微信

你是不是也有多个微信号需要管理&#xff1f; 是不是也觉得频繁切换账号很麻烦&#xff1f; 是不是也想提升多账号管理的效率&#xff1f; 在工作中&#xff0c;好的辅助工具&#xff0c;能让我们的效率加倍增长&#xff01; 今天&#xff0c; 就给大家分享一个多微管理工具…

爬虫——数据解析与提取

第二节&#xff1a;数据解析与提取 在网络爬虫开发中&#xff0c;获取网页内容&#xff08;HTML&#xff09;是第一步&#xff0c;但从这些内容中提取有用的数据&#xff0c;才是爬虫的核心部分。HTML文档通常结构复杂且充满冗余信息&#xff0c;因此我们需要使用高效的解析工…

3D Gaussian Splatting 代码层理解之Part1

2023 年初,来自法国蔚蓝海岸大学和 德国马克斯普朗克学会的作者发表了一篇题为“用于实时现场渲染的 3D 高斯泼溅”的论文。该论文提出了实时神经渲染的重大进步,超越了NeRF等以往方法的实用性。高斯泼溅不仅减少了延迟,而且达到或超过了 NeRF 的渲染质量,在神经渲染领域掀…

数据结构《栈和队列》

文章目录 一、什么是栈&#xff1f;1.1 栈的模拟实现1.2 关于栈的例题 二、什么是队列&#xff1f;2.2 队列的模拟实现2.2 关于队列的例题 总结 提示&#xff1a;关于栈和队列的实现其实很简单&#xff0c;基本上是对之前的顺序表和链表的一种应用&#xff0c;代码部分也不难。…

ComfyUI-image2video模型部署教程

一、介绍 本项目基于ComfyUI进行部署&#xff0c;在上面可以简单实现图片到视频的效果。也就是可以通过给定一张图片&#xff0c;实现的功能是图片动起来。 二、部署 要求显存&#xff1a;VAE解码需要13G以上 1. 部署ComfyUI 本篇的模型部署是在ComfyUI的基础上进行&#x…

react中如何在一张图片上加一个灰色蒙层,并添加事件?

最终效果&#xff1a; 实现原理&#xff1a; 移动到图片上的时候&#xff0c;给img加一个伪类 &#xff01;&#xff01;此时就要地方要注意了&#xff0c;因为img标签是闭合的标签&#xff0c;无法直接添加 伪类&#xff08;::after&#xff09;&#xff0c;所以 我是在img外…

使用Axios函数库进行网络请求的使用指南

目录 前言1. 什么是Axios2. Axios的引入方式2.1 通过CDN直接引入2.2 在模块化项目中引入 3. 使用Axios发送请求3.1 GET请求3.2 POST请求 4. Axios请求方式别名5. 使用Axios创建实例5.1 创建Axios实例5.2 使用实例发送请求 6. 使用async/await简化异步请求6.1 获取所有文章数据6…

基于Java Web 的家乡特色菜推荐系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

opencv kdtree pcl kdtree 效率对比

由于项目中以一个环节需要使用kdtree ,对性能要求比较严苛&#xff0c;所以看看那个kdtree效率高一些。对比了opencv和pcl。 #include <array> #include <deque> #include <fstream> #include <opencv2/highgui.hpp> #include <opencv2/imgproc.hpp…

Flink_DataStreamAPI_输出算子Sink

Flink_DataStreamAPI_输出算子Sink 1连接到外部系统2输出到文件3输出到Kafka4输出到MySQL&#xff08;JDBC&#xff09;5自定义Sink输出 Flink作为数据处理框架&#xff0c;最终还是要把计算处理的结果写入外部存储&#xff0c;为外部应用提供支持。 1连接到外部系统 Flink的D…

RAG经验论文《FACTS About Building Retrieval Augmented Generation-based Chatbots》笔记

《FACTS About Building Retrieval Augmented Generation-based Chatbots》是2024年7月英伟达的团队发表的基于RAG的聊天机器人构建的文章。 这篇论文在待读列表很长时间了&#xff0c;一直没有读&#xff0c;看题目以为FACTS是总结的一些事实经验&#xff0c;阅读过才发现FAC…

【Android compose原创组件】在Compose里面实现内容不满一屏也可以触发边界阻尼效果的一种可用方法

创意背景 在安卓 View 传统命令式开发里面提供了非常多稳定美观体验好的组件&#xff0c;但是目前Compose还未有可用的组件&#xff0c;比如View中可以使用 coordinatorlayout 的滚动效果可以实现局部&#xff08;即使内容不满一屏也可以触发滚动边界阻尼效果&#xff09;&…