插入排序

来源:互联网 发布:记事本写c语言 编辑:程序博客网 时间:2024/06/06 23:50
什么是插入排序?
插入排序其实就是指对于一个无序的数组,从下标为1的元素开始,每一轮都以此元素(即准备插入的元素)为起点,向着数组首元素(即array[0])的方向开始遍历,直到遇到比此元素小的数据项,则停止遍历,然后从这个数据项开始,其后的元素都后移一位,以腾出空间,再将一开始准备插入的那个元素插入到这个位置。


插入排序代码:

<span style="white-space:pre"></span>int finishKey;    //当前准备插入的数据项int changeKey;    //由finishKey开始,向左遍历进行交换的数据项int temp;         //暂时存储当前准备插入的数据项public void insertSort(int[] a){//从左开始进行每一轮的插入排序for(finishKey = 1;finishKey<a.length; finishKey++){temp = a[finishKey];  //先把准备进行插入的数据项暂时存放在temp中//内层循环,从finishKey开始向左进行遍历,直到遇到比temp小的数据项才停止遍历for(changeKey = finishKey-1;changeKey>=0&&a[changeKey]>temp; changeKey--){a[changeKey+1] = a[changeKey];   //如果数据项比temp大,就都后移一位}a[changeKey+1] = temp;      //后移完成后,将空出来的空位赋予temp,即将a[finishKey]插入该空位}}


测试代码:


控制台:




代码具体步骤解析:
数组初始化的数据:int a[] = new int[]{4,1,6,2,7,9,3,8};【我们要将此数组按照插入排序排成从小到大
第一轮应该从a[1]开始,为什么不从a[0]开始呢?因为插入排序的原则是要将元素插入到前面已经排好的数据之中,如果从a[0]开始,则前面并没有可以插入的位置。
首先将要插入的元素的值赋给temp,temp是一个用来暂时存放待插入元素的变量,待会儿插入的时候便是使用temp的值来插入。因此此处将a[1]赋给temp。然后从a[0]开始向前遍历,即:


这里a[changeKey]即a[0]大于temp。那么符合循环的条件,需要移位,将a[0]的值赋给a[1]:



这句代码运行之后,相当于a[0]去到了a[1]的位置,那么原本a[0]的位置便腾了出来

继续内层循环,changeKey--之后,changeKey=-1不符合a[changeKey]>=0的循环条件,所以结束内层循环,接着就可以将temp(即这一轮准备插入的元素a[1])插入到刚才腾出来的位置:



第一轮插入结束,此时数组的数据为:{1,4,6,2,7,9,3,8}


第二轮则应该从a[2]开始,一样先将a[2]的值赋给temp存放着,然后从a[2]前面的元素(即a[1])开始进行内层遍历,这里
a[1]并没有大于temp,且经过刚才的第一轮插入,a[1]前面的元素肯定都会比a[1]小,所以a[2]不可能能够插入到前面的数据项中,因此直接结束内层循环,仍然将temp赋回给a[2],第二轮插入结束:此时数组的数据为:{1,4,6,2,7,9,3,8}


依次类推,继续下一轮直到数组最后一个元素完成插入排序。







插入排序的时间复杂度:
插入排序第一轮最多需要比较1次,第二轮最多需要比较2次...
所以最终最多需要比较:1+2+3+...+N-1次,即N(N-1)/2次,但实际情况中并不用每一趟都遍历到底,以平均除以2来计算则需要N(N-1)/4次,因此对于随机顺序的数据,插入排序需要O(N^2)的时间级。
数组数据项基本有序的情况下,插入排序的优势非常明显,因为每一轮在开始遍历时便不符合内层循环的条件,可以直接跳出,结束本轮插入。最终只是走了外层循环,即N-1次,这种情况下算法时间复杂度为O(N)级。
但是如果对于数据项逆序排列的情况下,插入排序就需要较多的时间,因为每一轮都要比较到底,每一轮都需要执行所有内层循环,此插入排序并不比冒泡排序快。
1 0