【排序】插入排序算法

    特别说明:

对于算法,重在理解其思想、解决问题的方法,思路。因此,以下内容全都假定待排序序列的存储结构为:顺序存储结构。

一:插入排序算法思想

01.设待排序序列为 。插入排序将  划分为由已排序好序的  部分 以及 未排序的  部分组成;

注意:刚开始时  部分其实可认为只有一个元素,即: 元素

02.排序开始时,每次从  序列中(随机,但一般是直接取第一个元素)取出一个元素 ,将其插入到已排好序  部分的"适当位置 ",使得以下条件成立:

     ,{ 1  x  i  y  m }

03.将位置  及其后的所有元素全部后移一个位置后,赋值  =  即可;

04.重复执行第 02、03 步骤,直到未排序部分为空为止;

二:直接插入排序算法

直接插入排序是严格按照前面思想设计的一种插入排序算法。因此,其编码实现参考如下:

 1 //
 2 // summary     : 直接插入排序
 3 // in param    : seqlist 待排序列表.同时也是排完序列表.
 4 // in param    : nLen 列表长度
 5 // out param   : --
 6 // return      : --
 7 // !!!note       : 01.以下实现均假设一切输入数据都合法.即:内部不对参数全法性进行校验,默认它们全都合法有效.
 8 //               02.排序开始前 seqlist 是无序的,排序结束后 seqlist 是有序的.
 9 void insert_sort(int seqlist[/*nLen*/], const int nLen) {
10     auto nTemp     = 0;
11     auto nInnerIdx = 0;
12     for (auto nOuterIdx = 1; nOuterIdx < nLen; ++nOuterIdx) {
13         nTemp = seqlist[nOuterIdx];
14         for (nInnerIdx = nOuterIdx; nInnerIdx > 0; --nInnerIdx) {
15             if (nTemp >= seqlist[nInnerIdx - 1]) {
16                 break;
17             }
18             seqlist[nInnerIdx] = seqlist[nInnerIdx - 1];
19
20         }
21         seqlist[nInnerIdx] = nTemp;
22     }
23 }

直接插入排序算法编码参考

直接插入排序算法的辅助空间复杂度 ;算法是稳定的;属于原地排序算法;平均时间复杂度 ;每一趟的平均数据移动次数为  次;每一趟的平均数据比较次数为  次。

三:折半插入排序算法

从前文内容可知,为得知适当的位置 ,需要从  位置一直往前逐一比较元素,这样(每一趟的)平均比较次数是线性的(为  次)。但由于这前  个元素已经明确是有序的,因此利用这一有利条件,可以利用折半查找在  次数内定位到  位置。因此,折半插入排序算法,算是对直接插入排序的一种改进。算法编码参考如下:

 1 //
 2 // summary     : 折半插入排序
 3 // in param    : seqlist 待排序列表.同时也是排完序列表.
 4 // in param    : nLen 列表长度
 5 // out param   : --
 6 // return      : --
 7 // !!!note       : 01.以下实现均假设一切输入数据都合法.即:内部不对参数全法性进行校验,默认它们全都合法有效.
 8 //               02.排序开始前 seqlist 是无序的,排序结束后 seqlist 是有序的.
 9 void binary_insert_sort(int seqlist[/*nLen*/], const int nLen) {
10     auto nTemp     = 0;
11     auto nInnerIdx = 0;
12     auto nLow      = 0;
13     auto nHigh     = 0;
14     auto nMid      = 0;
15     for (auto nOuterIdx = 1; nOuterIdx < nLen; ++nOuterIdx) {
16         nTemp = seqlist[nOuterIdx];
17
18         nLow  = 0;
19         nHigh = nOuterIdx;
20         while (nLow < nHigh) {
21             nMid = (nLow + nHigh) >> 1;
22             nTemp < seqlist[nMid] ? nHigh = nMid : nLow = nMid + 1;
23         }
24         for (nInnerIdx = nOuterIdx; nInnerIdx > nHigh; --nInnerIdx) {
25             seqlist[nInnerIdx] = seqlist[nInnerIdx - 1];
26         }
27         seqlist[nInnerIdx] = nTemp;
28     }
29 }

折半插入排序算法编码参考

折半插入排序算法总体情况与直接插入排序是一样的,只是比较次数总体上会优于直接插入排序。算法实现上,会稍稍比直接插入排序复杂些。

四:2路插入排序算法

相比于排序元素的"关键字"比较而言,多数情况下数据的移动可能会更加的耗时些(因为现实应用中的数据可能就不止是简简单单的基础数据类型,有时候可能还是复杂的自定义类型对象)。2路插入排序算法利用额外的辅助空间,以求尽量减少直接插入排序的数据移动次数。注意:虽说移动次数会得到改善,但付出的代价也是较大的,其需要的额外辅助空间与待排序序列的空间一样大小,因此,如果在某些空间资源较为缺乏的应用场合,该算法就不太可行。

2路插入排序算法的思想:

假设待排序序列为 ,辅助序列为 

01.将  的第一个元素赋值给  的第一个元素。即: = 

02.从  中取出下一个元素 ,将其与  比较。当比  小时,则插入到  的"低端"的适当位置;如果比  大时,则插入到  的"高端"的适当位置;

注释:

a) "低端":因为  是辅助序列的第一个元素,即为顺序存储结构的第一个元素,因此,此处的"低端"是指  序列的高端部分的存储空间(即: 列表的右端部分的存储空间);

b) "高端":因为  是辅助序列的第一个元素,即为顺序存储结构的第一个元素,因此,此处的"高端"是指  序列的低端部分的存储空间(即: 列表的左端部分的存储空间);

注意:

a) 关于此处如何定位到适当位置的问题,其实算法本身是没有明确要求,因此,我们可参考直接插入排序算法思想中的定位方法,也可以参考折半插入排序算法思想中的定位方法,甚至任何其他方法(只要认为高效的)均可。下文的具体编码参考实现中,使用的是直接插入排序算法思想中的定位方法,具体见编码参考。

03.重复步骤 02 直到全部处理完整个  序列为止;

04.将辅助空间  中的数据,拷贝到  序列列表中,排序完成;

注意:

a) 2路插入排序算法在实现时,一般情况下是需要设置两个游标指针 first 与 last。其中 first 指示  的低端下界位置;last 指示  的高端上界位置;

b) 在处理上面 04点时,要先按顺序拷贝低端部分的数据,然后再按顺序拷贝高端部分的数据;

算法的编码参考如下:

 1 //
 2 // summary     : 2路插入排序
 3 // in param    : seqlist 待排序列表(数组).即是输入也是输出.
 4 // in param    : helplist 辅助列表(数组)
 5 // in param    : nLen 列表长度
 6 // out param   : --
 7 // return      : --
 8 // !!!note       : 01.以下实现均假设一切输入数据都合法.即:内部不对参数全法性进行校验,默认它们全都合法有效.
 9 //               02.排序开始前 seqlist 是无序的,排序结束后 seqlist 是有序的.
10 void two_way_insert_sort(int seqlist[/*nLen*/], int helplist[/*nLen*/], const int nLen) {
11     helplist[0]    = seqlist[0];
12     auto first     = 0; // 已排好序的低端(即:最小值的一端).所在位置即为最小值位置索引.
13     auto last      = 0; // 已排好序的高端(即:最大值的一端).所在位置即为最大值位置索引.
14     auto nTemp     = 0;
15     auto nInnerIdx = 0;
16     auto nPriorIdx = 0;
17     for (auto nOuterIdx = 1; nOuterIdx < nLen; ++nOuterIdx) {
18         nTemp = seqlist[nOuterIdx];
19         if (nTemp < helplist[first]) {
20             first = (first - 1 + nLen) % nLen;
21             helplist[first] = nTemp;
22         } else if (nTemp >= helplist[last]) {
23             ++last;
24             helplist[last] = nTemp;
25         } else {
26             nInnerIdx = ++last;
27             while (nInnerIdx != first) {
28                 nPriorIdx = (nInnerIdx - 1 + nLen) % nLen;
29                 if (nTemp >= helplist[nPriorIdx]) {
30                     break;
31                 }
32                 helplist[nInnerIdx] = helplist[nPriorIdx];
33                 nInnerIdx = nPriorIdx;
34             }
35             helplist[nInnerIdx] = nTemp;
36         }
37     }
38     auto nCounter = 0;
39     while (nCounter < nLen) {
40         seqlist[nCounter] = helplist[(first + nCounter) % nLen];
41         ++nCounter;
42     }
43 }

2路插入排序算法编码参考

时间: 2024-08-04 19:43:22

【排序】插入排序算法的相关文章

数据结构——排序——直接插入排序和折半插入排序算法

直接插入排序(Insertion Sort)的基本思想是: 每次将一个待排序的记录,按其关键字大小插入到前面已经排好序的子序列中的适当位置,直到全部记录插入完成为止. 设数组为a[0…n-1]: 1. 初始时,a[0]自成1个有序区,无序区为a[1..n-1].令i=1 2. 将a[i]并入当前的有序区a[0…i-1]中形成a[0…i]的有序区间. 3. i++并重复第二步直到i==n-1.排序完成. #include<stdio.h> #include<stdbool.h> vo

插入排序算法---插入排序与希尔排序

本文主要说明插入排序.shell排序两种排序方法.  一.插入排序  算法思想:  假定这个数组的序是排好的,然后从头往后,如果有数比当前外层元素的值大,则将这个数的位置往后挪,直到当前外层元素的值大于或等于它前面的位置为止.这具算法在排完前k个数之后,可以保证a[1…k]是局部有序的,保证了插入过程的正确性. 一般来说,插入排序都采用in-place在数组上实现.具体算法描述如下: ⒈ 从第一个元素开始,该元素可以认为已经被排序 ⒉ 取出下一个元素,在已经排序的元素序列中从后向前扫描 ⒊ 如果

插入排序算法之直接插入排序和希尔排序

插入排序算法 有一个已经有序的数据序列,要求在这个已经排好的数据序列中插入一个数,但要求插入后此数据序列仍然有序,这个时候就要用到一种新的排序方法--插入排序法,插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的.个数加一的有序数据. 直接插入排序 直接插入排序的排序思路是:每次将一个待排序的元素与已排序的元素进行逐一比较,直到找到合适的位置按大小插入. 例子: 有序列: 开始时,有序序列只有一个元素就是第一个元素(红色),后面的无序序列(绿色).接下来,取无序序列中

排序算法之 Java插入排序算法

package net.qh.test.sort; import java.util.ArrayList; import java.util.Calendar; import java.util.List; /** * Created by Administrator on 2016/03/01. */ public class Insert { public int[] sort(int[] arr){ if ( arr == null || arr.length <= 1 ){ return

算法大神之路----排序(插入排序法)

插入排序法 所谓插入排序法乃是将一个数目插入该占据的位置. 输入一个元素,检查数组列表中的每个元素,将其插入到一个已经排好序的数列中的适当位置,使数列依然有序,当最后一个元素放入合适位置时,该数组排序完毕. 代码示例: import java.util.Random; /** * 算法大神之路----排序(插入排序法) */ public class Study03 { public static void main(String[] args) { //新建一个数组 int[] arr = n

排序系列 之 直接插入排序算法 —— Java实现

直接插入排序算法 基本思想: 把n个待排序的元素看成一个有序表和一个无序表,开始时有序表中只有一个元素,无序表中有n-1个元素:排序过程即每次从无序表中取出第一个元素,将它插入到有序表中,使之成为新的有序表,重复n-1次完成整个排序过程. 实例: 0.初始状态 3,1,5,7,2,4,9,6(共8个数)    有序表:3:无序表:1,5,7,2,4,9,6 1.第一次循环,从无序表中取出第一个数 1,把它插入到有序表中,使新的数列依旧有序    有序表:1,3:无序表:5,7,2,4,9,6 2

排序算法之直接插入排序算法

基本思想 当插入第i(i≥1)个元素,前面的i-1个元素已经排好序.这时用第i个元素与前i-1个元素进行比较,找到插入位置即将第i个元素插入,原来位置上的元素向后顺移. 代码: //待排数据存储在数组a中,以及待排序列的左右边界 public void InsertSort(int[] a, int left, int right) { int temp;//临时变量 int i, j;//循环标记 for (i = left + 1; i <= right; i++) {//遍历待排序列 if

排序系列 之 折半插入排序算法 —— Java实现

基本思想: 折半插入算法是对直接插入排序算法的改进,排序原理同直接插入算法: 把n个待排序的元素看成一个有序表和一个无序表,开始时有序表中只有一个元素,无序表中有n-1个元素:排序过程即每次从无序表中取出第一个元素,将它插入到有序表中,使之成为新的有序表,重复n-1次完成整个排序过程. 与直接插入算法的区别在于:在有序表中寻找待排序数据的正确位置时,使用了折半查找/二分查找. 实例: (参考直接插入排序算法:http://www.cnblogs.com/snowcan/p/6244128.htm

【插入排序算法】初学算法之排序--直接插入排序

前言: 厚厚一本<算法第四版>,看到五分之一就已经收益良多,而前五分之一又大部分是关于排序,有冒泡排序.快速排序.堆排序.直接插入排序.希尔排序等等,理解起来也不算特别的难,今天就跟大家分享其中的一种 —— 直接插入排序算法,这里我实现了javascript和java两个语言版本. 思路: 在生活中,如果我们要对扑克牌按大小排序,我们会怎么排呢? ① 首先找出一张牌 放在桌子上 ② 拿出第二张牌,比第一张小就放上面,比第一张大就放下面 ③ 拿出第三张牌,比第一张小就放上面,比第一张大就和第二张