张仰彪第二排序法_C++之排序

a88c48c554de5cee85fd81b6be0b4e6e.gif

常见的各种排序

6e245eee81bdb18f0c5b999df30e006f.png

算法复杂度

6bcde0718ddbae8af90b3242d7d9fcbb.png

快速排序

1.原理

假设我们现在对“6  1  2 7  9  3  4  5 10  8”这个10个数进行排序。首先在这个序列中随便找一个数作为基准数。为了方便,就让第一个数6作为基准数吧。接下来,需要将这个序列中所有比基准数大的数放在6的右边,比基准数小的数放在6的左边,类似下面这种排列:

3  1  2 5  4  6  9 7  10  8

在初始状态下,数字6在序列的第1位。我们的目标是将6挪到序列中间的某个位置,假设这个位置是k。现在就需要寻找这个k,并且以第k位为分界点,左边的数都小于等于6,右边的数都大于等于6,递归对左右两个区间进行同样排序即可。想一想,你有办法可以做到这点吗?这就是快速排序所解决的问题。

快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。它采用了一种分治的策略,通常称其为分治法(Divide-and-ConquerMethod)。它的平均时间复杂度为O(nlogn),最坏时间复杂度为O(n^2).

1273515648d4c37d5639901794a9c787.png

从图中我们可以看到:

left指针,right指针,base参照数。

其实思想是蛮简单的,就是通过第一遍的遍历(让left和right指针重合)来找到数组的切割点。

第一步:首先我们从数组的left位置取出该数(20)作为基准(base)参照物。(如果是选取随机的,则找到随机的哨兵之后,将它与第一个元素交换,开始普通的快排)

第二步:从数组的right位置向前找,一直找到比(base)小的数,如果找到,将此数赋给left位置(也就是将10赋给20),此时数组为:10,40,50,10,60, left和right指针分别为前后的10。

第三步:从数组的left位置向后找,一直找到比(base)大的数,如果找到,将此数赋给right的位置(也就是40赋给10),此时数组为:10,40,50,40,60, left和right指针分别为前后的40。

第四步:重复“第二,第三“步骤,直到left和right指针重合,最后将(base)放到40的位置, 此时数组值为:10,20,50,40,60,至此完成一次排序。

第五步:此时20已经潜入到数组的内部,20的左侧一组数都比20小,20的右侧作为一组数都比20大, 以20为切入点对左右两边数按照"第一,第二,第三,第四"步骤进行,最终快排大功告成。

2.算法实现

//快速排序,随机选取哨兵放前面void QuickSort(int* h, int left, int right){    if(h==NULL) return;    if(left>=right) return;    //防止有序队列导致快速排序效率降低    srand((unsigned)time(NULL));    int len=right-left;    int kindex=rand()%(len+1)+left;    Swap(h[left],h[kindex]);    int key=h[left],i=left,j=right;    while(i    {        while(h[j]>=key && i        if(i        while(h[i]        if(i    }    h[i]=key;    //QuickSort(&h[left],0,i-1);    //QuickSort(&h[j+1],0,right-j-1);    QuickSort(h,left,i-1);    QuickSort(h,j+1,right);}

冒泡排序

1.原理

冒泡排序在扫描过程中两两比较相邻记录,如果反序则交换,最终,最大记录就被“沉到”了序列的最后一个位置,第二遍扫描将第二大记录“沉到”了倒数第二个位置,重复上述操作,直到n-1 遍扫描后,整个序列就排好序了。

bcfdf3da2e1d5e932ccec0bee6b8aa0a.png

2.算法实现

//冒泡排序void BubbleSort(int* h, size_t len){    if(h==NULL) return;    if(len<=1) return;    //i是次数,j是具体下标    for(int i=0;i        for(int j=0;j            if(h[j]>h[j+1])                Swap(h[j],h[j+1]);    return;}

选择排序

1.原理

选择排序也是一种简单直观的排序算法。它的工作原理很容易理解:初始时在序列中找到最小(大)元素,放到序列的起始位置作为已排序序列;然后,再从剩余未排序元素中继续寻找最小(大)元素,放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

注意选择排序与冒泡排序的区别:冒泡排序通过依次交换相邻两个顺序不合法的元素位置,从而将当前最小(大)元素放到合适的位置;而选择排序每遍历一次都记住了当前最小(大)元素的位置,最后仅需一次交换操作即可将其放到合适的位置。

2.算法实现

//选择排序void SelectionSort(int* h, size_t len){    if(h==NULL) return;    if(len<=1) return;    int minindex,i,j;    //i是次数,也即排好的个数;j是继续排    for(i=0;i    {        minindex=i;        for(j=i+1;j        {            if(h[j]        }        Swap(h[i],h[minindex]);    }    return;}

插入排序

1.原理

直接插入排序(straight insertion sort),有时也简称为插入排序(insertion sort),是减治法的一种典型应用。其基本思想如下:

  • 对于一个数组A[0,n]的排序问题,假设认为数组在A[0,n-1]排序的问题已经解决了。

  • 考虑A[n]的值,从右向左扫描有序数组A[0,n-1],直到第一个小于等于A[n]的元素,将A[n]插在这个元素的后面。

  很显然,基于增量法的思想在解决这个问题上拥有更高的效率。

直接插入排序对于最坏情况(严格递减的数组),需要比较和移位的次数为n(n-1)/2;对于最好的情况(严格递增的数组),需要比较的次数是n-1,需要移位的次数是0。当然,对于最好和最坏的研究其实没有太大的意义,因为实际情况下,一般不会出现如此极端的情况。然而,直接插入排序对于基本有序的数组,会体现出良好的性能,这一特性,也给了它进一步优化的可能性。(希尔排序)。直接插入排序的时间复杂度是O(n^2),空间复杂度是O(1),同时也是稳定排序。

下面用一个具体的场景,直观地体会一下直接插入排序的过程:

场景:

现有一个无序数组,共7个数:89 45 54 29 90 34 68。

使用直接插入排序法,对这个数组进行升序排序。

89 45 54 29 90 34 68

45 89 54 29 90 34 68

45 54 89 29 90 34 68

29 45 54 89 90 34 68

29 45 54 89 90 34 68

29 34 45 54 89 90 68

29 34 45 54 68 89 90

2.算法实现

//插入排序void InsertSort(int* h, size_t len){    if(h==NULL) return;    if(len<=1) return;    int i,j;    //i是次数,也即排好的个数;j是继续排    for(i=1;i        for(j=i;j>0;--j)            if(h[j]-1]) Swap(h[j],h[j            else break;    return;}

归并排序

1.原理

归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。

分而治之

260fdfc28cafec0252db3e28cc485a43.png

3863a6aa4dc291ac954d83ea4f9c4644.png

0c2f8bfc886390acc70e47ad052655f8.png

2.算法实现

//归并排序void  MergeArray(int* arr, size_t left, size_t mid, size_t right, int* temp){    if(arr==NULL) return;    size_t i=left,j=mid+1,k=0;    while(i<=mid && j<=right)    {        if(arr[i]<=arr[j])        {            temp[k++]=arr[i++];            continue;        }        temp[k++]=arr[j++];    }    while(i<=mid)        temp[k++]=arr[i++];    while(j<=right)        temp[k++]=arr[j++];    memcpy(&arr[left],temp,k*sizeof(int));    return;}void MMergeSort(int* arr, size_t left, size_t right, int* temp){    if(left    {        size_t mid=(left+right)/2;        MMergeSort(arr, left, mid, temp);        MMergeSort(arr, mid+1,right, temp);        MergeArray(arr,left, mid, right, temp);    }}void MergeSort(int* h, size_t len){    if(h==NULL) return;    if(len<=1) return;    int* temp=(int*)calloc(len,sizeof(int));    MMergeSort(h, 0, len-1, temp);    memcpy(h,temp,sizeof(int)*len);    free(temp);    return;}

希尔排序

1.原理

希尔排序是希尔(Donald Shell)于1959年提出的一种排序算法。希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序,同时该算法是冲破O(n2)的第一批算法之一。本文会以图解的方式详细介绍希尔排序的基本思想及其代码实现。

基本思想

  希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。

  简单插入排序很循规蹈矩,不管数组分布是怎么样的,依然一步一步的对元素进行比较,移动,插入,比如[5,4,3,2,1,0]这种倒序序列,数组末端的0要回到首位置很是费劲,比较和移动元素均需n-1次。而希尔排序在数组中采用跳跃式分组的策略,通过某个增量将数组元素划分为若干组,然后分组进行插入排序,随后逐步缩小增量,继续按组进行插入排序操作,直至增量为1。希尔排序通过这种策略使得整个数组在初始阶段达到从宏观上看基本有序,小的基本在前,大的基本在后。然后缩小增量,到增量为1时,其实多数情况下只需微调即可,不会涉及过多的数据移动。

  我们来看下希尔排序的基本步骤,在此我们选择增量gap=length/2,缩小增量继续以gap = gap/2的方式,这种增量选择我们可以用一个序列来表示,{n/2,(n/2)/2...1},称为增量序列。希尔排序的增量序列的选择与证明是个数学难题,我们选择的这个增量序列是比较常用的,也是希尔建议的增量,称为希尔增量,但其实这个增量序列不是最优的。此处我们做示例使用希尔增量。

11d505b4ec69655256b3d826260ba6bf.png

2.算法实现

//希尔排序void ShellSort(int* h, size_t len){    if(h==NULL) return;    if(len<=1) return;    for(int div=len/2;div>=1;div/=2)        for(int k=0;k
for(int i=div+k;i for(int j=i;j>k;j-=div) if(h[j] else break; return;}

堆排序

1.原理

堆排序实际上是利用堆的性质来进行排序的,要知道堆排序的原理我们首先一定要知道什么是堆。 堆的定义: 堆实际上是一棵完全二叉树。 堆满足两个性质: 1、堆的每一个父节点都大于(或小于)其子节点; 2、堆的每个左子树和右子树也是一个堆。 堆的分类: 堆分为两类: 1、最大堆(大顶堆):堆的每个父节点都大于其孩子节点; 2、最小堆(小顶堆):堆的每个父节点都小于其孩子节点; 

12f012f8714c873e56a19b756b11fd04.png

堆的存储: 一般都用数组来表示堆,i结点的父结点下标就为(i – 1) / 2。它的左右子结点下标分别为2 * i + 1和2 * i + 2。如下图所示: 

4eea0d47502eac4126c09ce5b7341f82.png

堆排序: 由上面的介绍我们可以看出堆的第一个元素要么是最大值(大顶堆),要么是最小值(小顶堆),这样在排序的时候(假设共n个节点),直接将第一个元素和最后一个元素进行交换,然后从第一个元素开始进行向下调整至第n-1个元素。所以,如果需要升序,就建一个大堆,需要降序,就建一个小堆。 堆排序的步骤分为三步: 1、建堆(升序建大堆,降序建小堆); 2、交换数据; 3、向下调整。 假设我们现在要对数组arr[]={8,5,0,3,7,1,2}进行排序(降序): 首先要先建小堆: 

2208e79aea39fe18427596594b2b4340.png

堆建好了下来就要开始排序了: 

d7f1151ba49e26cf184263600edfff63.png

现在这个数组就已经是有序的了。

2.算法实现

//堆排序/*大顶堆sort之后,数组为从小到大排序*///====调整=====void AdjustHeap(int* h, int node, int len)  //----node为需要调整的结点编号,从0开始编号;len为堆长度{    int index=node;    int child=2*index+1; //左孩子,第一个节点编号为0    while(child<len)    {        //右子树        if(child+1<len && h[child]1])        {            child++;        }        if(h[index]>=h[child]) break;        Swap(h[index],h[child]);        index=child;        child=2*index+1;    }}//====建堆=====void MakeHeap(int* h, int len){    for(int i=len/2;i>=0;--i)    {        AdjustHeap(h, i, len);    }}//====排序=====void HeapSort(int* h, int len){    MakeHeap(h, len);    for(int i=len-1;i>=0;--i)    {        Swap(h[i],h[0]);        AdjustHeap(h, 0, i);    }}

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

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

相关文章

mysql1440秒未活动_phpMyAdmin登陆超时1440秒未活动请重新登录

本文章总结了关于phpMyAdmin登陆超时1440秒未活动请重新登录解决方法&#xff0c;有需要的朋友可参考本文章。问题现象&#xff1a;现象一&#xff1a;phpmyadmin在使用过程中经常出现“登陆超时(1440秒未活动)&#xff0c;请重新登录”&#xff1b;现象二&#xff1a;phpmyadm…

python3读取jpg_python3读取图像并可视化的方法(PIL/Pillow、opencv/cv2)

原图&#xff1a;使用TensorFlow做图像处理的时候&#xff0c;会对图像进行一些可视化的操作。下面&#xff0c;就来列举一些我知道的图像读取并可视化的方法。 1. Pillow模块 1.1 Pillow模块的前生 Pillow就是python2中的 PIL 模块。PIL模块&#xff08;Python Imaging Librar…

mysql一对多增删改查_SpringBoot+MySql+ElementUI实现一对多的数据库的设计以及增删改查的实现...

场景业务中经常会用到一对多的数据库的设计与数据的增删改查的实现。比如要实现一个对手机应用配置允许访问的权限的业务。app与权限就是一对多的关系。即一个app可以拥有多个权限。注&#xff1a;实现首先设计数据库。要有一个app表、一个权限表、一个app与权限关联表。首先设…

python设置时间到后结束程序_Python设置程序等待时间

写代码时&#xff0c;特别是涉及到其他外部可执行文件调用时&#xff0c;通常会出现调用程序还未生成结果&#xff0c;后面的程序就自动执行的情况。而通常情况下&#xff0c;前一步调用的生成结果是下一步程序的输入文件&#xff0c;因此出现找不到该文件或打不开该文件的情况…

c++心形代码_情人节,用代码比个心

今日份的情人节&#xff0c;在家闲出p的你&#xff0c;是不是比往日更加寂寞&#xff1f;这无情的雨&#xff0c;这冰冷的雪&#xff0c;这朴实无华且枯燥的生活&#xff0c;你是否想做点什么&#xff1f;没有朱一旦的劳力士&#xff0c;也没有朱一龙的神仙颜值&#xff0c;那么…

上下相机贴合对位计算公式_展商速递 | 汇驰新材热可塑性光学透明膜优化升级全贴合工艺...

2020/11/19-21广州汇驰新材料有限公司(东莞欧伏电子)展位号&#xff1a;1R10展会时间&#xff1a;11月19-21日地点&#xff1a;深圳会展中心(福田区老展馆)欢迎相关企业莅临商谈&#xff01;关于汇驰新材广州汇驰新材料有限公司(东莞欧伏电子)(展位号&#xff1a;1R10)主要从事…

datagrip替换字_DataGrip使用进阶-导航及搜索(一)

1、关键字导航&#xff1a;当在datagrip的文本编辑区域编写sql时&#xff0c;按住键盘Ctrl键不放&#xff0c;同时鼠标移动到sql关键字上&#xff0c;比如表名、字段名称、或者是函数名上&#xff0c;鼠标会变成手型&#xff0c;关键字会变蓝&#xff0c;并加了下划线&#xff…

js map获取_感知 Node.js 异步I/O 的魅力!

JS 在浏览器的网页中执行&#xff0c;浏览器给 JS 提供的能力是操作文字、图片&#xff0c;或实现一些简单效果。术语叫 DOM 操作。JS 在 Node.js 环境中执行, Node 给 JS 提供了诸如 文件操作, 网络操作 等功能模块。基于这些模块&#xff0c;JS 一下就牛气冲天了。在 Node.j…

k8s pod restartcount 改0_通过实例快速掌握k8s(Kubernetes)核心概念

点击上方蓝色“Go语言中文网”关注我们&#xff0c;设个星标&#xff0c;每天学习 Go 语言本文作者&#xff1a;倚天码农&#xff0c;原创授权发布原文链接&#xff1a;https://segmentfault.com/a/1190000020595811容器技术是微服务技术的核心技术之一&#xff0c;并随着微服务…

div垂直居中的方法_【CSS】8种常见的垂直水平居中方法

1.比较传统的方式 absolutemargin负值偏移特点&#xff1a;父容器要设置宽高&#xff0c;需要知道子容器宽高&#xff0c;偏移量是子容器宽高的一半且是负值&#xff0c;兼容性好/* absolutemargin负值偏移布局 */.layout.absolute {position: relative;}.layout.absolute art…

websocket 导致大量apache进程_Swoole 服务端主动向websocket推送消息

在之前的博文中&#xff0c;我们已经学完了如果使用swoole搭建websocket长连接&#xff0c;也学会了swoole的多进程数据共享操作。但在一个完整的websocket长连接日常操作链中&#xff0c;服务端往往会主动给在线的用户单独推送消息&#xff0c;会群发一些消息。在Swoole-webso…

python因子分析法_python——因子分析

因子分析用Python做的一个典型例子 一、实验目的 采用合适的数据分析方法对下面的题进行解答二、实验要求 采用因子分析方法&#xff0c;根据48位应聘者的15项指标得分&#xff0c;选出6名最优秀的应聘者。 三、代码 importpandas aspd importnumpy asnp importmath asmath imp…

polycom安卓手机客户端_三款免费「游戏串流」APP,在手机/电视上玩PC游戏

以前想把电脑游戏输出到电视机上玩&#xff0c;得用HDMI线输出&#xff0c;如果电脑主机和电视机离太远&#xff0c;HDMI线不够长&#xff0c;还得抱电脑主机到电视机旁边&#xff0c;非常不方便。随着技术的发展&#xff0c;现在已经有「串流」功能&#xff0c;只要电视机和电…

python获取返回值_python如何获取函数的返回值

函数需要先定义后调用&#xff0c;函数体中 return 语句的结果就是返回值。如果一个函数没有 reutrn 语句&#xff0c;其实它有一个隐含的 return 语句&#xff0c;返回值是 None&#xff0c;类型也是 NoneType。return 语句的作用&#xff1a;结束函数调用、返回值 指定返回值…

java模拟器百度_Java模拟实现百度文档在线浏览

这个思路是我参考网上而来&#xff0c;代码是我实现。采用Apache下面的OpenOffice将资源文件转化为pdf文件&#xff0c;然后将pdf文件转化为swf文件&#xff0c;用FlexPaper浏览。ok&#xff0c;A、下载OpenOffice (转换资源文件)B、下载JodConverter(调用OpenOffice)C、下载Sw…

body click js 委托_JS 事件循环

进程 线程CPU 分配资源的最小单位是进程&#xff0c;同一个时间内单个 CPU 只能运行一个进程&#xff0c;单个 CPU 一次只能运行一个任务CPU 调度的最小单位是线程&#xff0c;一个进程里面包含多个线程。可以看看阮老师的这篇文章&#xff0c;进程与线程的一个简单解释浏览器的…

django jsonresponse_利用 Django 动态展示 Pyecharts 图表数据的几种方法

本文将介绍如何在 web 框架 Django 中使用可视化工具 Pyecharts, 看完本教程你将掌握几种动态展示可视化数据的方法!Django 模板渲染1. 新建一个 Django 项目命令行中输入以下命令django-admin startproject pyecharts_django_demo创建一个应用程序python manage.py startapp d…

python网页登录验证码不显示_进网页需要验证码?不好意思,Python从来不惧各种验证码!...

今天要来说说滑动验证码了大家应该都很熟悉点击滑块然后移动到图片缺口进行验证现在越来越多的网站使用这样的验证方式为的是增加验证码识别的难度那么&#xff0c;对于这种验证码应该怎么破呢接下来就是见证神奇的时刻打开 b 站的登录页面可以看到登录的时候需要进行滑块验证按…

怎么调用新建模型里文章的内容_优雅地进行Tensorflow Lite模型转换

初涉知乎江湖&#xff0c;知道大佬很多&#xff0c;请温柔以待&#xff01;&#xff01;&#xff01;七日凌晨&#xff0c;谷歌连夜发布了有关于Tensorflow最新成果和技术&#xff0c;这应该是贾扬清离开脸书后另一个深度学习界令人惊呼的事件了吧&#xff01;&#xff08;旁白…

git add后取消_Git常用命令-总结

创建git用户$ git config --global user.name "Your Name"$ git config --global user.email "emailexample.com"初始化一个Git仓库&#xff0c;使用git init命令。添加文件到Git仓库&#xff0c;分两步&#xff1a;使用命令git add &#xff0c;注意&…