《C语言实现各种排序算法》

news2024/9/9 4:14:23

文章目录

    • 一、排序
        • 1、排序的各种方式分类
    • 二、插入排序
        • 1、直接插入排序
        • 2、希尔排序
        • 3、希尔排序时间复杂度分析
    • 三、选择排序
        • 1、直接选择排序
        • 2、堆排序
    • 四、交换排序
        • 1、冒泡排序
        • 2、快速排序
        • 3、快速排序hoare找基准值
        • 4、快排挖坑法找基准值
        • 5、前后指针法
        • 6、快速排序非递归实现
    • 五、归并排序
        • 1、递归实现
        • 2、非递归实现
    • 六、排序算法复杂度及稳定性分析
    • 七、计数排序

一、排序

在生活中各种场景中都会有排序的身影存在,在网购时会有价格排序,在学校中会有程序排序,在游戏中会有段位的排序等。

1、排序的各种方式分类

在这里插入图片描述

这些排序的效率各有不同

二、插入排序

直接插⼊排序是⼀种简单的插⼊排序法,其基本思想是:把待排序的记录按其关键码值的⼤⼩逐个插⼊到⼀个已经排好序的有序序列中,直到所有的记录插⼊完为⽌,得到⼀个新的有序序列 。

1、直接插入排序

当插⼊第 i(i>=1) 个元素时,前⾯的 array[0],array[1],…,array[i-1] 已经排好序,此时⽤ array[i] 的排序码与 array[i-1],array[i-2],… 的排序码顺序进⾏⽐较,找到插⼊位置即将 array[i] 插⼊,原来位置上的元素顺序后移

代码实现:

void InsertionSort(int* arr, int n)
{
	int i = 0;
	int j = 0;
	for ( i = 1; i < n; i++)
	{
		j = i-1;
		int tmp = arr[i];
		while (j >= 0)
		{
			if (arr[j] < tmp)
			{
				arr[j + 1] = arr[j];
				j--;
			}
			else
			{
				break;
			}
		}
		arr[j + 1] = tmp;
	}
}
2、希尔排序

直接插入排序效率不高,在直接插入排序的基础上进行优化,改进,把一个大的集合分为若干个小的集合再进行直接插入排序,从而提升效率。
希尔排序法⼜称缩⼩增量法。希尔排序法的基本思想是:先选定⼀个整数(通常是gap = n/3+1),把待排序⽂件所有记录分成各组,所有的距离相等的记录分在同⼀组内,并对每⼀组内的记录进⾏排序,然后gap=gap/3+1得到下⼀个整数,再将数组分成各组,进⾏插⼊排序,当gap=1时,就相当于直接插⼊排序。

代码实现:

void ShellSort(int* arr, int n)
{
	int gec = n;
	int i, j = 0;
	while (gec > 1)
	{
		gec = gec / 3 + 1;
		for (i = gec; i < n; i++)
		{
			j = i - gec;
			int tmp = arr[i];
			while (j >= 0)
			{
				if (arr[j] < tmp)
				{
					arr[j + gec] = arr[j];
					j -= gec;
				}
				else
				{
					break;
				}
			}
			arr[j + gec] = tmp;
		}
	}
}
3、希尔排序时间复杂度分析

外层循环的时间复杂度可以直接给出为: O(log2 n) 或者 O(log3 n) ,即 O(log n)
内层循环

在这里插入图片描述
在这里插入图片描述

希尔排序的时间复杂度大约为 log ⁡ 2 n 1.3 \log_2 {n^{1.3}} log2n1.3

三、选择排序

每⼀次从待排序的数据元素中选出最⼩(或最⼤)的⼀个元素,存放在序列的起始位置,直到全部待排序的数据元素排完 。

1、直接选择排序
void SelectSort(int* a, int n)
{
	int begin = 0, end = n - 1;
	while (begin < end)
	{
		int max = begin, min = begin;
		for (int i = begin + 1; i <= end; i++)
		{
			if (a[i] < a[min])
			{
				min = i;
			}
			if (a[i] > a[max])
			{
				max = i;
			}
		}
		if (max == begin)
		{
			max = min;
		}
		{
			int tmp = a[min];
			a[min] = a[begin];
			a[begin] = tmp;
		}
		{
			int tmp = a[max];
			a[max] = a[end];
			a[end] = tmp;

		}
		begin++;
		end--;
	}
}
2、堆排序
void HeapSort(int* arr, int n)
{
	int i = 0;
	for (i = (n-1)/2; i>=0; i--)
	{
		
		int parent = i;
		int child = parent * 2 + 1;
		while (child <= i)
		{
			if (child + 1 <= i && arr[child + 1] < arr[child])
			{
				child++;
			}
			if (arr[child] < arr[parent])
			{
				int tmp = arr[parent];
				arr[parent] = arr[child];
				arr[child] = tmp;
				parent = child;
				child = parent * 2 + 1;
			}
			else
			{
				break;
			}
		}

	}
	for (i = n - 1; i > 0; i--)
	{
		int child = i;
		int parent = 0;
		int tmp = arr[parent];
		arr[parent] = arr[child];
		arr[child] = tmp;
		child = parent * 2 + 1;
		while (child < i)
		{
			if (child + 1 < i && arr[child + 1] < arr[child])
			{
				child++;
			}
			if (arr[child] < arr[parent])
			{
				tmp = arr[parent];
				arr[parent] = arr[child];
				arr[child] = tmp;
				parent = child;
				child = parent * 2 + 1;
			}
			else
			{
				break;
			}
		}
	}
}

堆排序的时间复杂度为n log ⁡ n \log n logn

四、交换排序

1、冒泡排序
void BubbleSort(int* a, int n)
{
	for (int i = 0; i < n - 1; i++)
	{
		int falg = 1;
		for (int j = 0; j < n - 1 - i; j++)
		{
			if (a[j] > a[j + 1])
			{
				int tmp = a[j];
				a[j] = a[j + 1];
				a[j + 1] = tmp;
				falg = 0;
			}
		}
		if (falg)
		{
			break;
		}
	}
}
2、快速排序

通过找基准值,基准值的位置就是这个值该待的位置,然后递归找基准值左边区间和右区间,直到区间不成立位置,确定每个值该待的位置完成排序。

int _QuickSort(int* a, int left, int right)
{
	int keyi = left;
	left++;
	while (left <= right)
	{
		
 		while (left <= right && a[left] < a[keyi])
		{
			left++;
		}
		while (left <= right && a[right] > a[keyi])
		{
			right--;
		}
		if (left <= right)
		{
			int tmp = a[left];
			a[left] = a[right];
			a[right] = tmp;
			left++;
			right--;
		}

	}
	int tmp = a[keyi];
	a[keyi] = a[right];
	a[right] = tmp;

	return right;
}

void QuickSort(int* a, int left,int right)
{
	if (left >= right)
	{
		return;
	}
	
	int keyi = _QuickSort(a, left, right);
	QuickSort(a, keyi + 1, right);
	QuickSort(a, left, keyi - 1);

}

快排的空间复杂度:O( l o n g n long n longn)
快排的时间复杂度:O(n l o n g n long n longn)

3、快速排序hoare找基准值
 //快速排序hoare版本
int PartSort1(int* a, int left, int right)
{
	int keyi = left;
	++left;
	while (left < right)
	{
		while (left <=right && a[right] > a[keyi])
		{
			right--;
		}
		while (left <= right && a[left] < a[keyi])
		{
			left++;
		}
		if (left < right)
		{
			swap(&a[left], &a[right]);
		}
	}
	swap(&a[keyi], &a[right]);

	return right;
}
4、快排挖坑法找基准值
// 快速排序挖坑法
int PartSort2(int* a, int left, int right)
{
	int hole = left;
	int tmp = a[hole];
	while (left < right)
	{
		while (left < right && a[right] > tmp)
		{
			right--;
		}
		a[hole] = a[right];
		hole = right;
		while (left < right && a[left] < tmp)
		{
			left++;
		}
		a[hole] = a[left];
		hole = left;
	}
	a[hole] = tmp;
	return hole;
}
5、前后指针法
// 快速排序前后指针法
int PartSort3(int* a, int left, int right)
{
	int pfast = left + 1;
	int pslow = left;
	int keyi = left;
	while (pfast <= right)
	{
		while (pfast <= right && a[pfast] < a[keyi] && ++pslow != pfast)
		{
			swap(&a[pslow], &a[pfast]);
		}
		pfast++;
	}
	swap(&a[pslow], &a[keyi]);
	return pslow;
}
6、快速排序非递归实现
// 快速排序 非递归实现

//运用栈数据结构
typedef int StackDataType;

typedef struct Stack
{
	int* a;
	int capacity;
	int top;
}ST;

//栈初始化
void STInit(ST* ps)
{
	ps->a = NULL;
	ps->capacity = ps->top = 0;
}

//入栈
void STPush(ST* ps,StackDataType x)
 {
	if (ps->capacity == ps->top)
	{
		int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		int* tmp = (int*)realloc(ps->a, newcapacity * sizeof(StackDataType));
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		ps->capacity = newcapacity;
		ps->a = tmp;
		tmp = NULL;
	}
	ps->a[ps->top++] = x;
}

//判断栈是否为空
bool STEmpty(ST* ps)
{
	return ps->top == 0;
}

//出栈
void STPop(ST* ps)
{
	if (ps->top == 0)
	{
		return;
	}
	ps->top--;
}

//取栈顶元素
StackDataType STTop(ST* ps)
{
	if (ps->top == 0)
	{
		exit(1);
	}
	return ps->a[ps->top - 1];
}

void QuickSortNonR(int* a, int left, int right)
{
	ST s;
	STInit(&s);

	STPush(&s, right);
	STPush(&s, left);
	while (!STEmpty(&s))
	{
		int begin = STTop(&s);
		STPop(&s);
		int end = STTop(&s);
		STPop(&s);


		int pfast = begin + 1;
		int pslow = begin;
		int keyi = begin;
		while (pfast <= end)
		{
			while (pfast <= end && a[pfast] < a[keyi] && ++pslow != pfast)
			{
				swap(&a[pslow], &a[pfast]);
			}
			pfast++;
		}
		swap(&a[pslow], &a[keyi]);

		if (pslow + 1 < end)
		{
			STPush(&s, end);
			STPush(&s, pslow + 1);
		}
		if (pslow - 1 > begin)
		{
			STPush(&s, pslow - 1);
			STPush(&s, begin);
		}
	}

五、归并排序

归并排序算法思想:
归并排序(MERGE-SORT)是建⽴在归并操作上的⼀种有效的排序算法,该算法是采⽤分治法(DivideandConquer)的⼀个⾮常典型的应⽤。将已有序的⼦序列合并,得到完全有序的序列;即先使每个⼦序列有序,再使⼦序列段间有序。若将两个有序表合并成⼀个有序表,称为⼆路归并。

1、递归实现

在这里插入图片描述

代码实现:

//归并排序
void _MergeSort(int* arr, int left, int right, int* tmp)
{
	if (left >= right)
	{
		return;
	}
	int mid = (right - left) / 2 + left;

	_MergeSort(arr, left, mid, tmp);
	_MergeSort(arr, mid + 1, right,tmp);

	//合并
	int begin1 = left, end1 = mid;
	int begin2 = mid + 1, end2 = right;
	int begin = left;

	while (begin1 <= end1 && begin2 <= end2)
	{
		if (arr[begin1] < arr[begin2])
		{
			tmp[begin++] = arr[begin1++];
		}
		else
		{
			tmp[begin++] = arr[begin2++];
		}
	}
	while (begin1 <= end1)
	{
		tmp[begin++] = arr[begin1++];
	}
	while (begin2 <= end2)
	{
		tmp[begin++] = arr[begin2++];
	}

	//传值
	while (left <= right)
	{
		arr[left] = tmp[left];
		left++;
	}
}

void MergeSort(int* arr, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	_MergeSort(arr, 0, n - 1, tmp);
	free(tmp);
	tmp = NULL;
}
2、非递归实现
// 归并排序非递归实现
void MergeSortNonR(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		perror("malloc fail");
		exit(1);
	}

	int k = 1;
	while (k < n)
	{
		int i = 0;
		for (i = 0; i < n - 2 * k + 1;i += 2*k)
		{
			int mid = i + k - 1;
			int left = i;
			int right = i + 2 * k - 1;

			int begin1 = left, end1 = mid;
			int begin2 = mid + 1, end2 = right;

			int begin = left;
			while (begin1 <= end1 && begin2 <= end2)
			{
				if (a[begin1] < a[begin2])
				{
					tmp[begin++] = a[begin1++];
				}
				else
				{
					tmp[begin++] = a[begin2++];
				}
			}

 			while (begin1 <= end1)
			{
				tmp[begin++] = a[begin1++];
			}

			while (begin2 <= end2)
			{
				tmp[begin++] = a[begin2++];
			}

			while (left <= right)
			{
				a[left] = tmp[left];
				left++;
			}
		}

		if (i < n-k)
		{
			int mid = i+k-1;
			int left = i;
			int right = n-1;

			int begin1 = left, end1 = mid;
			int begin2 = mid + 1, end2 = right;

			int begin = left;
			while (begin1 <= end1 && begin2 <= end2)
			{
				if (a[begin1] < a[begin2])
				{
					tmp[begin++] = a[begin1++];
				}
				else
				{
					tmp[begin++] = a[begin2++];
				}
			}

			while (begin1 <= end1)
			{
				tmp[begin++] = a[begin1++];
			}

			while (begin2 <= end2)
			{
				tmp[begin++] = a[begin2++];
			}

			while (left <= right)
			{
				a[left] = tmp[left];
				left++;
			}
		}
		k *= 2;
	}

	free(tmp);
}

六、排序算法复杂度及稳定性分析

稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,⽽在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。

在这里插入图片描述

七、计数排序

只能排序整数,不适合排不集中的数据如1,10000000,100000002;会产生空间浪费

// 计数排序
void CountSort(int* a, int n)
{
	int min = a[0], max = a[0];
	for (int i = 1; i < n; i++)
	{
		if (min > a[i])
		{
			min = a[i];
		}
		if (max < a[i])
		{
			max = a[i];
		}
	}

	int range = max - min + 1;
	int* count = (int*)calloc(range ,sizeof(int));
	for (int i = 0; i < n; i++)
	{
		count[a[i]-min]++;
	}
	int indext = 0;
	for (int i = 0; i < range; i++)
	{
		while (count[i]--)
		{
			a[indext++] = i + min;

		}
	}

	free(count);
	count = NULL;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

甄选范文“论数据分片技术及其应用”软考高级论文,系统架构设计师论文

论文真题 数据分片就是按照一定的规则,将数据集划分成相互独立、正交的数据子集,然后将数据子集分布到不同的节点上。通过设计合理的数据分片规则,可将系统中的数据分布在不同的物理数据库中,达到提升应用系统数据处理速度的目的。 请围绕“论数据分片技术及其应用”论题…

OCC BRepOffsetAPI_ThruSections使用

目录 一、BRepOffsetAPI_ThruSections简介 二、功能与特点 三、应用场景 四、示例 一、BRepOffsetAPI_ThruSections简介 在Open CASCADE Technology (OCCT) 中,BRepOffsetAPI_ThruSections 类是用来通过放样生成一个实体或者一个面壳(Shell)。当使用这个类时,isSolid 参…

具身智能,存内计算芯片应用新赛道

引言&#xff1a; 具身智能&#xff08;Emboided Al&#xff09;是指通过身体与环境的动态互动&#xff0c;实现对世界的感知、认知和行为控制的智能系统。具身智能强调的是智能体与环境的交互/学习/改变&#xff0c;而不仅仅是身体本身。具身智能的核心要素体现在智能体通过…

MySQL --- 数据类型

一、类型分类 数值类型bit(M)位类型&#xff0c;M指定位数&#xff0c;默认值1&#xff0c;范围1 - 64bool使用0和1表示真假tinyint [unsigned]带符号范围 -128~127&#xff0c;无符号范围 0~255&#xff0c;默认有符号smallint [unsigned]带符号范围 -2^15~2^15-1&#xff0c…

【网络世界】HTTPS协议

目录 &#x1f308;前言&#x1f308; &#x1f4c1; HTTP缺陷 &#x1f4c1; HTTPS &#x1f4c2; 概念 &#x1f4c2; 加密 &#x1f4c2; 加密方式 &#x1f4c1; 中间人攻击 &#x1f4c1; CA机构和证书 &#x1f4c2; 数据摘要&#xff08;数据指纹&#xff09; &…

nginx反向代理和负载均衡+安装jdk-22.0.2

ps -aux|grep nginx //查看进程 nginx 代理 nginx代理是负载均衡的基础 主机&#xff1a;192.168.118.60 这台主机只发布了web服务&#xff0c;没有做代理的任何操作 修改一下index.html中的内容 echo "this is java web server" > /usr/local/nginx/htm…

【OpenCV-Python实战项目】26-实时手部跟踪

0 介绍 目的&#xff1a;使用mediapipe库做手部的实时跟踪 检测流程&#xff1a;&#xff08;1&#xff09;手掌检测&#xff1b;&#xff08;2&#xff09;手掌特征检测 手掌特征分布&#xff1a;mediapipe手掌特征分布如下&#xff1a; 1.环境要求 后续代码运行环境&…

力扣SQL50 换座位

Problem: 626. 换座位 &#x1f468;‍&#x1f3eb; 参考题解 Code SELECT(CASEWHEN MOD(id, 2) ! 0 AND counts ! id THEN id 1WHEN MOD(id, 2) ! 0 AND counts id THEN idELSE id - 1END) AS id,student FROMseat,(SELECTCOUNT(*) AS countsFROMseat) AS seat_counts O…

电测量数据交换DLMSCOSEM组件第53部分:DLMSCOSEM应用层(中)

2.综述 (续上篇) 上篇地址:http://t.csdnimg.cn/DBKrg 2.2DLMS/COSEM应用层主要特点 2.2.1DLMS/COSEM应用层结构 DLMS/COSEM AL的主要部件是应用服务对象(ASO)。它给其服务用户提供服务(COSEM应用进程),并使用支撑层提供的服务。客户机和服务器侧都包含三个必…

Image Caption评估指标深入理解

前言&#xff1a;刚开始做图像描述的任务就整理了这些评估指标&#xff0c;时间久远有点记不清怎么具体实现原理了&#xff0c;结果面试的时候就问了这个问题&#xff0c;没答上来&#xff0c;郁闷了很久&#xff0c;还是基础不扎实&#xff0c;浅浅记录一下 文章目录 BLEUROUG…

C语言的结构体

结构体定义 结构体指针

【优选算法】滑动窗口——leetcode——串联所有单词的⼦串(hard)

目录 1.题目 2&#xff0c;算法原理 ​编辑 1.哈希表 2.left和right指针的移动 3.滑动窗口的执行次数 3.代码实现 1.C代码 2.C语言代码 4.C知识点 1. std::vector 2. std::string 3. std::unordered_map 4. 迭代器 5. 范围循环 (range-based for loop) 6. 动…

0基础学会无代码在亚马逊云科技AWS上利用LLM和智慧体(Agent)开发客服机器人

简介&#xff1a; 小李哥将继续每天介绍一个基于亚马逊云科技AWS云计算平台的全球前沿AI技术解决方案&#xff0c;帮助大家快速了解国际上最热门的云计算平台亚马逊云科技AWS AI最佳实践&#xff0c;并应用到自己的日常工作里。 本次介绍的是如何利用亚马逊云科技大模型托管服…

【解决方法】git clone出现 curl 56 OpenSSL SSL_read: Connection was reset, errno 10054

当我们克隆别人的项目出现以下提示信息时候 remote: Enumerating objects: 7095, done. error: RPC failed; curl 56 OpenSSL SSL_read: Connection was reset, errno 10054 error: 2292 bytes of body are still expected fetch-pack: unexpected disconnect while reading s…

Python(C++)大尺度分层边值时变图统计推理并行算法

&#x1f3af;要点 &#x1f3af;分层结构制定生成模型 | &#x1f3af;贝叶斯模型选择程序 | &#x1f3af;分层结构图的信息性 | &#x1f3af;分层模型适应实值边协变量的网络 | &#x1f3af;分层模型适应时变网络&#xff0c;划分层对应于检测变化点 | &#x1f3af;定义…

Python中15个让你代码更优雅的上下文管理器用法

文末赠免费精品编程资料~~ 今天&#xff0c;我们要探索的是Python中一个超级实用又往往被低估的特性——上下文管理器。这可不是普通的魔法&#xff0c;它能让你的代码更加整洁、安全&#xff0c;还能自动处理资源&#xff0c;就像变魔术一样。准备好&#xff0c;让我们一起揭…

一分多行列转换(Gbase版)

1、源数据表结构 CREATE TABLE "sf_ref_pd_config" ("I_BATCH_NO" decimal(5,0) DEFAULT NULL COMMENT 批次ID,"V_ASSET_CLASS_NAME" varchar(200) DEFAULT NULL COMMENT 资产类型,"N_EXEC_ID" decimal(5,0) DEFAULT NULL COMMENT 执…

pyjwt:Python 中的 JWT 处理专家

文章目录 探索 pyjwt&#xff1a;Python 中的 JWT 处理专家简介&#xff1a;为何选择 pyjwt&#xff1f;什么是 pyjwt&#xff1f;安装 pyjwtpyjwt 的基本使用1. 编码JWT2. 解码JWT3. 验证签名4. 过期时间5. 自定义头部 场景应用场景一&#xff1a;用户登录场景二&#xff1a;A…

深度学习的数据类型总结

文章目录 1.基本概念1.比特&#xff08;bit&#xff09;&#xff1a;2. **字节**&#xff08;Byte&#xff09;:2. **数据类型**: 2. 相互转化 1.基本概念 1.比特&#xff08;bit&#xff09;&#xff1a; 计算机中最小的数据存储单位&#xff0c;用 0 和 1 表示。信息传输速…

python制作一个AI聊天机器人-【python教程】教你用python制作一个AI聊天机器人,源码可分享,零基础也能实现!

要制作一个基本的AI聊天机器人&#xff0c;我们可以使用Python的多个库&#xff0c;其中一个非常流行且易于上手的是Rasa。一个简单的入门示例&#xff0c;我们可以使用pyttsx3&#xff0c;是一个Python库&#xff0c;用于将文本转换为语音。 它提供了一个简单易用的接口&#…