Java数据结构和算法-简单排序(3-插入排序)

来源:互联网 发布:mac应用程序开发教程 编辑:程序博客网 时间:2024/06/05 02:12

在大部分情况下,插入排序是简单排序中最好的,虽然插入排序算法仍然需要O(N^2)的时间,但是它要比冒泡排序快一倍,比选择排序快一点,尽管插入排序算法比冒泡和选择排序算法麻烦一些,但也并不复杂,它常作为复杂排序的最后一段,比如快速排序。

插入排序的例子

同样以体育课排队为例,只不过这次利用插入排序。
这次假设,利用插入排序已经排好了队伍的一半(这样更便于对插入排序的理解),即在中间的同学的右边队伍是有序的,不过是局部有序(注意冒泡和选择排序不会出现局部有序的情况,而是完全有序的),这意味着这部分的人都按顺序排好了,左边的都要比右边的人高,但是这部分学生在队伍中的最终位置并没有确定,也就是说会有没排序过的同学插入到他们之中,从而位置会发生移动。
此时我们将最中间的同学作为标记,他和他右边的同学都是未排序的。如下图:
这里写图片描述
现在要将被标记的同学插入到其左边局部有序的同学当中,但是要插入的话,就必须把部分已排序的同学向右移动。为了提供移动所需的空间,就先让被标记的同学出列。
现在开始移动部分已排序的同学。将被标记的同学依次与左边已排序的最高、次高…的同学进行比较,若比被标记的同学高则向右移动一个位置,依此类推。直到最后一个已排序当中比被标记同学高的同学向右移动之后,停止比较,将被标记同学插入到最后一次移位所空出来的位置。就是被标记同学应该插入的位置。整个步骤如下图:
这里写图片描述
这里写图片描述
此时,局部有序的队伍中又多了一名同学,接下来,再将标记在整个队伍中向右移动一位,现在被标记的同学仍然是未排序的队伍中的最左边的同学,重复上述过程,直到所有未排序的同学都被插入到有序队伍中的适当位置时,整个队伍就是完全有序的了。

插入排序的Java代码

下面是插入排序的Java代码,仍然通过一个类来封装一个数组及其插入排序等操作,由于其他操作与之前类似,不再详写,只是写一下其中的插入排序的方法。

public void insertSort() {    int in, out;    for(out = 1; out < nItem; out ++) {        int temp = array[out];        for(in = out - 1; in >= 0; in --) {            if(array[in] > temp)                array[in + 1] = array[in];            else                break;        }        array[in + 1] = temp;    }}

外层循环当中out表示被标记的下标,从1开始向右移动,内层循环当中的in从局部有序的队伍的最右边开始,向左移动,直到temp的值大于in所对应的值,或者in不能再往左移动时停止。内层循环每循环一次都向右移动了一个已排序的数据。

不变性

在每一趟结束时,out左边的数据都是局部有序的。

插入排序的效率

在第一趟排序时,最多需要进行一次比较,第二趟最多需要两次比较,依此类推,最后一趟最多需要N-1次比较,所以总共要进行:
1+2+3+…+(N-2)+(N-1)=(N-1)*N/2
但是,实际上在每趟排序发现插入点之前,平均只有一半的数据进行了比较,所以总共比较次数为(N-1)*N/4。
复制的次数大致等于比较次数,不过复制的时间与交换的时间不同,所以插入排序要比冒泡排序快一倍,比选择排序快一点。
在任意情况下对于随机的数据,插入排序和其他排序一样都需要O(N^2)的时间。
对于已经有序或者大部分有序的数据而言,插入排序的内层循环实际上并不起作用,所以整个程序就变成了外层循环的简单语句,只执行了N-1次,所以当数据几乎有序时,插入排序只需要进行O(N)的时间,这对基本有序的文件是很有效的排序方法。

0 0
原创粉丝点击