您的位置:首页 > 编程语言 > Java开发

算法入门---java语言实现的插入排序小结

2017-04-08 11:50 435 查看
public class InsertSort {


/**

*你想啊,每个的前面都是比它小的,这样的组合肯定是有序的啊,细分到最小,每一个都需要遵守规则,

* 这样就保证了前面的所有的,即使没和我挨着那么也是都比我小的。

* 插入排序的思想:

*   元素从前往后,第一个元素排在它应该排的位置,然后去遍历第二个元素插入到它合适的位置,

*   然后依次这样,那么怎么算是它合适的位置那?就是前面要么它是第一个了,要么前面的数比它小了

*   这就证明它已经找好自己的位置可以退出查找了,每个数都按照这样来,直到最后排好序

* @param src 数据源.

*/

public static void sort(int[] src){

int len = src.length;

//第一个数认为有序不需要比较,所以从第一个开始

//此时的索引是将要插入的元素.

for(int i = 1;i<len;i++){

//j索引应该是i后面的哪一个,依次和前一个比较找到自己合适的位置就可以退出这个循环,或者走到了最前面.

//当发现前面的比自己大的时候就需要交换位置(个人感觉是不是可以吧选择排序合入?)

/*for(int j = i;j>0;j--){

if(src[j]<src[j-1]){

int temp = src[j-1];

src[j-1] = src[j];

src[j] = temp;

}else{

break;

}

}*/

//可以简化成这样,注意是从i开始,而不是i+1.不要到最后一个i+1越界。

for(int j = i;j>0 && (src[j]<src[j-1]);j--){

int temp = src[j-1];

src[j-1] = src[j];

src[j] = temp;

}

}

}

}


          插入排序的一个特性就是,中途可能会退出,不许要完全比较完未排序的序列。

          时间复杂度:

          最坏的情况就是到序的时候,插入第2个元素时要比较前1个元素,插入第3个元素时,要比较前2个元素,……,插

入第N个元素,要比较前 N - 1 个元素。因此,最坏情况下的比较次数是 1 + 2 + 3 + ... + (N - 1)也就是 N^2 / 2,所以最坏

情况下的复杂度为 O(N^2)。

          最好情况下,数组已经是有序的,每插入一个元素,只需要比较前一个元素,(比较完就退出了)因此最好情况下,

插入排序的时间复杂度为O(N)

          实测平均用时:

10000

name: 冒泡排序1 花费了 = 73ms

name: 冒泡排序2 花费了 = 67ms

name: 冒泡排序3 花费了 = 58ms

name: 冒泡排序4 花费了 = 58ms

name: 冒泡排序5 花费了 = 60ms


平均:51


50000

name: 冒泡排序1 花费了 = 1684ms

name: 冒泡排序2 花费了 = 1660ms

name: 冒泡排序3 花费了 = 1486ms

name: 冒泡排序4 花费了 = 1436ms

name: 冒泡排序5 花费了 = 1482ms


平均:1549


100000

name: 冒泡排序1 花费了 = 6742ms

name: 冒泡排序2 花费了 = 6700ms

name: 冒泡排序3 花费了 = 5880ms

name: 冒泡排序4 花费了 = 5888ms

name: 冒泡排序5 花费了 = 5848ms


平均:6211


        总的看起来还是比选择排序用时长,比冒泡排序用时短。它能中断所以比冒泡短,但是即使它可以中断,但交换的
次数相对于选择排序还是非常的多的,而一次的交换就意味着三次的赋值。

但是它可以改进,对插入排序进行改进,核心是利用每次需要交换元素时换成赋值的,把前面比较大的元素复制到它的后

一个索引所在的位置(这个位置最开始的是要插入的那个元素,拿出来保留住),一直到最后,再把前面保留住的元素存入
到最后空出来的这个合适的位置。
       改进后的代码如下:

/**

* 改进后的插入排序。

*  核心改进思想:当发现比前面数据小的时候不是每次都要交换,而是通过赋值。

*  先把最初的元素的值取出来保存,把当前位置往后赋值。循环到最后,再把取出来的数放入空出的位置。

* @param src 数据源

*/

public static void betterInsertSort(int[] src){

int len = src.length;

for(int i = 1;i<len;i++){

//先把需要插入到指定序列的元素拿出来,用于最后确定位置的时候进行插入。

int e = src[i];

int j;//为了方便最后出来的时候最后的赋值。

//比较拿出来的那个元素和前面各个元素的大小。注意从j-1开始。

for(j=i;j>0&&(e<src[j-1]);j--){

//由于e小于j-1索引对应的数,那么把j-1索引对应的数赋值到j上,向后移动而不是交换。

src[j] = src[j-1];

}

//循环完毕后,此时e>j或者j == 0了。一直比较的是j是当前索引,不符合的时候j-1赋值给j,然后j往前动1。

//此时还是比较当前所以,不符合那么直接把拿出来的放这即可。

src[j] = e;

}

}


        改进后的实测时间:

10000

name: 冒泡排序1 花费了 = 47ms

name: 冒泡排序2 花费了 = 39ms

name: 冒泡排序3 花费了 = 17ms

name: 冒泡排序4 花费了 = 17ms

name: 冒泡排序5 花费了 = 20ms


平均:28


50000

name: 冒泡排序1 花费了 = 949ms

name: 冒泡排序2 花费了 = 934ms

name: 冒泡排序3 花费了 = 414ms

name: 冒泡排序4 花费了 = 418ms

name: 冒泡排序5 花费了 = 421ms


平均:627


100000

name: 冒泡排序1 花费了 = 3892ms

name: 冒泡排序2 花费了 = 3824ms

name: 冒泡排序3 花费了 = 1708ms

name: 冒泡排序4 花费了 = 1674ms

name: 冒泡排序5 花费了 = 1710ms


平均:2561


         对比别的博客的数据值可以看出来平均来说已经比插入快了,就是因为它有可能会中断,不需要每次都查询到未排
序序列的最后。

稳定性:稳定。
      你想啊,只有小于的时候才进行插入,不然直接就break了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息