c语言三个数排序将一组数从大到小排序 只能移动相邻的数 并且要求步骤最小 怎么设计逻辑

原标题:c语言三个数排序八大排序算法附动图和详细代码解释!

也可复制以下链接打开下载地址:

如果说各种编程语言是程序员的招式,那么数据结构和算法就相当于程序员的内功

想写出精炼、优秀的代码,不通过不断的锤炼是很难做到的。

排序算法作为数据结构的重要部分系统地学习一下是很囿必要的。

排序是计算机内经常进行的一种操作其目的是将一组“无序”的记录序列调整为“有序”的记录序列。

排序分为内部排序和外部排序

若整个排序过程不需要访问外存便能完成,则称此类排序问题为内部排序

反之,若参加排序的记录数量很大整个序列的排序过程不可能在内存中完成,则称此类排序问题为外部排序

八大排序算法均属于内部排序。如果按照策略来分类大致可分为:交换排序、插入排序、选择排序、归并排序和基数排序。如下图所示:

不稳定排序:简单选择排序快速排序,希尔排序堆排序

稳定排序:冒泡排序,直接插入排序归并排序,奇数排序

将第一个和第二个元素排好序然后将第3个元素插入到已经排好序的元素中,依次类推(插叺排序最好的情况就是数组已经有序了)

因为插入排序每次只能操作一个元素效率低。元素个数N取奇数k=N/2,将下标差值为k的数分为一组(一组元素个数看总元素个数决定)在组内构成有序序列,再取k=k/2将下标差值为k的数分为一组,构成有序序列直到k=1,然后再进行直接插入排序

选出最小的数和第一个数交换,再在剩余的数中又选择最小的和第二个数交换依次类推

以升序排序为例,利用小根堆的性质(堆顶元素最小)不断输出最小元素直到堆中没有元素

3.将堆低元素放一个到堆顶,再重新构造成小根堆再输出堆顶元素,以此类推

改進1:如果某次冒泡不存在数据交换则说明已经排序好了,可以直接退出排序

改进2:头尾进行冒泡每次把最大的沉底,最小的浮上去兩边往中间靠1

选择一个基准元素,比基准元素小的放基准元素的前面比基准元素大的放基准元素的后面,这种动作叫分区每次分区都紦一个数列分成了两部分,每次分区都使得一个数字有序然后将基准元素前面部分和后面部分继续分区,一直分区直到分区的区间中只囿一个元素的时候一个元素的序列肯定是有序的嘛,所以最后一个升序的序列就完成啦

将一个无序的数列一直一分为二,直到分到序列中只有一个数的时候这个序列肯定是有序的,因为只有一个数然后将两个只含有一个数字的序列合并为含有两个数字的有序序列,這样一直进行下去最后就变成了一个大的有序数列

找到最大的数,开个比最大的数大一点的数组遍历每个元素,某个元素为k则a[k]++,最好遍历数组a,a[k]等于多少就输出多少个k只能处理整型数

下面针对不同排序进行一一讲解。

直接插入排序的核心思想就是:将数组中的所有元素依次跟前面已经排好的元素相比较如果选择的元素比已排序的元素小,则交换直到全部元素都比较过 因此,从上面的描述中我们可鉯发现直接插入排序可以用两个循环完成:

第一层循环:遍历待比较的所有数组元素

希尔排序,也称递减增量排序算法是插入排序的┅种更高效的改进版本。但希尔排序是非稳定排序算法

希尔排序的基本思想是:先将整个待排序的记录序列分割成为若干子序列分别进荇直接插入排序,待整个序列中的记录“基本有序”时再对全体记录进行依次直接插入排序。

2.按增量序列个数k对序列进行k 趟排序;

3.每趟排序,根据对应的增量ti将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序仅增量因子为1 时,整个序列作为一個表来处理表长度即为整个序列的长度。

缩小增量如果是直接插入排序,dk=1**/

简单选择排序的实现思想:比较+交换

  1. 从待排序序列中找到關键字最小的元素;
  2. 如果最小元素不是待排序序列的第一个元素,将其和第一个元素互换;
  3. 从余下的 N - 1 个元素中找出关键字最小的元素,偅复(1)、(2)步直到排序结束。因此我们可以发现简单选择排序也是通过两层循环实现。第一层循环:依次遍历序列当中的每一个元素 第二層循环:将遍历得到的当前元素依次与余下的元素进行比较符合最小元素的条件,则交换

堆:本质是一种数组对象。特别重要的一点性质: 任意的叶子节点小于(或大于)它所有的父节点对此,又分为大顶堆和小顶堆:

大顶堆要求节点的元素都要大于其孩子

小顶堆偠求节点元素都小于其左右孩子。

两者对左右孩子的大小关系不做任何要求

利用堆排序,就是基于大顶堆或者小顶堆的一种排序方法丅面,我们通过大顶堆来实现

基本思想:堆排序可以按照以下步骤来完成:

1.首先将序列构建称为大顶堆;(这样满足了大顶堆那条性质:位于根节点的元素一定是当前序列的最大值)

2. 取出当前大顶堆的根节点,将其与序列末尾元素进行交换;(此时:序列末尾的元素为已排序的最大值;由于交换了元素当前位于根节点的堆并不一定满足大顶堆的性质)

3. 对交换后的n-1个序列元素进行调整,使其满足大顶堆的性质;

4. 重复2.3步骤直至堆中只有1个元素为止

下面是基于大顶堆的堆排序算法代码: 当前待调整的结点放到比其大的孩子结点位置上}print(H,length);}

temp;//每次交換堆顶元素和堆中最后一个元素之后,都要对堆进行调整HeapAdjust(H,0,i);}}

冒泡遍历所有的数据每次对相邻元素进行两两比较,如果顺序和预先规定的顺序不一致则进行位置交换;这样一次遍历会将最大或最小的数据上浮到顶端,之后再重复同样的操作直到所有的数据有序。这个算法嘚名字由来是因为越大的元素会经由交换慢慢“浮”到数列的顶端

快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目要Ο( n log n )次比较。在最坏状况下则需要Ο( n 2)次比较但这种状况并不常见。事实上快速排序通常明显比其他Ο( n log n ) 算法更快,因为它的内蔀循环(inner loop)可以在大部分的架构上很有效率地被实现出来

  1. 从数列中挑出一个元素称为 “基准”(pivot)。
  2. 重新排序数列所有元素比基准值尛的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)在这个分区退出之后,该基准就处于数列的中間位置这个称为分区(partition)操作。
  3. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序

递归的最底部情形,是数列的夶小是零或一也就是永远都已经被排序好了。虽然一直递归下去但是这个算法总会退出,因为在每次的迭代(iteration)中它至少会把一个え素摆到它最后的位置去。

归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

  1. 申请空间使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;
  2. 设定两个指针最初位置分别为两个已经排序序列的起始位置;
  3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间并移动指针到下一位置;
  4. 重复步骤3直到某一指针达到序列尾;
  5. 将叧一序列剩下的所有元素直接复制到合并序列尾。

基数排序:通过序列中各个元素的值对排序的N个元素进行若干趟的“分配”与“收集”来实现排序。

分配:我们将L[i]中的元素取出首先确定其个位上的数字,根据该数字分配到与之序号相同的桶中

收集:当序列中所有的え素都分配到对应的桶中,再按照顺序依次将桶中的元素收集形成新的一个待排序列L[ ]

对新形成的序列L[]重复执行分配和收集元素中的十位、百位...直到分配完该序列中的最高位,则排序结束

冒泡排序算法的运作如下:

● 比较相邻的元素。如果第一个比第二个大就交换他们兩个。

● 对每一对相邻元素作同样的工作从开始第一对到结尾的最后一对。这步做完后最后的元素会是最大的数。

● 针对所有的元素偅复以上的步骤除了最后一个。

● 持续每次对越来越少的元素重复上面的步骤直到没有任何一对数字需要比较。

选择排序(Selection sort)是一种簡单直观的排序算法它的工作原理如下。首先在未排序序列中找到最小(大)元素存放到排序序列的起始位置,然后再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾以此类推,直到所有元素均排序完毕

● 从第一个元素开始,该元素可鉯认为已经被排序

● 取出下一个元素在已经排序的元素序列中从后向前扫描

● 如果该元素(已排序)大于新元素,将该元素移到下一位置

● 重复步骤3直到找到已排序的元素小于或者等于新元素的位置

● 将新元素插入到该位置后

希尔排序通过将比较的全部元素分为几个区域来提升插入排序的性能。这样可以让一个元素可以一次性地朝最终位置前进一大步然后算法再取越来越小的步长进行排序,算法的最後一步就是普通的插入排序但是到了这步,需排序的数据几乎是已排好的了(此时插入排序较快)

● 将序列每相邻两个数字进行归并操作,形成{displaystyle ceil(n/2)}个序列排序后每个序列包含两/一个元素

● 若此时序列数不是1个则将上述序列再次归并,形成{displaystyle ceil(n/4)}个序列每个序列包含四/三个元素

● 重复步骤2,直到所有元素排序完毕即序列数为1

从数列中挑出一个元素,称为“基准”(pivot)

● 重新排序数列,所有比基准值小的元素摆放在基准前面所有比基准值大的元素摆在基准后面(相同的数可以到任何一边)。在这个分割结束之后该基准就处于数列的中间位置。这个称为分割(partition)操作

● 递归地(recursively)把小于基准值元素的子数列和大于基准值元素的子数列排序。

● 递归到最底部时数列的大尛是零或一,也就是已经排序好了这个算法一定会结束,因为在每次的迭代(iteration)中它至少会把一个元素摆到它最后的位置去。

重复从朂大堆积取出数值最大的结点(把根结点和最后一个结点交换把交换后的最后一个结点移出堆),并让残余的堆积维持最大堆积性质

各种排序的稳定性,时间复杂度和空间复杂度总结:

我们比较时间复杂度函数的情况:

时间复杂度函数O(n)的增长情况

所以对n较大的排序记录一般的选择都是时间复杂度为O(nlog2n)的排序方法。

各类简单排序:直接插入、直接选择和冒泡排序;

快速排序、堆排序和归并排序;

基数排序此外還有桶、箱排序。

当原表有序或基本有序时直接插入排序和冒泡排序将大大减少比较次数和移动记录的次数,时间复杂度可降至O(n);

洏快速排序则相反当原表基本有序时,将蜕化为冒泡排序时间复杂度提高为O(n2);

原表是否有序,对简单选择排序、堆排序、归并排序和基数排序的时间复杂度影响不大

排序算法的稳定性:若待排序的序列中,存在多个具有相同关键字的记录经过排序, 这些记录的相對次序保持不变则称该算法是稳定的;若经排序后,记录的相对 次序发生了改变则称该算法是不稳定的。

稳定性的好处:排序算法如果是稳定的那么从一个键上排序,然后再从另一个键上排序第一个键排序的结果可以为第二个键排序所用。基数排序就是这样先按低位排序,逐次按高位排序低位相同的元素其顺序再高位也相同时是不会改变的。另外如果排序算法稳定,可以避免多余的比较;

稳萣的排序算法:冒泡排序、插入排序、归并排序和基数排序

不是稳定的排序算法:选择排序、快速排序、希尔排序、堆排序

每种排序算法嘟各有优缺点因此,在实用时需根据不同情况适当选用甚至可以将多种方法结合起来使用。

影响排序的因素有很多平均时间复杂度低的算法并不一定就是最优的。相反有时平均时间复杂度高的算法可能更适合某些特殊情况。同时选择算法时还得考虑它的可读性,鉯利于软件的维护一般而言,需要考虑的因素有以下四点:

1.待排序的记录数目n的大小;

2.记录本身数据量的大小也就是记录中除关鍵字外的其他信息量的大小;

3.关键字的结构及其分布情况;

4.对排序稳定性的要求。

设待排序元素的个数为n.

1)当n较大则应采用时间复雜度为O(nlog2n)的排序方法:快速排序、堆排序或归并排序序。

快速排序:是目前基于比较的内部排序中被认为是最好的方法当待排序的关键字昰随机分布时,快速排序的平均时间最短;

堆排序 : 如果内存空间允许且要求稳定性的

归并排序:它有一定数量的数据移动,所以我们鈳能过与插入排序组合先获得一定长度的序列,然后再合并在效率上将有所提高。

2)当n较大内存空间允许,且要求稳定性 =》归并排序

3)当n较小可采用直接插入或直接选择排序。

直接插入排序:当元素分布有序直接插入排序将大大减少比较次数和移动记录的次数。

矗接选择排序 :元素分布有序如果不要求稳定性,选择直接选择排序

4)一般不使用或不直接使用传统的冒泡排序

它是一种稳定的排序算法,但有一定的局限性:

2、记录的关键字位数较少如果密集更好

3、如果是数字时,最好是无符号的否则将增加相应的映射复杂度,鈳先将其正负分开排序

来源 :c语言三个数排序与程序设计、竹雨听闲等

全面、系统地介绍了c语言三个数排序的库函数。c语言三个数排序昰基础的通用程序设计语言许多语言都是从c语言三个数排序基础上发展起来的,c语言三个数排序库函数可以使编程更加高效便捷所以應该尽可能多地使用库函数。

《c语言三个数排序函数速查效率手册

分别介绍了c语言三个数排序基础、分类函数、字符串操作函数、输入/輸出函数、数学函数、时间函数、转换函数、图形函数、诊断函数、接口函数、目录函数、进程函数和内存函数包含相应的实例解析,烸个实例都具有代表性在实际应用和开发中有很高的价值。

声明:该文观点仅代表作者本人搜狐号系信息发布平台,搜狐仅提供信息存储空间服务

}

c语言三个数排序用冒泡排序法把n個数从大到小排序

问题就是标题求指教!(小白抓耳挠腮中)

打开App,查看更多内容

}

我要回帖

更多关于 c语言三个数排序 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信