C++:十大排序

目录

时间复杂度分析

选择排序

引言

算法思想

动图展示

代码实现 (升序)

优化 

代码实现

分析 

冒泡排序

引言

算法思想

动图展示

代码实现

插入排序

引言

算法思想

动图展示

代码实现

计数排序

引言

算法思想

动图展示

代码实现

桶排序

引言

算法思想

动图展示

代码实现

基数排序

引言

算法思想

动图展示

代码实现

希尔排序

引言

算法思想

动图展示

代码实现 

快速排序

引言

算法思想

动图展示

动图分析 

代码实现

堆排序

引言

大堆和小堆

算法思想 

动图展示

代码实现

归并排序

引言

算法思想

动图展示

代码展示

 


时间复杂度分析

选择排序

引言

选择排序(Selection Sort)是一种简单直观的排序算法。他首先在未排序的序列中找到最小元素,存放到排序序列的起始位置,然后再找到剩下序列中最小的元素,放到排好序列的下一个位置。以此类推,直到所有元素排序完毕。

算法思想

第一步、在未排序的序列中找到最小(最大)的元素,存放到排序序列的起始位置。
第二步、再从剩余未排序元素中找到最小(最大)的元素,然后放到已排序的序列的末尾。
重复第二步,直到所有元素都排序完毕。

动图展示

代码实现 (升序)

void  Select(int* a, int n)
{
	for (int i = 0; i < n - 1; i++)//排前n-1的数
	{
		for (int j = i + 1; j < n; j++)
		{
			if (a[j] < a[i])
			{
				swap(a[i], a[j]);//未排序的序列中比目标小的就交换。
			}
		}
	}
}

优化 

上述代码在未排序的序列中找最小(最大)的元素,每一轮只能找到一个,还可以将其进行优化,一轮中可以同时找到最小和最大的元素,分别将其交换到未排序序列的头部和尾部.

代码实现

//选择排序
void chosesort(int* a, int n)
{
	int begin = 0; int end = n - 1;
	int mini = begin;
	int maxi = begin;
	while (begin < end)
	{
		maxi = begin; mini = begin;
		for (int i = begin + 1; i <=end; i++)
		{
			if (a[i] > a[maxi])maxi = i;
			if (a[i] < a[mini])mini = i;
		}
		if (begin ==maxi && end ==mini)swap(a[begin], a[end]);
		else
		{
			swap(a[begin], a[mini]);
			swap(a[end], a[maxi]);
		}
		begin++; end--;
	}
}

分析 

将未排序的序列的两端使用下标begin,end表示出来,注意我们找未排序序列中的最大值和最小值的时候找的是其下标并不是值,找到后将最大值(下标为maxi)和下标为end的值进行交换,将最小值(下标为mini)和下标为begin的值进行交换。

如果最大值恰好在begin位置,最小值恰好在end位置那么就只需要交换一次就可以了、

冒泡排序

引言

冒泡排序(Bubble Sort)是一种简单的排序算法,同过多次比较和交换相邻的元素,将数组中的元素按升序或降序排序。

算法思想

冒泡排序的基本思想是:每次遍历数组,比较相邻的两个元素,如果他们的顺序错误,就将他们交换,直到数组的所有元素都被遍历过。

动图展示

代码实现

//冒泡排序
void bubllesort(int* a, int n)
{
	for (int i = 0; i < n - 1; i++)
	{
		for (int j = 0; j < n - i - 1; j++)
		{
			if (a[j] > a[j + 1])
				swap(a[j], a[j + 1]);
		}
	}
}

插入排序

引言

插入排序(Insertion Sort)是一种简单直观的排序算法,它的工作原理是通过构有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应的位置并插入,直到整个数组有序。

算法思想

第一步:从第一个元素开始,将其看做已排序部分.
第二步:取出下一个元素,与已排序的元素进行比较。
第三步:如果该元素小于已排序部分的最后一个元素,则将其插入到已排序的适当位置。
重复步骤二和三,知道整个数组都排好。

动图展示

代码实现

//插入排序

void Insertsort(int* a, int n)
{
	for (int i = 1; i < n; i++)
	{
		int j;
		int tmp = a[i];
		for (j = i - 1; j >= 0; j--)
		{
			if (a[j] > tmp)
			{
				a[j + 1] = a[j];
			}
			else
				break;
		}
		a[j + 1] = tmp;
	}
}

计数排序

引言

计数排序(Counting Sort)是一种基于哈希的排序算法。它的基本思想是通过统计每个元素的出现次数,然后根据统计结果将元素一次放到排序后的序列中。这种算法使用与元素范围较小的情况,例如0到k之间。

算法思想

计数排序的核心是创建一个计数数组。用于记录没每个元素出现的次数、然后根据计数数组对原始数组进行排序。具体步骤如下:
第一步:初始化一个长度为最大元素加1的计数数组,所有元素初始化为0.
第二步:遍历数组,将每个元素的值作为索引,在计数师叔祖的对应位置加1。
第三步;将原数组清空。
第四步:遍历计数器数组,按照数组中元素的个数放回到原数组中。

动图展示

代码实现

int * countingSort1(int arr[],int count,int max) {
    int index = 0;
    int *tmpArr = (int *)malloc(max*sizeof(int));
    int *result = (int *)malloc(max*sizeof(int));
    
    for(int k = 0;k<max;k++) {
        tmpArr[k] = 0;
    }
    
    for (int i = 0; i<count; i++) {
        tmpArr[arr[i]]++;
    }
    for (int j = 0; j<max; j++) {
        while (tmpArr[j]) {
            result[index++] = j;
            tmpArr[j]--;
        }
    }
    free(tmpArr);
    tmpArr = NULL;
    return result;
}

桶排序

引言

桶排序(Bucket Sort)是一种基于计数的排序算法,工作原理是将数据分到有限数量的桶子里,然后将桶子在分别排序(有可能在使用别的排序算法或者是以递归方式继续使用桶排序进行排序)。

算法思想

第一步:设置固定的空桶。
第二步:把数据放到对应的桶中。
第三步:把每个不为空的桶中的数据进行排序。
第四步:拼接不为空的桶中的数据,得到结果。

动图展示

代码实现

void bucketsort(vector<int>& nums) {
	int n = nums.size();
	int mn = nums[0], mx = nums[0];
	for (int i = 1; i < n; i++) {
		mn = min(mn, nums[i]);
		mx = max(mx, nums[i]);
	}
	int size = (mx - mn) / n + 1;   // size 至少要为1
	int cnt = (mx - mn) / size + 1; // 桶的个数至少要为1
	vector<vector<int>> buckets(cnt);
	for (int i = 0; i < n; i++) {
		int idx = (nums[i] - mn) / size;
		buckets[idx].push_back(nums[i]);
	}
	for (int i = 0; i < cnt; i++) {
		sort(buckets[i].begin(), buckets[i].end());
	}
	int index = 0;
	for (int i = 0; i < cnt; i++) {
		for (int j = 0; j < buckets[i].size(); j++) {
			nums[index++] = buckets[i][j];
		}
	}
}

基数排序

引言

基数排序(Radix Sort)是一种非比较型的排序算法,他根据数字的每一位来进行排序,通常用于整数排序,基数排序的基本思想就是通过对所有元素进行若干次“分配”和“收集”操作来实现排序。

算法思想

基数排序的算法思想可以概括为以下步骤:
第一步:获取待排序元素的最大值,并确定其位数。
第二步:从最低位开始,依次对所有的元素进行“分配”和“收集”操作。
第三步:在每一位上,根据该位置上的值将元素分配到相应的桶中。
第四步:在每个桶中的元素进行顺序收集,得到排序后的部分结果、
重复上述操作,直到所有所有位都排好。

动图展示

代码实现


int main()
{
	int a[] = { 1,6,4,12,32,16,10,89,100,120 };
	int b[10];
	int sum[256] = { 0 }, sum1[256] = { 0 }, sum2[256] = { 0 }, sum3[256] = { 0 };
	for (int i = 0; i <= 9; i++) {
		++sum[a[i] & 255];
		++sum1[(a[i] >> 8) & 255];
		++sum2[(a[i] >> 16 )& 255];
		++sum3[(a[i] >> 24) & 255];
	}
	for (int i = 1; i <= 255; i++)
	{
		sum[i] += sum[i - 1];
		sum1[i] += sum[i - 1];
		sum2[i] += sum[i - 1];
		sum3[i] += sum[i - 1];
	}
	for (int i = 0; i <9; i++)
		b[--sum[a[i] & 255]] = a[i];
	for (int i = 9; i >= 0; i--)
		a[--sum1[(a[i] >> 8) & 255]] = b[i];
	for (int i = 9; i >= 0; i--)
		b[--sum2[(a[i] >> 16) & 255]] = a[i];
	for (int i = 9; i >= 0; i--)
		a[--sum3[(a[i] >> 24) & 255]] = b[i];

	for (int i = 0; i <= 9; i++)
		printf("a[%d]=%d\n", i, a[i]);
	getchar();
	return 0;

}

希尔排序

引言

希尔排序(Shell Sort):是直接插入排序的一种优化,希尔排序通过基于直接插入排序间隔性的将非顺序序列的元素进行排序。需要进行多次排序,每次都更加的接近顺序,直到排好。

算法思想

首先创造变量gap作为将每隔gap个数分到一组中,将序列分为若干组,然后在每组中使用直接插入排序,同时每次使用完直接插入排序后都要减小gap的值(通常是gap/=2或者是gap=gap/3+1);直到最后gap为1,此时就是将一个十分接近顺序的序列进行插入排序,就排好啦。

动图展示

代码实现 

void slove(int* a, int n)
{
	int gap = n;//通常将gap初始化为数组的长度
	while (gap > 1)//最后一次gap=1,就是直接插入排序
	{
		gap = gap / 3 + 1;//每次都要减少对应的间距
		for (int i = 1; i < n; i++)//直接插入排序
		{
			int j;
			int tmp = a[i];
			for (j = i - gap; j >= 0; j -= gap)
			{
				if (a[j] > tmp)
				{
					a[j + gap] = a[j];
				}
				else
					break;
			}
			a[j + gap] = tmp; 
		}
	}
}

快速排序

引言

快速排序(Quick Sort)是一种分而治之的排序算法。它通过选择一个基准元素,将数组分为两部分,一部分比基准销小,另一部分比基准大,然后对这两部分进行快速排序,最终得到有序的数组。

算法思想

第一步、选择基准元素;从数组中选择一个元素作为基准。
第二步、分割数组:将比基准小的元素放在基准的左边,比基准大的元素放在基准的右边。
第三步、递归排序:对基准左边和右边的子数组分别进行快速排序。
重复步骤一、二、三、直到子数组的长度为1或0。

动图展示

动图分析 

这里选择数组首元素6的位置作为基准元素的位置,接下来目的就是把数组分左边小于基准元素右边大于基准元素。

左边指针为L右边指针为R,这里注意远离基准元素位置的指针要先走,R先走,从右向左找比a[keyi]小的数然后停下,L走,L从左向右走,找到比a[keyi]大的数然后停下。将两者位置上的值进行交换。然后继续R走,L走,直到两个指针相遇。

相遇后将这个位置的数与基准位置上的数进行交换。

然后再递归左边和右边的序列即可。

代码实现


void Quicksort(int* a, int left, int right)
{
	//改为左边先走即可(keyi右端点)
	if (left >= right)return;
	int keyi = left; //选取基准位置
	int begin = left; 
	int end = right; 
	while (left < right)
	{ 
		 
		while (left < right && a[right] > a[keyi] )
		{ 
			right--;               
		}
		while (left < right && a[left] < a[keyi])        
		{
			left++;   
		}
		swap(a[left], a[right]);
	}   
	swap(a[left], a[keyi]);   
	keyi = left;  
	Quicksort(a, begin, keyi - 1);  
	Quicksort(a, keyi + 1, end);
}

堆排序

引言

堆排序(Heap Sort)就是对直接选择排序的一种改进。此话怎讲呢?直接选择排序在待排序的n个数中进行n-1次比较选出最大或者最小的,但是在选出最大或者最小的数后,并没有对原来的序列进行改变,这使得下一次选数时还需要对全部数据进行比较,效率大大降低。堆排序算法是Floyd和Williams在1964年共同发明的,同时他们发明了“堆”这种数据结构。

大堆和小堆

这里简单的说下什么是小堆什么是大堆。小堆就是父节点的值比两个孩子节点的值都要小,孩子节点之间无大小比较;大堆就是父节点比两个孩子的节点的值都要大,孩子节点之间无比较。

算法思想 

堆排序使用到二叉树的调整算法,由于向下调整算法更优,这里只给出向下调整算法,向下调整算法的目的是为了建堆;建小堆排好是降序,建大堆排好是升序。

第一步、建好大堆:使用向下调整算法实现建堆。
第二步、交换头尾元素:每次建好堆之后我们可以确定的是堆顶一定是值最大的元素,将他交换到数列的末尾。
第三步、再次建堆:交换首尾之后,原来的堆就遭到了破坏,因此我们需要再次重新建堆,需要注意的是这一次建堆元素的个数就减一,因为刚才交换到最后的最大值已经算是排好的了,因此我们需要将剩下的元素建堆。
重复上述操作n-1次就排好了。

动图展示

代码实现

//堆排序(升序)
void adjustdown(int* a, int parent,int n)
{
	int child = 2 * parent + 1;
	while (child < n)
	{
		if (child + 1 < n && a[child] < a[child + 1])
			child++;
		if (a[child] > a[parent])
		{
			swap(a[child], a[parent]);
			parent = child;
			child = child * 2 + 1; 
		}
		else
			break;
	}
}
void heapsort(int* a, int n)
{
	int end = n;
	while (end > 0)//堆不为空时
	{
		for (int i = (end - 2) / 2; i >= 0; i--)
			adjustdown(a, i, end);//先向下调整
		end--;//调整完之后
		swap(a[0], a[end]);//下一次要调整的堆的个数就是这一次要交换的目标值
	}
}

归并排序

引言

归并是一种常见的算法思想,在许多领域都有广泛的应用。归并排序的主要目的是将两个已排序的序列合并成有序的序列。

算法思想

当然,对于一个非有序的序列,可以拆成两个非有序的序列。然后分别调用归并排序,然后对两个有序的序列在执行合并的过程。所以这里的“归”其实是递归,“并”就是合并。
整个算法的执行过程用mergeSort(a[],l,r)描述,代表当前代排序的数组a,左下标i,右区间下标r,分为以下几步。

第一步:计算中点mid=(l+r)/2;
第二步:递归调用mergeSort(a[],l,mid)和mergeSort(a[],mid+1,r).
第三步:将第二步中的两个数组进行合并,在储存在a[l:r]。
调用时,调用mergeSort(a[],0,n-1)就能得到整个数组的排序结果了。

动图展示

代码展示

void merge(int*a,int begin,int mid,int end)
{
	int* b=new int[end-begin+1];//开辟区间所占整形大小的空间 
	int i=begin,j=mid+1;int k=0;//设置遍历下标初始值 
	while(i<=mid&&j<=end)//对辅助数组处理 
	{
		if(a[i]<a[j])
		b[k++]=a[i++];
		else
		b[k++]=a[j++];
	}
	while(i<=mid)//把多余的一半放到辅助数组中 
	b[k++]=a[i++];
	while(j<=end)
	b[k++]=a[j++];
	k=0;
	for(int i=begin;i<=end;i++)
	a[i]=b[k++];
} 
 
void mergesort(int*a,int begin,int end)
{
	if(begin<end)
	{
		int mid=(begin+end)/2;
		mergesort(a,begin,mid);//裂开! 
		mergesort(a,mid+1,end);
		merge(a,begin,mid,end);//合体! 
	}
	else
	return;
}

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

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

相关文章

OpenCV计算形状之间的相似度ShapeContextDistanceExtractor类的使用

操作系统&#xff1a;ubuntu22.04OpenCV版本&#xff1a;OpenCV4.9IDE:Visual Studio Code编程语言&#xff1a;C11 1.功能描述 ShapeContextDistanceExtractor是OpenCV库中的一个类&#xff0c;主要用于计算形状之间的相似度或距离。它是基于形状上下文&#xff08;Shape Co…

vue页面和 iframe多页面无刷新方案和并行存在解决方案

面临问题 : back的后台以jsp嵌套iframe为主, 所以在前端框架要把iframe无刷新嵌套和vue页面进行并行使用,vue的keep-alive只能对虚拟dom树 vtree 进行缓存无法缓存iframe,所以要对iframe进行处理 tab标签的切换效果具体参考若依框架的tab切换,可以去若依看源码,若依源码没有实…

C语言| 数组

直接定义一个数组&#xff0c;并给所有元素赋值。 数组的下标从0开始&#xff0c;下标又表示数组的长度。 【程序代码】 #include <stdio.h> int main(void) { int a[5] {1, 2, 3, 4, 5}; int i; for(i0; i<5; i) { printf("a[%d] %d\…

EulerOS 安装docker 拉取opengauss 镜像

#下载docker包 wget https://download.docker.com/linux/static/stable/x86_64/docker-18.09.9.tgz #解压 tar zxf docker-18.09.9.tgz #移动解压后的文件夹到/usr/bin mv docker/* /usr/bin #写入docker.service cat >/usr/lib/systemd/system/docker.service <<E…

在不使用js在情况下只用css实现瀑布流效果

使用到的是grid 布局&#xff0c;需要注意的是grid-template-rows: masonry; 目前只有Firefox 浏览器支持这个效果&#xff0c;而且还是一个实验性属性需要在设置里面开发实验性选项才行。 实例 <!DOCTYPE html> <html> <head><title>Document</ti…

如何安装和配置JDK?(详细步骤分享)

1、下载JDK 访问Oracle官方网站&#xff08;Oracle | Cloud Applications and Cloud Platform&#xff09;&#xff0c;选择适合您操作系统的JDK版本进行下载。建议下载最新的稳定版本。 打开Java&#xff0c;往下拉&#xff0c;找到Oracle JDK 打开后&#xff0c;选择右边的J…

抖店被扣保证金,做起来太难导致心态崩了,怎么办?

我是王路飞。 技术、黑科技这些东西&#xff0c;决定不了你做店的结果。 能够决定最终结果的&#xff0c;一定是心态&#xff0c;是乐观还是悲观&#xff1f;是自负还是自卑&#xff1f;是焦躁还是踏实&#xff1f;这很关键。 店铺被扣保证金了&#xff0c;感觉没希望了&…

Vue22-v-model收集表单数据

一、效果图 二、代码 2-1、HTML代码 2-2、vue代码 1、v-model单选框的收集信息 v-model&#xff1a;默认收集的就是元素中的value值。 单选框添加默认值&#xff1a; 2、v-model多选框的收集信息 ①、多个选择的多选 注意&#xff1a; 此处的hobby要是数组&#xff01;&…

视频媒介VS文字媒介

看到一篇蛮有思考意义的文章就摘录下来了&#xff0c;也引起了反思 目录 一、视频的定义 二、”视频媒介“与”文字媒介”作对比 1.形象 VS 抽象 2.被动 VS 主动 三、视频的缺点-【更少】的思考 1.看视频为啥会导致【更少的思考】 2.内容的【浅薄化】 3.内容的【娱乐化…

ctfshow-web入门-命令执行(web43-web52)关于黑洞“ >/dev/null 2>1“的处理与绕过

目录 1、web43 2、web44 3、web45 4、web46 5、web47 6、web48 7、web49 8、web50 9、web51 10、web52 1、web43 在上一题 ‘黑洞’ 的基础上新增过滤&#xff1a; preg_match("/\;|cat/i", $c) 问题不大&#xff0c;我们不用分号和 cat 就行&#xff1a;…

【动态规划算法题记录】70. 爬楼梯——递归/动态规划

题目描述 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; 题目分析 递归法&#xff08;超出时间限制&#xff09; 递归参数与返回值 void reversal(int i, int k) 每次我们处理第i个台阶到第k个…

在vue3中用PlayCanvas构建3D物理模型

本文由ScriptEcho平台提供技术支持 项目地址&#xff1a;传送门 3D 物理引擎示例&#xff1a;PlayCanvas 创建可互动的物理场景 应用场景 本示例演示了如何使用 PlayCanvas 创建一个交互式的 3D 物理场景。在这个场景中&#xff0c;用户可以创建和删除椅子&#xff0c;椅子…

Python入门教程 - 模块、包(八)

目录 一、模块的概念 二、模块的导入方式 三、案例演示 3.1 import模块名 3.2 from 模块名 import 功能名 3.3 from 模块名 import * 3.4 as定义别名 四、自定义模块 4.1 制作自定义模块 4.2 测试模块 4.3 注意事项 4.4 __all__ 五、Python包 5.1 包的概念 5.2 …

操作系统——信号

将信号分为以上四个阶段 1.信号注册&#xff1a;是针对信号处理方式的规定&#xff0c;进程收到信号时有三种处理方式&#xff1a;默认动作&#xff0c;忽略&#xff0c;自定义动作。如果不是自定义动作&#xff0c;这一步可以忽略。这个步骤要使用到signal/sigaction接口 2.…

2002-2023年款别克君威 君威GS维修手册和电路图资料更新

经过整理&#xff0c;2002-2023年款别克君威 君威GS全系列已经更新至汽修帮手资料库内&#xff0c;覆盖市面上99%车型&#xff0c;包括维修手册、电路图、新车特征、车身钣金维修数据、全车拆装、扭力、发动机大修、发动机正时、保养、电路图、针脚定义、模块传感器、保险丝盒图…

Dorkish:一款针对OSINT和网络侦查任务的Chrome扩展

关于Dorkish Dorkish是一款功能强大的Chrome扩展工具&#xff0c;该工具可以为广大研究人员在执行OSINT和网络侦查任务期间提供强大帮助。 一般来说&#xff0c;广大研究人员在执行网络侦查或进行OSINT信息收集任务过程中&#xff0c;通常会使用到Google Dorking和Shodan&…

晶圆代工市占洗牌,中芯跃居第三名 | 百能云芯

市场研究机构集邦咨询&#xff08;TrendForce&#xff09;最新发布的调查显示&#xff0c;今年第1季前五大晶圆代工厂第1季排名出现明显变动&#xff0c;除了台积电&#xff08;TSMC&#xff09;继续蝉联第一名&#xff0c;中芯国际&#xff08;SMIC&#xff09;受惠消费性库存…

Flutter-使用MethodChannel 实现与iOS交互

前言 使用 MethodChannel 在 Flutter 与原生 Android 和 iOS 之间进行通信&#xff0c;可以让你在 Flutter 应用中调用设备的原生功能。 基础概念 MethodChannel&#xff1a;Flutter 提供的通信机制&#xff0c;允许消息以方法调用的形式在 Flutter 与原生代码之间传递。方法…

光储充一体化充电站:能源革新的绿色引擎

在这个科技日新月异的时代&#xff0c;一场绿色能源的革命正悄然兴起。 光储充一体化充电站&#xff0c;作为这场革命中的璀璨明星&#xff0c;正以其独特的魅力&#xff0c;引领我们走向更加环保、高效的未来。 光储充一体化充电站&#xff0c;顾名思义&#xff0c;将光伏发电…

Chromium源码阅读:Mojo实战:从浏览器JS API 到blink实现

​ 通过在前面几篇文章&#xff0c;我们粗略梳理了Mojo这套跨进程通信的设计思路和IDL细节。 实际上&#xff0c;Mojo不止是跨进程通信框架&#xff0c;而是跨语言的模块通信自动化系统。 在浏览器暴露的JS API&#xff0c;也是需要通过Mojo这个系统进行桥接&#xff0c;最终…