非递归实现快排排序及归并排序(尾篇)

news2025/1/23 12:58:05

1.快速排序(双指针实现)

2.非递归实现快排

3.递归实现归并排序

4.非递归实现归并排序

5.总代码

1.快速排序(双指针实现)

俩有个指针一前一后的排放着,cur先走并且去找比kye对应值小的数组值,一旦找到后prev就会往前一步然后与cur对应的值进行交换,直至cur走出数组,key对应的值与prev对应的值进行交换,第一躺就完成了,接下来用递归去走分支(排序中篇已经阐述过)去完成其它俩边的排序。

代码实现:

#include<stdio.h>
void swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
void QuickSort2(int* a, int left,int right)
{
	if (left >= right)
		return;
	int keyi = left;
	int prev = left;
	int cur = prev + 1;
	/*while (cur<=right)
	{
		if (a[cur] < a[keyi])
		{
			++prev;
			swap(&a[prev], &a[cur]);
		}
		++cur;	
	}*/代码1
	while (cur <= right)
	{
		if (a[cur] <= a[keyi] && ++prev != cur)
			swap(&a[prev], &a[cur]);
		cur++;
	}//代码2
	swap(&a[keyi], &a[prev]);
	QuickSort2(a, left, prev - 1);
	QuickSort2(a, prev + 1, right);
}
int main()
{
	int a[] = { 1,4,6,7,9,3,2,5,8,8,8,8,8,99 };
	int size = sizeof(a) / sizeof(a[0]);
	QuickSort2(a,0,size-1);
	for (int i = 0; i < size; i++)
	{
		printf("%d ", a[i]);
	}
	return 0;
}

 代码分析:

循环的条件是cur小于等于right边界值才能一直执行,触发交换的条件是cur找到了比key小的值,这里有俩种写法,1是在里面++prev再交换,cur++之所以写在外面是因为不管你触不触发if都要加加,不然会死循环,

因为cur和prev会先重叠然后交互(前提是如果出门就发现了比key小的值) ,但如果prev和cur之间有距离差时就不会出现了,if的触发条件再加一个只有prev和cur不相等时才交换。

代码二则就相对简洁一些,在if判断里就可以实现prev++,但是需要注意的是判断++prev和cur是否相等要在后面,因为&&是前面满足才会看后面,如果写在前面就是不管找没找到都++prev,这样子prev就跑到cur前面去了,是不合理的,还有是pre停下来的位置是上一次交换完的位置,所以比keyi小,交换完后key的左边都是比key小,右边比key大。

2.非递归实现快排

快速排序用递归实现是相对简单的,但也可以使用非递归来实现。

首先要用到栈的知识,递归实现快排是一直开辟栈区来实现的,而开辟的栈区里面的内容有传过去的数组和left和right,但主要是left和right这俩个边界值,因为变的边界值,在每个开辟的栈区数组a都是同一个,但是边界值是不一样的,所以可以使用栈去存边界值left和right这俩个整型,然后用循环去更新边界值,每次从栈中取俩个值left和right,因为是单个单个放进去的,取也是单个单个取,每次获取边界值就跟递归一次效果差不多,但栈为空时就说明已经排好序了。

代码实现:
 

#include<stdio.h>
#include"Stack.h"
void swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
int PartSort2(int* a, int left, int right)
{
	int keyi = left;
	int prev = left;
	int cur = prev + 1;
	while (cur <= right)
	{
		if (a[cur] < a[keyi] && ++prev != cur)
			swap(&a[prev], &a[cur]);
		cur++;
	}
	swap(&a[prev], &a[keyi]);
	return prev;
}
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 keyi = PartSort2(a, begin, end);
		if (keyi + 1 < end)
		{
			STPush(&s,end);
			STPush(&s, keyi + 1);
		}
		if (keyi - 1 > begin)
		{
			STPush(&s, keyi - 1);
			STPush(&s, begin);
		}
	}
}
int main()
{
	int a[] = { 9,8,7,6,5,4,3,3,2,1,55,66,0};
	int size = sizeof(a) / sizeof(a[0]);
	QuickSortNonR(a,0,size-1);
	for (int i = 0; i < size; i++)
	{
		printf("%d ", a[i]);
	}
	return 0;
}

代码分析:

先建立一个栈并初始化,然后把left和right放进去,这里循环的条件是栈是否为空,取出栈顶的俩个值,然后出栈俩次,把取出的值作为参数得到一个keyi值,再把keyi作为参考分出俩个新的区间,然后先判断新的区间是否满足条件,满足则就放入栈里面,这里是以前序去排序(深度优先遍历),队列也可以实现(广度优先遍历),但是在一些情况下是不满足的.

3.递归实现归并排序

归并排序就是把一个数组对半分,一直分到只有一个,然后然后在俩个俩个比,比好就返回去,然后再俩个俩个比,此时俩个数是排好序的,比完后就变成个数为4的有序数组,然后在四个四个比,得到一个个数为8的有序数组,就是把整个分成若干个,在让这些小数组跟别的小数组比较合成一个新的有序数组,一直合成就变成与原来一样大的有序数组,就像魔方直接扣下来重新按颜色装好差不多。

代码实现:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void _MergeSort(int* a, int* tmp, int left, int right)
{
	if (left >= right)
		return;
	int mid = (left + right) / 2;
	_MergeSort(a, tmp, left, mid);
	_MergeSort(a, tmp, mid+1, right);
	int begin1 = left,end1 = mid;//不能在逗号隔开后再加int
	int begin2 = mid + 1,end2 = right;
	int i = left;
	while (begin1 <= end1 && begin2 <= end2)
	{
		if (a[begin1] < a[begin2])
		{
			tmp[i++] = a[begin1++];
		}
		else
		{
			tmp[i++] = a[begin2++];
		}
	}
	while (begin1 <= end1)
	{
		tmp[i++] = a[begin1++];
	}
	while ( begin2 <= end2)
	{
		tmp[i++] = a[begin2++];
	}
	memcpy(a + left, tmp + left, (right - left + 1) * sizeof(int));
}

void MergeSort(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp==NULL)
	{
		perror("malloc fail:");
		return;
	}
	_MergeSort(a, tmp, 0, n - 1);
    free(tmp);
    tmp=NULL;
}
int main()
{
	int a[] = { 9,8,7,6,5,4,3,2,1 };
	int size = sizeof(a) / sizeof(a[0]);
	MergeSort(a, size);
	for (int i = 0; i < size; i++)
	{
		printf("%d ", a[i]);
	}
	return 0;
}

代码分析:

通过递归会把边界值一直缩小,直至长度为1,这是if条件会触发,不能再往下递归开始走后面的程序,此时边界是相等的(left=right),等于是二叉树的兄弟结点进行比大小,谁小谁在前面,俩俩比较,而最小面的俩个while是防止一个数组的值都比较小先放完了,但是还有数据没放完,因为是有序的,所以直接while依次放入,执行完后会返回去跟上一层次的兄弟结点比,最后到第二层时就是原来数组对半分,比完后合并则原来的数组就变成有序的。

4.非递归实现归并排序

思想是通过循环来代替递归,先取gap组,俩俩gap个大小的进行比对后并放到tmp数组中,然后每次循环完后就改变区间到下一个区间去比较,end1-begin1=end2-begin2,但是有时候数组个数不一定能分均匀,有俩个if条件来判断,第一个if是俩个中有一个越界也就是不存在,所以不进行下面的合并,begin1是一定不会越界的,因为begin=i<n,所以只判断其他边界是否越界情况,end1越不越界不重要,要看后面的begin2是否越界,只要begin2越界了那么就不用合并了,第二个if则是判断end2有没有越界,越界了但是begin2没有,还有有效数据存在,所以要修正end2的值变为n-1,不让其越界访问,总的就是,用for循环来实现每俩个gap组能比较,while循环来控制gap的大小,来类比递归的效果。

代码实现:

void MergeSortNonR(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		perror("malloc fail");
		return;
	}
	int gap = 1;
	while (gap < n)
	{
		for (int i = 0; i < n; i += 2*gap)
		{
			int begin1 = i, end1 = i + gap - 1;
			int begin2 = i + gap, end2 = i + 2 * gap - 1;
			int j = i;
			if (begin2 >= n)//end1>n和end1小于n无所谓  只要begin2大于n就不用归并 俩个结果是一样的
			{
				break;
			}
			if (end2 >= n)
			{
				end2 = n - 1;
			}
			while (begin1 <= end1 && begin2 <= end2)
			{
				if (a[begin1] < a[begin2])
				{
					tmp[j++] = a[begin1++];
				}
				else
				{
					tmp[j++] = a[begin2++];
				}
			}
			while (begin1 <= end1)
			{
				tmp[j++] = a[begin1++];
			}
			while (begin2 <= end2)
			{
				tmp[j++] = a[begin2++];
			}
			//memcpy(a +begin1, tmp +begin1, sizeof(int) * (end2 - begin1 + 1));这样是不行的,因为在上面的代码中begin1已经不是原来的值了,
			memcpy(a + i, tmp + i, sizeof(int) * (end2 - i + 1));
		}
		
		gap = 2*gap;
	}
}
int main()
{
	int a[] = { 9,8,7,6,5,4,3,2,1,4343,521,0,5,4,3,3 };
	int size = sizeof(a) / sizeof(a[0]);
	MergeSortNonR(a, size);
	for (int i = 0; i < size; i++)
	{
		printf("%d ", a[i]);
	}
	return 0;
}

5.归并排序的时间复杂度

 因为每次会对半分,直到分成一个,所以能分成logn层,而每个层数访问数据个数都是n,所以总的时间复杂度就是O(N*logN),图片虽然是个三角形,但是每层个数都是n,这里的层数代表是分出的个数,可以理解为上面虽然比下面的短但是是一样重的。

总代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void _MergeSort(int* a, int* tmp, int left, int right)
{
	if (left >= right)
		return;
	int mid = (left + right) / 2;
	_MergeSort(a, tmp, left, mid);
	_MergeSort(a, tmp, mid+1, right);
	int begin1 = left,end1 = mid;//不能在逗号隔开后再加int
	int begin2 = mid + 1,end2 = right;
	int i = left;
	while (begin1 <= end1 && begin2 <= end2)
	{
		if (a[begin1] < a[begin2])
		{
			tmp[i++] = a[begin1++];
		}
		else
		{
			tmp[i++] = a[begin2++];
		}
	}
	while (begin1 <= end1)
	{
		tmp[i++] = a[begin1++];
	}
	while ( begin2 <= end2)
	{
		tmp[i++] = a[begin2++];
	}
	memcpy(a + left, tmp + left, (right - left + 1) * sizeof(int));
}

void MergeSort(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp==NULL)
	{
		perror("malloc fail:");
		return;
	}
	_MergeSort(a, tmp, 0, n - 1);
}
void MergeSortNonR(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		perror("malloc fail");
		return;
	}
	int gap = 1;
	while (gap < n)
	{
		for (int i = 0; i < n; i += 2*gap)
		{
			int begin1 = i, end1 = i + gap - 1;
			int begin2 = i + gap, end2 = i + 2 * gap - 1;
			int j = i;
			if (begin2 >= n)//end1>n和end1小于n无所谓  只要begin2大于n就不用归并 俩个结果是一样的
			{
				break;
			}
			if (end2 >= n)
			{
				end2 = n - 1;
			}
			while (begin1 <= end1 && begin2 <= end2)
			{
				if (a[begin1] < a[begin2])
				{
					tmp[j++] = a[begin1++];
				}
				else
				{
					tmp[j++] = a[begin2++];
				}
			}
			while (begin1 <= end1)
			{
				tmp[j++] = a[begin1++];
			}
			while (begin2 <= end2)
			{
				tmp[j++] = a[begin2++];
			}
			//memcpy(a +begin1, tmp +begin1, sizeof(int) * (end2 - begin1 + 1));这样是不行的,因为在上面的代码中begin1已经不是原来的值了,
			memcpy(a + i, tmp + i, sizeof(int) * (end2 - i + 1));
		}
		
		gap = 2*gap;
	}
}
int main()
{
	int a[] = { 9,8,7,6,5,4,3,2,1,4343,521,0,5,4,3,3 };
	int size = sizeof(a) / sizeof(a[0]);
	MergeSortNonR(a, size);
	for (int i = 0; i < size; i++)
	{
		printf("%d ", a[i]);
	}
	return 0;
}

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

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

相关文章

我国液碱产量逐渐增长 行业集中度有望不断提升

我国液碱产量逐渐增长 行业集中度有望不断提升 液碱是由氢氧化钠&#xff08;NaOH&#xff09;、氢氧化钾&#xff08;KOH&#xff09;等化合物以及水组成的一种碱性化合物。液碱的相对分子质量为40.00&#xff0c;密度为1.318g/cm&#xff0c;在常温常压下多表现为一种无色、无…

萨科微的“Slkor”和金航标“Kinghelm”

宋仕强说&#xff0c;我国的科学研究和先进技术&#xff0c;与先进国家相比还有差距&#xff0c;这一点还体现在社会生产效率和人均GDP上面。我们只有抓住科技进步的风口如人工智能&#xff08;AI&#xff09;&#xff0c;再加上公司内部的研发和管理等环节的微创新&#xff0c…

ai怎么导出jpg?让我告诉你答案【详】

在设计和创意工作中&#xff0c;Adobe Illustrator&#xff08;AI&#xff09;是一款不可或缺的工具。然而&#xff0c;当我们将设计作品导出为JPG格式时&#xff0c;可能会遇到一些问题。ai怎么导出jpg&#xff1f;如何确保导出的JPG图片保持高质量&#xff1f;接下来&#xf…

原子阿波罗STM32F429程序的控制器改为STM32F407

以前&#xff0c;学习原子的探索者开发板&#xff0c;有STM32F407ZGT6开发板&#xff0c;现在想学习阿波罗开发板&#xff0c;但手头没有F429开发板&#xff0c;于是&#xff0c;想把STM32F429芯片替换为STM32F407芯片&#xff0c;本以为没有什么难度&#xff0c;但是替换后发下…

Mysql:通过一张表里的父子级,递归查询并且分组分级

表&#xff1a;gc_jzst_single_base 需求&#xff1a;要求返回这张表里符合条件的数据&#xff0c;且有父子级关系的&#xff0c;展示为同一组且分级&#xff0c;给后续业务调用 代码 WITH RECURSIVE t1 AS (SELECTsingle_id,old_build_single_id,single_name,bulid_code,1 A…

ArcGIS中几个好用的空间分析工具

ArcGIS是一款经典的GIS应用&#xff0c;其空间分析能力很强&#xff0c;有着丰富的空间分析工具。今天&#xff0c;我们一起来了解几个好用的空间分析工具的功用及操作。 注&#xff1a;演示版本为ArcMap10.4.1 1.方向分布&#xff08;标准差椭圆&#xff09; 路径&#xff…

三.网络编程套接字_TCP

一.序言 在上一章中&#xff0c;我们已经实现了用udp来实现网络编程&#xff0c;这一节我们用tcp来实现网络编程&#xff0c;通过对比两者编写过程的区别&#xff0c;来加深对udp,tcp的理解&#xff01; (两者其实差别不大&#xff01;有了udp的基础&#xff0c;学习起来tcp会…

MongoDB~存储引擎了解

存储引擎 存储引擎是一个数据库的核心&#xff0c;主要负责内存、磁盘里数据的管理和维护。 MongoBD的优势&#xff0c;在于其数据模型定义的灵活性、以及可拓展性。但不要忽略&#xff0c;其存储引擎也是插件式的存在&#xff0c;支持不同类型的存储引擎&#xff0c;使用不同…

C++学习笔记(22)——多态

目录 [TOC](目录) 比喻与理解1. 多态的概念2. 多态的定义及实现2.1多态的构成条件2.2 虚函数2.3虚函数的重写2.3.1 虚函数重写的两个例外&#xff1a;1. 协变(基类与派生类虚函数返回值类型不同)2. 析构函数的重写(基类与派生类析构函数的名字不同) 2.4 C11 override 和 final2…

【Git教程】(二十)外包长历史记录 — 概述及使用要求,执行过程及其实现,替代解决方案 ~

Git教程 外包长历史记录 1️⃣ 概述2️⃣ 使用要求3️⃣ 执行过程及其实现3.1 外包项目历史3.2 链接到当前活动版本库 Git 版本库会随着时间积累越来越大&#xff0c;会影响它的内存管理效率。通常在版本库中只有源 代码文件情况下&#xff0c;这点效率影响可以忽略不计。在现…

新火种AI|倒反天罡!美国名校斯坦福AI团队抄袭中国大模型

作者&#xff1a;一号 编辑&#xff1a;美美 中国大模型被抄袭&#xff0c;怎么不算是某种层面上的国际认可呢&#xff1f; 5月29日&#xff0c;斯坦福大学的一个AI研究团队发布了一个名为「Llama3V」的模型&#xff0c;号称只要 500 美元就能训练出一个 SOTA 多模态模型&am…

精酿啤酒新风尚,FENDI CLUB盛宴启幕,品质生活触手可及

随着现代人对生活品质的追求日益提升&#xff0c;精酿啤酒作为一种新兴的生活方式&#xff0c;正逐渐引领潮流。在这个背景下&#xff0c;FENDI CLUB的盛宴盛大开启&#xff0c;为广大消费者带来了一场别具一格的品质生活体验。 一、精酿啤酒的崛起 精酿啤酒以其独特的口感、…

手机卡不缴纳违约金就不给注销?实用的处理方法大全!

我手机卡都不用了&#xff0c;为何不能注销&#xff1f;而且要缴纳违约金&#xff1f;简直是无法无天&#xff01;小编在回复粉丝问题的时候&#xff0c;经常遇到这种情况&#xff0c;现在就给大家系统整理下如何处理这个问题&#xff0c;希望能帮助到大家&#xff01; 在处理不…

段子照进现实!裁员裁到大动脉,理想被传召回被裁员工…?

你一定看过类似这样的段子吧&#xff01;「公司高层换血&#xff0c;各个部门丢裁了个遍&#xff0c;终于要对财务下手&#xff0c;财务总监走之前&#xff0c;让公司补了六百万税」 还有类似这样的&#xff1a;「某公司裁员把一个销售主管裁了&#xff0c;那销售上午刚谈了个1…

vue动态加载组件import引入组件找不到组件(Error: Cannot find module)

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 http://218.75.87.38:9666/ 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a; h…

【杂谈】AIGC之Stable Diffusion:AI绘画的魔法

Stable Diffusion&#xff1a;AI绘画的魔法 引言 在AI的世界里&#xff0c;Stable Diffusion就像一位魔法师&#xff0c;它能够将我们脑海中的幻想&#xff0c;用画笔一一描绘出来。今天&#xff0c;就让我们一探这位魔法师的奥秘&#xff0c;看看它是如何从无到有&#xff0…

Java驱动的工程项目管理系统:实现高效协作与精准管理

在工程行业的现代管理实践中&#xff0c;有效地协同工作和信息共享对于提高工作效率和降低成本至关重要。本文将深入探讨一款基于Java技术的工程项目管理系统&#xff0c;该系统采用前后端分离的架构&#xff0c;功能全面&#xff0c;旨在满足不同角色的需求&#xff0c;从项目…

【一小时学会Charles抓包详细教程】Charles 弱网测试与实战篇 (10)

&#x1f680; 个人主页 极客小俊 ✍&#x1f3fb; 作者简介&#xff1a;程序猿、设计师、技术分享 &#x1f40b; 希望大家多多支持, 我们一起学习和进步&#xff01; &#x1f3c5; 欢迎评论 ❤️点赞&#x1f4ac;评论 &#x1f4c2;收藏 &#x1f4c2;加关注 Charles 弱网测…

Message forwarding mechanism (消息转发机制)

iOS的消息转发机制 iOS的消息转发机制是在消息发送给对象时&#xff0c;找不到对应的实例方法的情况下启动的。消息转发允许对象在运行时处理无法识别的消息&#xff0c;提供了一种动态的、灵活的消息处理方式。 消息转发机制主要分为三个阶段&#xff1a; 动态方法解析快速…

基于振弦采集仪的土木工程安全监测技术研究

基于振弦采集仪的土木工程安全监测技术研究 随着土木工程的发展&#xff0c;安全监测成为了非常重要的一部分。土木工程的安全监测旨在及早发现结构的变形、位移、振动等异常情况&#xff0c;以便及时采取措施进行修复或加固&#xff0c;从而保障工程的安全运行。振弦采集仪作…