【算法】(C语言):快速排序(递归)、归并排序(递归)、希尔排序

news2024/9/24 23:32:22

快速排序(递归) 

  1. 左指针指向第一个数据,右指针指向最后一个数据。取第一个数据作为中间值。
  2. 右指针指向的数据 循环与中间值比对,若大于中间值,右指针往左移动一位,若小于中间值,右指针停住。右指针指向的数据放入左指针指向的位置。
  3. 左指针指向的数据 循环与中间值比对,若小于中间值,左指针往右移动一位,若大于中间值,左指针停住。左指针指向的数据放入右指针指向的位置。
  4. 重复2和3,直到左指针和右指针指向同一个位置pos,则中间值放入该位置pos。
  5. 从中间值所在位置pos将数据分成左边和右边两部分。左边数值都比中间值小,右边数值都比中间值大。
  6. 重复1-5,直到左边或右边只有一个数据。到此排序完成。

(注:左指针指向的数据始终比中间值小,右指针指向的数据始终比中间值大。)

时间复杂度:最好情况 O(nlogn),最坏情况 O(n^{2}),平均情况 O(nlogn)

  • 左右指针依次从头或从尾与中间值比对,一轮比对约n次。
  • 若每次取的中间值正好是中间位置的数据,每次都是对半拆分,拆分层级logn,则所有数据需约logn轮的比对,总时间 约 O(nlogn)。
  • 若已经排好序了,则每次取的中间值都是最小或最大值,则每次都是依次从下一位数据重新开始,类似斜树,最坏时间约  O(n^{2})。

空间复杂度:最好情况  O(logn),最坏情况 O(n)。

  • 在原位置排序,使用栈作为辅助空间。每次递归,中间值入栈,递归结束,中间值出栈。
  • 若最好情况,拆分层级logn,最多logn个中间值在栈中,则即空间使用 O(logn)。
  • 若最坏情况,则递归n次,即空间使用约  O(n)。


C语言实现:(quicksort.c)

#include <stdio.h>

/* function prototype */
void quicksort(int *, int, int);	// quick sort (recursion)
void traverse(int *, int);		// show element one by one

/* main function */
int main(void)
{
	int arr[] = {4,2,6,9,5,1,3};
	int n = sizeof(arr) / sizeof(int);
	traverse(arr, n);

	quicksort(arr, 0, n - 1);
	printf("[ after quick sort ] ");
	traverse(arr, n);
	return 0;
}
/* subfunction */
void quicksort(int *array, int start, int end)		// quick sort (recursion)
{
	if(start >= end) return ;
	int low = start, high = end;
	int middata = array[low];	// the first element as middle data
	while(low < high)
	{
		// right side, data is bigger than middle data.High index move a step to left  
		while(low < high && array[high] >= middata) high--;
		// right side, if data is smaller than middle data, data change to low index  
		array[low] = array[high];
		// left side, data is smaller than middle data.Low index move a step to right
		while(low < high && array[low] < middata) low++;
		// left side, if data is bigger than middle data, data change to high index
		array[high] = array[low];
	}
	// the middle data in the correct position
	array[low] = middata;
	// from the position of the middle data, split to two sides
	quicksort(array, start, low  - 1);
	quicksort(array, low + 1, end);
}

void traverse(int *array, int length)		// show element one by one
{
	printf("elements(%d): ", length);
	for(int k = 0; k < length; k++)
	{
		printf("%d  ", array[k]);
	}
	printf("\n");
}

编译链接: gcc -o quicksort quicksort.c

执行可执行文件: ./quicksort



归并排序(递归)

  1. 从中间位置,将数据拆分成左右两部分。再分别将左右两部分从各自中间位置再拆分成左右两部分。直到左边或右边只有一个元素。
  2. 将最多只有一个元素的左右两边,排序合并在一起。
  3. 将排好序的左右两边,排序合并在一起。
  4. 重复3,直到全部排好序。

时间复杂度:最好情况 O(nlogn),最坏情况 O(nlogn),平均情况 O(nlogn)

  • 每次对半拆分,拆分层级logn,所有数据都需要比对 进行重新排序合并,一轮比对合并约n次,共约logn轮,则总时间约 nlogn,即 O(nlogn)。

空间复杂度:O(n)

  • 有多少数据,就需要多少额外的空间存储 已排好序的数据,即 O(n)。


C语言实现:(mergesort.c)

#include <stdio.h>
#include <math.h>

/* function prototype */
void mergesort(int *, int, int);	// merge sort (recursion)
void traverse(int *, int);		// show element one by one

/* main function */
int main(void)
{
	int arr[] = {4,2,6,9,5,1,3};
	int n = sizeof(arr) / sizeof(int);
	traverse(arr, n);

	mergesort(arr, 0, n - 1);
	printf("[ after merge sort ] ");
	traverse(arr, n);
	return 0;
}
/* subfunction */
void mergesort(int *array, int start, int end)		// merge sort (recursion)
{
	if(start >= end) return ;
	// from the middle, split the array to the left side and the right side
	int mid = start + ceil((end - start) / 2);
	mergesort(array, start, mid);
	mergesort(array, mid + 1, end);
	// merge the left and right, sort to the new array
	int tmparr[end - start + 1];
	int i = start, j = mid + 1;
	for(int k = 0; k <= end - start; k++)
	{
		// the right side is over or left data < right data, copy the left data
		if(j > end || (i <= mid && array[i] < array[j]))
		{
			tmparr[k] = array[i];
			i++;
		}
		// the left side is over or left data >= right data, copy the right data
		else
		{
			tmparr[k] = array[j];
			j++;
		}
	}
	// elements in the new array copy to the original array
	for(int i = start, k = 0; i <= end; i++, k++)
	{
		array[i] = tmparr[k];
	}
}

void traverse(int *array, int length)		// show element one by one
{
	printf("elements(%d): ", length);
	for(int k = 0; k < length; k++)
	{
		printf("%d  ", array[k]);
	}
	printf("\n");
}

编译链接: gcc -o mergesort mergesort.c

执行可执行文件: ./mergesort



希尔排序

  1. 取一定间隔(开始一般为数据量的一半),将数据分为多个组,每个组分别排序。
  2. 将间隔减半,数据分为多个组,每个组分别排序。
  3. 重复2,直到间隔为1,完成最后的排序。

时间复杂度:O(n^{1.3}) - O(n^{2})

  • 插入排序的升级。先根据大间隔,按组进行插入排序,再依次减小间隔,按组进行插入排序。
  • n^{2}快,但比nlogn慢。

空间复杂度:O(1)

  • 在原位置排序,只重复使用了用于交换的临时空间,不随数据量的变动而变动,空间使用为常量(1)。


C语言实现:(shellsort.c)

#include <stdio.h>
#include <math.h>

/* function prototype */
void shellsort(int *, int);			// shell sort
void traverse(int *, int);			// show element one by one

/* main function */
int main(void)
{
	int arr[] = {4,2,6,9,5,1,3};
	int n = sizeof(arr) / sizeof(int);
	traverse(arr, n);

	shellsort(arr, n);
	printf("[ after shell sort ] ");
	traverse(arr, n);
	return 0;
}
/* subfunction */
void shellsort(int *array, int length)		// shell sort
{
	int gap = ceil(length / 2);	// steps of two comparative data
	while(gap > 0)
	{
		// from gap to the end, each element compare with data before gap steps
		for(int i = gap; i < length; i++)
		{
			// element cycle compare with data before gap steps, until 0 index
			for(int j = i; j >= gap; j -= gap)
			{
				if(array[j] < array[j - gap])
				{
					int tmp = array[j];
					array[j] = array[j - gap];
					array[j - gap] = tmp;
				}
			}
		}
		// reduce the step
		gap  = ceil(gap / 2);
	}
}

void traverse(int *array, int length)		// show element one by one
{
	printf("elements(%d): ", length);
	for(int k = 0; k < length; k++)
	{
		printf("%d  ", array[k]);
	}
	printf("\n");
}

编译链接: gcc -o shellsort shellsort.c

执行可执行文件: ./shellsort

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

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

相关文章

【学术会议征稿】第五届大数据、人工智能与物联网工程国际会议

第五届大数据、人工智能与物联网工程国际会议 2024 5th International Conference on Big Data, Artificial Intelligence and Internet of Things 第五届大数据、人工智能与物联网工程国际会议&#xff08;ICBAIE 2024&#xff09;定于2024年10月25-27号在中国深圳隆重举行。…

新功能上线 | 自定义工作台,成就个性化办公

为进一步优化用户操作体验&#xff0c;帮助用户更轻松、便捷的使用采购系统&#xff0c;隆道平台面向用户推出自定义工作台。根据个人的工作习惯和需求&#xff0c;轻松定制专属的工作界面。无论您需要快速查看待办事项&#xff0c;还是实时追踪业务进度&#xff0c;或是全面掌…

掌握这五大关键,轻松驾驭AI大模型项目落地

随着AI技术的蓬勃发展&#xff0c;众多企业纷纷投身于大模型项目的浪潮中&#xff0c;力求在这场技术革新中占据一席之地。然而&#xff0c;成功与失败并存&#xff0c;背后的原因引人深思。本文将为您揭示五大关键因素&#xff0c;助您轻松驾驭AI大模型项目的落地过程。 一、…

FL Studio 24.1.1.4234 Crack

Image-Line bvba 的 FL Studio 是一款数字音频工作站&#xff08;DAW&#xff09;软件&#xff0c;是音乐家、制作人和音频工程师的完整音乐制作解决方案。FL Studio 以其直观的界面、强大的功能和广泛的性能而著称&#xff0c;用户可以利用它高效、创造性地进行作曲、编曲、录…

动手学深度学习53 语言模型

动手学深度学习53 语言模型 语言模型代码QA 语言模型 核心&#xff1a;预测文本出现的概率 最常见应用&#xff1a;做预训练模型 当数据序列很长怎么办&#xff1f;常用n-gram 。 一元语法&#xff1a;马尔科夫假设tao0 基本认为每一个字是独立的&#xff0c;不管前面的东西。…

zabbix“专家坐诊”第245期问答

问题一 Q&#xff1a;vfs.dev.discovery拿的是哪里的文件&#xff0c;我看源码里面获取的是/proc/parttions里面的信息&#xff0c;但是我没有这个device&#xff0c;是怎么获取出来的&#xff1f; 在这里插入图片描述 A&#xff1a;检查下系统内核版本或者agent程序版本&…

收银系统源码

千呼新零售2.0系统是零售行业连锁店一体化收银系统&#xff0c;包括线下收银线上商城连锁店管理ERP管理商品管理供应商管理会员营销等功能为一体&#xff0c;线上线下数据全部打通。 私有化独立部署/全开源源码&#xff0c;系统开发语言&#xff1a; 核心开发语言: PHP、HTML…

数据结构(初阶1)

文章目录 一、复杂度概念 二、时间复杂度 2.1 大O的渐进表示法 2.2 时间复杂度计算示例 2.2.1. // 计算Func2的时间复杂度&#xff1f; 2.2.2.// 计算Func3的时间复杂度&#xff1f; 2.2.3.// 计算Func4的时间复杂度&#xff1f; 2.2.4.// 计算strchr的时间复杂度&#xff1f; …

区间贪心

目录 1.贪心算法的思想 2.区间贪心算法常用的一些题目类型 1.选择最多不相交区间问题 P2970 [USACO09DEC] Selfish Grazing S 1.思路分析 2.上代码 2.区间选点问题 P1250 种树 1.题目 2.方法一 1.代码解释 3.方法二 3.区间合并问题 P2434 [SDOI2005] 区间 1. 思路…

容器docker

文章目录 前言一、docker1.1 为什么有docker1.2 docker架构1.3 docker 安装1.4 docker中央仓库1.5 docker 基本指令1.6 docker数据卷&#xff0c;挂载例&#xff1a;nginx 数据卷挂载例&#xff1a;mysql 本地持久化 1.7 镜像制作镜像结构dockerfile基础指令容器生成镜像 1.8 d…

JFlash读取和烧录加密stm32程序

JFlash读取和烧录加密stm32程序 安装后JFlash所在的目录&#xff1a;C:\Program Files\SEGGER\JLink 一、烧写加密程序 1、打开C:\Program Files\SEGGER\JLink目录&#xff0c;找到JFlash.exe,双击它&#xff0c;就可以打开该执行程序。见下图&#xff1a; 2、选择“Create …

Vue基础知识:Vue3.3出现的defineOptions,如何使用,解决了什么问题?

1.那么为什么会出现defineOptions? 原因说明&#xff1a; 有<script setup></script>语法糖应用之前&#xff0c;如果要定义 props&#xff0c;emits 可以轻而易举地添加一个与 setup 平级的属性。但是用了<script setup>后&#xff0c;就没法这么干了整个…

地理服务零成本:免费地图API合辑

在全球化和数字化不断推进的今天&#xff0c;地图已成为我们日常生活和工作中不可或缺的工具。无论是规划日常通勤、探索未知地域&#xff0c;还是进行地理数据分析&#xff0c;地图都发挥着至关重要的作用。它们不仅提供了地理信息的直观表示&#xff0c;还支持复杂的空间查询…

【U8+】登录U8时,选择账套登录窗口闪退。

【问题描述】 打开用友U8企业应用平台登录窗口&#xff0c; 输入账号和密码后&#xff0c;选择账套的时候闪退。 【解决方法】 方法一&#xff1a; 重装微软的silverlight&#xff0c;在U8soft\3rdprogram中有安装包。 注&#xff1a;不要自动更新此程序版本。关闭杀毒软件防火…

【线程安全】线程互斥的原理

文章目录 Linux线程互斥线程互斥相关概念互斥量mutex引出线程并发问题引出互斥锁、互斥量 互斥量的接口初始化互斥量销毁互斥量互斥量加锁和解锁使用互斥锁抢票 可重入和线程安全概念&#xff1a;常见线程不安全的情况常见线程安全的情况常见不可重入的情况常见可重入情况可重入…

jvm 05JVM - 对象的创建 ,oop模型,字符串常量池

01.JVM - 对象的创建 1、对象的创建的方式 Java语言中&#xff0c;对象创建的方式有六种&#xff1a; new关键字&#xff1a;最常见的形式、Xxx的静态方法、XxxBuilder、XxxFactory的静态方法。 Class类的newInstance()方法&#xff1a;通过反射的方式创建对象&#xff0c;调…

92. 反转链表 II (Swift 版本)

题目描述 给你单链表的头指针 head 和两个整数 left 和 right &#xff0c;其中 left < right 。请你反转从位置 left 到位置 right 的链表节点&#xff0c;返回 反转后的链表 。 分析 这是一个经典的链表问题&#xff0c;要求反转链表的部分节点。我们可以通过以下步骤实…

Codesys 连接 EtherCAT 总线伺服

本文内容是根据参考视频做的笔记&#xff1a; EtherCAT Master 控制&#xff1a;https://www.bilibili.com/video/BV1L14y1t7ks/EtherCAT Master Motion 控制&#xff1a;https://www.bilibili.com/video/BV16P411j71E/ EtherCAT 总线简单介绍 从站站号&#xff1a;如果使用扫…

【pytorch22】激活函数与GPU加速

激活函数 ReLu还是还是可能出现梯度弥散&#xff0c;因为x<0的时候&#xff0c;梯度还是可能小于0 leaky relu&#xff0c;在x<0的时候&#xff0c;梯度就不会为0&#xff0c;梯度不会不动 Relu函数在x0处是不连续的 一种更加光滑的曲线是SELU&#xff0c;是两个函数的…