news 2026/5/1 7:51:23

归并排序与快速排序

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
归并排序与快速排序

归并排序

介绍

有时候我们需要把两个有序的序列进行合并从而得到有序的大序列,基于这个思想,便引出了归并排序,其思路就是把一个无序序列拆分成多个有序序列(当序列的元素为1时就是有序序列),然后对所有序列进行合并操作,最终得到一整个有序序列。

实现

typedef int ElementType; void Merge(ElementType A[],ElementType TmpArray[],int Lpos,int Rpos,int RightEnd) { int i,LeftEnd,NumElements,TmpPos; LeftEnd=Rpos-1; TmpPos=Lpos; NumElements=RightEnd-Lpos+1; while (Lpos<=LeftEnd && Rpos<=RightEnd) { if (A[Lpos]<=A[Rpos]) { TmpArray[TmpPos++]=A[Lpos++]; }else { TmpArray[TmpPos++]=A[Rpos++]; } } while (Lpos<=LeftEnd) { TmpArray[TmpPos++]=A[Lpos++]; } while (Rpos<=RightEnd) { TmpArray[TmpPos++]=A[Rpos++]; } for (i=0;i<NumElements;i++,RightEnd--) { A[RightEnd]=TmpArray[RightEnd]; } } void Msort(ElementType A[],ElementType TmpArray[],int Left,int Right) { int Center; if (Left<Right) { Center=(Left+Right)/2; Msort(A,TmpArray,Left,Center); Msort(A,TmpArray,Center+1,Right); Merge(A,TmpArray,Left,Center+1,Right); } } void MergeSort(ElementType A[],int N) { ElementType *TmpArray; TmpArray = (ElementType*)malloc(N*sizeof(ElementType)); if (TmpArray!=NULL) { Msort(A,TmpArray,0,N-1); free(TmpArray); }else { printf("Not enough memory for Merge Sort\n"); } }

算法有两个重要的操作,一个是将大序列分成小序列的操作,一个是将两个有序序列合并成有序大序列的操作。

合并操作的逻辑:假设要合并序列A和序列B(都是升序),首先创建一个空间大小为A和B元素数量之和的大小。然后比较A和B最左边的元素,较小的放新序列里,较大的那个和另一个序列的下一个元素比,持续这个过程直到其中一个序列遍历完,那就把另一个序列剩下的元素放到新序列里就可以了。

递归拆分的逻辑:将数组从中间拆成左右两部分,再对左右两部分再以中间拆成两部分,一直这样拆到小序列只要一个元素,然后再对这两个小序列进行合并操作,一步一步合并直至左右两大部分的序列进行最后一次合并成为最终完成排序的总序列。

这里开了一个临时变量TmpArray为了方便后面进行合并操作时频繁新辟用于存两个序列的新数组。

分析

归并操作包括拆分和合并,将数组拆分成许多小数组的的过程一共要进行LogN次,每一层的合并最坏要比较N次,所以总的时间复杂度为O(LogN)。

归并排序是稳定排序,因为每一次的拆分都是相邻序列的拆分,合并时若两元素相等,也是先将左数组的元素放入临时数组,这不改变相同元素的相对位置。

快速排序

介绍

当得到一个无序数组,那我们随机选其中一个元素,然后让剩下的元素中小于它的排在它左边,大于它的元素排在它右边,这样我们就让这个元素归位了,它所在的位置不会在变了。接着再对剩下的元素重复进行这样的操作,这样随着一个个元素的归位,序也就排好了。

实现

typedef int ElementType; #define Cutoff (3) void Swap(ElementType *a,ElementType *b) { ElementType Tmp=*a; *a=*b; *b=Tmp; } void InsertionSort(ElementType A[],int N) { int j,P; ElementType Tmp; for (P=1;P<N;P++) { Tmp=A[P]; for (j=P;j>0&&A[j-1]>Tmp;j--) { A[j]=A[j-1]; } A[j]=Tmp; } } ElementType Median3(ElementType A[],int Left,int Right) { int Center = (Left+Right)/2; if (A[Left]>A[Center]) { Swap(&A[Left],&A[Center]); } if (A[Left]>A[Right]) { Swap(&A[Left],&A[Right]); } if (A[Center]>A[Right]) { Swap(&A[Center],&A[Right]); } Swap(&A[Center],&A[Right-1]); return A[Right-1]; } void Qsort(ElementType A[],int Left,int Right) { int i,j; ElementType Pivot; if (Left+Cutoff<=Right) { Pivot=Median3(A,Left,Right); i=Left; j=Right-1; for (;;) { while (A[++i]<Pivot) {} while (A[--j]>Pivot) {} if (i<j) { Swap(&A[i],&A[j]); }else { break; } } Swap(&A[i],&A[Right-1]); Qsort(A,Left,i-1); Qsort(A,i+1,Right); }else { InsertionSort(A+Left,Right-Left+1); } } void QuickSort(ElementType A[],int N) { Qsort(A,0,N-1); }

这里的排序操作比较灵活,算法步骤如下:

为了提高算法效率防止出现快速排序最坏的情况(避免选到极值做枢轴),先找到待排序数组的左端点,中点和右端点这三个位置,然后对这三个位置进行排序,排好序后将中点的元素和Right-1处的元素进行交换并且将其作为枢轴(枢轴的左边所有元素小于枢轴本身,枢轴的右边所有元素大于枢轴本身)。

快速排序的核心操作(此操作没有新辟一块空间来存储经交换后快速排序的数组,所以空间复杂度较低):使用双指针i,j分别从数组最左端和Right-2两次开始遍历,先i右移直到找比枢轴大的元素后,再j左移直到找到比枢轴小的元素,这样如果顺利的话会出现i位置的元素小于j位置的元素,那就交换这两个元素,然后i,j指针接着移动重复上面的操作,若出现i的元素大于等于j位置的元素,说明i,j指针已经不在正确的左右区间了,即此时i的位置的元素是第一个大于枢轴的元素的位置,那就将枢轴和i位置进行交换,这样枢轴的左侧全是小于它的元素,枢轴右侧都是大于它的元素。

接着再对枢轴左侧的子数组(left到i-1)和右侧数组(i+1到Right)递归地进行快速排序的核心操作,直到某个小数组的长度小于3,数组长度太小用快速排序还是太烦琐了,使用就对数组长度小于3的小序列进行插入排序。这样就逐步完成了整个序列的排序

分析

和归并排序一样,选数组的操作及递归层数为LogN,每一层最坏要遍历N个元素,所以快速排序的时间复杂度是O(NLogN)。

快速排序是不稳定排序,双指交换元素时可能会打乱相同元素的相对位置。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/22 20:27:45

HuggingFace Model Card撰写Qwen-Image-Edit-2509技术细节

HuggingFace Model Card撰写Qwen-Image-Edit-2509技术细节 在电商运营、社交媒体内容更新等高频视觉修改场景中&#xff0c;一个看似简单的需求——“把这张图里的品牌名从‘BrandA’改成‘NewLife’&#xff0c;字体换成金色”——往往意味着设计师要打开Photoshop&#xff0c…

作者头像 李华
网站建设 2026/4/27 18:49:46

利用Docker安装Stable Diffusion 3.5 FP8实现跨平台无缝迁移

利用Docker安装Stable Diffusion 3.5 FP8实现跨平台无缝迁移 在生成式AI快速渗透内容创作领域的今天&#xff0c;一个现实问题始终困扰着开发者和企业&#xff1a;如何让像 Stable Diffusion 这样的高性能模型&#xff0c;在不牺牲图像质量的前提下&#xff0c;真正跑得动、部署…

作者头像 李华
网站建设 2026/4/23 16:02:20

X-TRACK终极指南:打造你的离线地图GPS自行车码表

X-TRACK终极指南&#xff1a;打造你的离线地图GPS自行车码表 【免费下载链接】X-TRACK A GPS bicycle speedometer that supports offline maps and track recording 项目地址: https://gitcode.com/gh_mirrors/xt/X-TRACK 想要一款功能强大、价格亲民的GPS自行车码表吗…

作者头像 李华
网站建设 2026/4/25 22:15:17

网站整站下载工具完整使用教程:从零基础到精通掌握

WebSite-Downloader是一款高效实用的网站整站下载工具&#xff0c;采用Python开发&#xff0c;能够快速将整个网站的内容完整下载到本地&#xff0c;实现离线浏览和静态备份。通过多线程并发下载和智能链接解析技术&#xff0c;该工具支持HTML、CSS、JavaScript以及各类媒体文件…

作者头像 李华
网站建设 2026/4/28 8:04:20

中国金融智能体发展研究与厂商评估报告(2025)|附68页PDF文件下载

本报告基于技术发展周期视角&#xff0c;对中国金融智能体的落地现状和趋势展开了深度洞察&#xff0c;阐述了金融智能体在关键周期阶段的主要表现&#xff0c;期望能够为行业提供一份拥有参考价值的研究内容。以下为报告节选&#xff1a;......文│艾瑞咨询本报告共计&#xf…

作者头像 李华
网站建设 2026/4/28 15:03:45

从评估到改进:RAG知识库质量优化探索

一、前情提要——知识库评估框架搭建1.之前的评估指标我们提到了用retrieved_context、answer、ground_truth三个值&#xff0c;分别两两做余弦相似度&#xff0c;来衡量RAG知识库的建设情况。其中&#xff1a;retrieved_context&#xff1a;即RAG知识库召回的内容&#xff0c;…

作者头像 李华