标签:排序算法
排序算法分为很多种,其中插入排序算是最基础的排序算法了。插入排序包括直接插入排序,折半插入排序和希尔排序,这三种排序算法本质是一样的,但是在实际操作和实现的过程中有不同的辅助存储空间和时间复杂度。
一、直接插入排序
基本思想
直接插入排序是指把一个元素直接插入到一个有序表中,从而得到一个元素数增加1的新有序表。所以当需要排序一组数时,我们取出这组数的第1个元素作为一个有序表,然后取第2个元素进行插入,得到一个含有2个元素的有序表,再取第3个元素进行插入,以此类推,直到最后一个元素被插入到新的有序表中,排序完成。
在一个已有i个元素的有序表中插入新元素时,可以选择从第i个元素开始从后往前搜索新元素插入的位置,这样就可以在搜索的过程中后移元素,以便在找到插入的位置时直接将新元素插入(见伪代码)。也可以在从后往前搜索的过程中,当插入的元素小于与其比较的元素时,直接原地交换,然后继续向前搜索,直到跳出循环(见下文代码实现)。原地交换的好处就是节省一些空间,并且可以防止数组越界。
举个栗子
需要排序的数列为:22 45 12 47 56 36
第一次: (22 45)12 47 56 36
第二次: (12 22 45)47 56 36
第三次: (12 22 45 47)56 36
第三次: (12 22 45 47 56)36
第四次: (12 22 36 45 47 56) 排序完成!
算法伪代码
InsertionSort(A[0...n-1]) //用插入排序对给定数组排序 //输入:n个可排序元素构成的一个数组A[0...n-1] //输出:非降序排列的数组A[0...n-1] for i ← 1 to n-1 do v ← A[i] j ← i-1 while j >= 0 and A[j]>v do A[j+1] ← A[j] //后移元素 j ← j+1 A[j+1] ← v
算法复杂度分析
由上面的伪代码可以看出,该算法的基本操作是键值比较 A[j]>v,显然键值比较的次数显然依赖于特定的输入。在最坏的情况下,上述伪代码的while循环每次都从j=i-1执行到j=0,也就是说原数组是一个降序排列的数组,所以对于这种输入,键值的比较次数是:
C worst(n)= ∑(i=1...n-1)∑(j=0...i-1) 1= (n-1)n/2 ∈ θ(n^2)
最好的情况下,原数组已经按照升序排列了,所以每次while循环只执行一次,故对于n个元素的数组键值比较次数为n ∈ θ(n),但是这种情况本身没有多大意义,因为我们不能指望有这么简单的输入。
根据书上所讲的,对于随机序列的数组,直接插入排序的平均比较次数是降序数组的一半,也就是说:
C avg(n)= (n-1)n/4 ∈ θ(n^2)
平均性能比最差性能快一倍,并且在遇到基本有序数组时表现优异,使得直接插入排序领先于它在基本排序算法领域的主要竞争对手——选择排序和冒泡排序,但这并不意味着它可以取代这些算法,接下来的文章中我会再温习这些算法。
算法的代码实现(Java)
public class InsertionSort { public static void main(String[] args){ int [] array=new int[]{22,65,34,18,56,49,0}; int temp; for(int i=1;i<array.length;i++){ for(int j = i;j > 0;j--){ if(array[j] < array[j-1]){ temp = array[j-1]; array[j-1] = array[j]; array[j] = temp; } } } for(int i:array) System.out.print(i+","); } }
水平有限,希望诸位大佬多加指正!
本文出自 “卫莨” 博客,转载请与作者联系!
标签:排序算法
原文地址:http://acevi.blog.51cto.com/13261784/1963566