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

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;	}*/代码1while (cur <= right){if (a[cur] <= a[keyi] && ++prev != cur)swap(&a[prev], &a[cur]);cur++;}//代码2swap(&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;//不能在逗号隔开后再加intint 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;//不能在逗号隔开后再加intint 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.mzph.cn/bicheng/22833.shtml

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

相关文章

x86国产化麒麟系统上安装docker及问题解决

以前感觉安装docker没有问题&#xff0c;所以没有记录怎么安装的&#xff0c;最近在国产化系统上安装docker总是失败&#xff0c;经过仔细研究完全解决了该问题&#xff0c;特此记录。 参考链接&#xff1a; 在 OpenKylin 上安装 Docker 按照上面的链接可以知道整个docker安装…

EMC整改学习-笔记

EMC整改学习-笔记 来自赛盛技术的笔记 如果我拿到一个产品超标的一个频谱图的话&#xff0c;首先我们可以对比做一个分析。来确定你干扰源的一个分类和定义是哪些。是你这个产品类型&#xff0c;什么样的电路对应什么样的一个。从我们的一个大量的一个测试数据的经验来看&…

超全面,编程语言汇总,看看哪些语言适合GIS开发?

最近总有很多人关心GIS开发语言的问题&#xff0c;这个确实很重要&#xff0c;毕竟学习一门编程语言需要花费不少时间和精力&#xff0c;找不到合适GIS的编程语言意味着浪费时间。 首先我们来简单看一下常见的编程语言有哪些&#xff0c;后续再给大家介绍哪些语言适合GIS开发&a…

如何获知SylixOS某API调用方法?

问题背景 SylixOS从2006年韩总在大学时开始开发&#xff0c;到今年2024年已走过18个年头&#xff0c;这18年一直在不断迭代更新&#xff0c;也经过无数实际项目的考验&#xff0c;SylixOS无论从功能还是性能上看&#xff0c;都毫无疑问是世界一流的大型实时操作系统。 但实时…

AI大模型还没有到卷长文的时候

AI风口上&#xff0c;国内大模型技术突飞猛进&#xff0c;很多人都沉浸在用AI来辅助办公&#xff0c;辅助学习等等工具化应用落地&#xff0c;但也有趁着风口想大赚一笔&#xff0c;为了估值什么都敢说的。 前几天&#xff0c;Kimi对外宣称自己的技术狂飙到能读200万字甚至100…

标准发布 | 高氨氮废水厌氧氨氧化处理应用技术规范

高氨氮废水厌氧氨氧化处理应用技术规范 Technical specification for anammox treatment of high strength ammonia nitrogen wastewater 一、编制单位 本文件由中华环保联合会水环境治理专业委员会提出。 本文件由中华环保联合会归口。 本文件主编单位&#xff1a;北京城市…

SSRF思路及步骤

什么是SSRF&#xff1f; SERVER SIDE REQUEST FORGERY的简写 因为服务器本身提供了资源获取相关的服务&#xff0c;在资源地址能够被用户控制时&#xff0c;将可能导致攻击者利用服务器身份获取预期外的资源的后果 危害&#xff1f; 条件满足的情况下&#xff1a;突破网络防…

佛教祭拜小程序-寺庙小程序-纪念馆小程序

大家好&#xff0c;我是程序员小孟。 现在有很多的产品或者工具都开始信息话了&#xff0c;寺庙或者佛教也需要小程序吗&#xff1f; 当然了&#xff01; 前面我们还开发了很多寺庙相关的小程序&#xff0c;都有相关的介绍&#xff1a; 1,优质的寺庙小程序-H5寺庙网页 今天…

机器学习多场景实战

机器学习已不再局限于理论探讨&#xff0c;而是广泛渗透到我们生活的方方面面&#xff0c;成为解决复杂问题、优化决策过程的强有力工具。从智能推荐系统个性化推送你可能喜爱的电影和商品&#xff0c;到金融风控领域精准识别欺诈交易&#xff1b;每一个应用场景都是机器学习技…

(学习笔记)数仓建模

数仓建模 OLAP数仓分层数据模型数据模型建设方法模型建设具体流程模型数据域事实表设计事实表拉链表 数据模型规范表命名(采用阿里one-data设计)字段命名(采用阿里one-data设计)数据模型标注规范 数据模型发展周期 OLAP OLTP&#xff1a;概念全称OnLine Transaction Processin…

实验七、创建小型实验拓扑《计算机网络》

早检到底是谁发明出来的。 一、实验目的 完成本实验后&#xff0c;您将能够&#xff1a; • 设计逻辑网络。 • 配置物理实验拓扑。 • 配置 LAN 逻辑拓扑。 • 验证 LAN 连通性。 二、实验任务 在本实验中&#xff0c;将要求您连接网络设备并配置主机实现基本的网络…

【YOLO系列】YOLOv10论文超详细解读(翻译 +学习笔记)

前言 研究AI的同学们面对的一个普遍痛点是&#xff0c;刚开始深入研究一项新技术&#xff0c;没等明白透彻&#xff0c;就又迎来了新的更新版本——就像我还在忙着逐行分析2月份发布的YOLOv9代码&#xff0c;5月底清华的大佬们就推出了全新的v10。。。 在繁忙之余&#xff0…

第101天:权限提升-Win 本地用户进程注入令牌窃取ATSCPS 服务命令

目录 思维导图 案例一&#xff1a; WIN-本地用户-AT&SC&PS 命令 AT命令 sc PS 案例二&#xff1a;WIN-本地用户-进程迁移注入获取 msf 案例三&#xff1a;WIN-本地&Web-令牌窃取&土豆溢出 令牌窃取 土豆溢出 案例四&#xff1a; uac原理与绕过 思维…

【Qt】Frame和Widget的区别

1. 这两个伙计有啥区别&#xff1f; 2. 区别 2.1 Frame继承自Widget&#xff0c;多了一些专有的功能 Frame Widget 2.2 Frame可以设置边框

C51学习归纳4 --- 矩阵键盘

一、开发板原理图 我们可以看到这个键盘是4*4的&#xff0c;行可以由4个数据接口接收&#xff08;P1_4~7&#xff09;&#xff0c;列可以由4个数据接口接收&#xff08;P1_0~3)。 所以我们可让行作为扫描方向&#xff0c;或者列作为扫描方向&#xff0c;进行按键扫描。如何扫描…

VS2017配置OpenCV4.5.1

VS2017配置OpenCV 一、下载OpenCV二、配置OpenCV的电脑环境变量三、配置visual Studio添加路径复制文件到C盘 四、如何使用注意运行时选择Debug x64 五、报错&#xff1a;VSOpencv出现&#xff1a;xxx处有未经处理的异常: Microsoft C 异常: cv::Exception&#xff0c;位于内存…

@vue-office/excel遇到的问题 error in ./src/components/gem-histogram.base.vue?vuetype=templateid=691572

下载后一直抱这个错误 10:39:39 - Building for production... 10:40:36 ERROR Failed to compile with 41 errors2:40:31 AM 10:40:36 10:40:36 error in ./src/components/gem-histogram.base.vue?vue&typetemplate&id691572bb&scopedtrue 10:40:36 …

GaussDB的数种形态

GaussDB作为一种新兴的关系型数据库产品&#xff0c;似乎有点让人摸不着头脑。有朋友问我GaussDB单机版怎么样&#xff0c;有人说GaussDB是分布式数据库&#xff0c;还有人说它是云数据库&#xff0c;还有人会把GaussDB和华为的数据仓库GaussDB DWS混为一谈。确实&#xff0c;公…

算法学习笔记——时间复杂度和空间复杂度

时间复杂度和空间复杂度 常数操作&#xff1a; 固定时间的操作&#xff0c;执行时间和数据量无关 位运算 > 算数运算 > 寻址 > 哈希运算&#xff0c;都是常数操作&#xff0c;哈希运算操作时间最慢 链表的get(i)方法不是常数操作&#xff0c;因为链表不是连续的存储…

颠沛流离学二叉树(完结撒花篇)

本篇会加入个人的所谓鱼式疯言 ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. &#x1f92d;&#x1f92d;&#x1f92d;可能说的不是那么严谨.但小编初心是能让更多人…