码迷,mamicode.com
首页 > 编程语言 > 详细

算法学习#09--用简单的思维理解选择、插入、冒泡和希尔排序

时间:2016-08-04 23:21:38      阅读:748      评论:0      收藏:0      [点我收藏+]

标签:

选择排序

1.原理

首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

2.特点

①运行时间与输入无关。

无论输入初始状态如何,是否有序,都需要遍历数组来找出最小的元素。其他算法则更善于利用输入的初始状态来优化时间。

②数据移动次数最小。

如果某个元素位于正确的最终位置上,则它不会被移动。选择排序每次交换一对元素,它们当中至少有一个将被移到其最终位置上,因此对n个元素的表进行排序总共进行至多n-1次交换。在所有的完全依靠交换去移动元素的排序方法中,选择排序属于非常好的一种。

3.代码

    public static void selection_sort(int[] arr) {
        int i, j, min, temp, len = arr.length;
        for (i = 0; i < len - 1; i++) {
            min = i;
            for (j = i + 1; j < len; j++)
                if (arr[min] > arr[j])
                    min = j;
            temp = arr[min];
            arr[min] = arr[i];
            arr[i] = temp;
        }
    }

4.复杂度

①交换次数O(n): 最好情况是,已经有序,交换0次;最坏情况是,逆序,交换n-1次

②比较次数O(n^2): (n-1)+(n-2)+…+1=n*(n-1)/2

③赋值次数O(n):0到3(n-1)次之间

5.概述

最差时间复杂度 О(n2)

最优时间复杂度 О(n2)

平均时间复杂度 О(n2)

最差空间复杂度 总共О(n), 需要辅助空间O(1)

动态图:

技术分享

选择排序的示例动画。红色表示当前最小值,黄色表示已排序序列,蓝色表示当前位置。

技术分享

插入排序

1.原理

通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

步凑如下:

①从第一个元素开始,该元素可以认为已经被排序

②取出下一个元素,在已经排序的元素序列中从后向前扫描

③如果该元素(已排序)大于新元素,将该元素移到下一位置

④重复步骤3,直到找到已排序的元素小于或者等于新元素的位置

⑤将新元素插入到该位置后

⑥重复步骤②~⑤

如果比较操作的代价比交换操作大的话,可以采用二分查找法来减少比较操作的数目。该算法可以认为是插入排序的一个变种,称为二分查找插入排序。

2.特点

直接插入排序是一种稳定的排序。对部分有序的数组十分高效,也很适合小规模数组。

3.代码

    public static void insertion_sort( int[] arr ) {
        for( int i=0; i<arr.length-1; i++ ) {   
            for( int j=i+1; j>0; j-- ) {
                if( arr[j-1] <= arr[j] )
                    break;
                int temp = arr[j];
                arr[j] = arr[j-1];
                arr[j-1] = temp;
            }
        }
    }

另一个版本:

    public static void insertion_sort(int[] arr)
    {
        for (int i = 1; i < arr.length; i++ ) {
            int temp = arr[i];
            for (int j = i - 1; j >= 0 && arr[j] > temp; j-- ) {
                arr[j + 1] = arr[j];
            }
            arr[j + 1] = temp;
    }

4.复杂度

①交换次数O(0): 不需要

②比较次数O(n^2): 最好情况是,已经有序,需(n-1)次即可次;最坏情况是,逆序,需n(n-1)/2次

③赋值次数O(n^2):比较操作的次数加上(n-1)次

平均来说插入排序算法复杂度为O(n^2)因而,插入排序不适合对于数据量比较大的排序应用。但是,如果需要排序的数据量很小,例如,量级小于千,那么插入排序还是一个不错的选择。

5.概述

最差时间复杂度 О(n2)

最优时间复杂度 О(n)

平均时间复杂度 О(n2)

最差空间复杂度 总共О(n), 需要辅助空间O(1)

动态图:

技术分享

使用插入排序为一列数字进行排序的过程:

技术分享

冒泡排序

1.原理

它重复地遍历过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。遍历数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。

步凑如下:

①比较相邻的元素。如果第一个比第二个大,就交换他们两个。

②对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。

③针对所有的元素重复以上的步骤,除了最后一个。

④持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

2.特点

尽管这个算法是最简单了解和实现的排序算法之一,但它对于少数元素之外的数列排序是很没有效率的。

3.代码

    public static void bubble_sort(int[] arr) {
        int i, j, temp, len = arr.length;
        for (i = 0; i < len - 1; i++)
            for (j = 0; j < len - 1 - i; j++)
                if (arr[j] > arr[j + 1]) {
                    temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
    }

4.复杂度

①交换次数O(n^2)

②比较次数O(n^2): 可以原地排序。

③赋值次数O(0):不需要,交换就可以了。

冒泡排序是与插入排序拥有相等的运行时间,但是两种算法在需要的交换次数却很大地不同。在最好的情况,冒泡排序需要O(n^2)次交换,而插入排序只要最多O(n)交换。冒泡排序的实现通常会对已经排序好的数列拙劣地运行O(n^2),而插入排序在这个例子只需要O(n)个运算。

5.概述

最差时间复杂度 О(n2)

最优时间复杂度 О(n)

平均时间复杂度 О(n2)

最差空间复杂度 总共О(n), 需要辅助空间O(1)

动态图:

技术分享

希尔排序

1.原理

将数组列在一个表中并对列排序(用插入排序)。重复这过程,不过每次用更长的列来进行。最后整个表就只有一列了。将数组转换至表是为了更好地理解这算法,算法本身仅仅对原数组进行排序(通过增加索引的步长,例如是用i += step_size而不是i++)。

例如,假设有这样一组数[ 13 14 94 33 82 25 59 94 65 23 45 27 73 25 39 10 ],如果我们以步长为5开始进行排序,我们可以通过将这列表放在有5列的表中来更好地描述算法,这样他们就应该看起来是这样:

13 14 94 33 82
25 59 94 65 23
45 27 73 25 39
10

然后我们对每列进行排序:

10 14 73 25 23
13 27 94 33 39
25 59 94 65 82
45

將上述四行数字,依序接在一起时我们得到:[ 10 14 73 25 23 13 27 94 33 39 25 59 94 65 82 45 ].这时10已经移至正确位置了,然后再以3为步长进行排序:

10 14 73
25 23 13
27 94 33
39 25 59
94 65 82
45

排序之后变为:

10 14 13
25 23 33
27 25 59
39 65 73
45 94 82
94

最后以1步长进行排序(此时就是简单的插入排序了)。

2.特点

步长的选择是希尔排序的重要部分。只要最终步长为1任何步长序列都可以工作。算法最开始以一定的步长进行排序。然后会继续以一定步长进行排序,最终算法以步长为1进行排序。当步长为1时,算法变为插入排序,这就保证了数据一定会被排序。

3.代码

    public static void shell_sort(int[] arr) {
        int gap = 1, i, j, len = arr.length;
        int temp;
        while (gap < len / 3)
            gap = gap * 3 + 1; // <O(n^(3/2)) by Knuth,1973>: 1, 4, 13, 40, 121, ...
        for (; gap > 0; gap /= 3)
            for (i = gap; i < len; i++) {
                temp = arr[i];
                for (j = i - gap; j >= 0 && arr[j] > temp; j -= gap)
                    arr[j + gap] = arr[j];
                arr[j + gap] = temp;
            }
    }

4.复杂度

技术分享

5.概述

最差时间复杂度 根据步长序列的不同而不同,最好时为О(n(logn)^2)

最优时间复杂度 O(n)

平均时间复杂度 根据步长序列的不同而不同

最差空间复杂度 О(n)

动态图:

技术分享

算法学习#09--用简单的思维理解选择、插入、冒泡和希尔排序

标签:

原文地址:http://blog.csdn.net/tclxspy/article/details/52120861

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!