[笔记]算法复习笔记---排序算法(桶排序、冒泡排序)

对于一个算法的性能来说,除了时间复杂度,还有空间复杂度,稳定性等一系列指标。我平常说的算法复杂度可分为两部分:时间复杂度和空间复杂度。

从这两个维度综合分析,可以知道一个算法的好坏,然后才可以针对这个算法进行优化。

一、桶排序

桶排序也叫箱排序,它简单而快速。其中的主要思想是我们首先需要知道所有待排序元素的范围,然后需要有在这个范围内的同样数量的桶,接着把元素放入对应的桶,最后按顺序输出。

但是,当待排序元素很多大的时候,比如100万个,我们要设置100万个桶吗,当然不可能。在很多时候我们会把桶排序与其他排序相结合,一个桶里有多个元素,那这岂不是跟散列表很相似呢。

讲了这么多,是不是感觉很简单呢,跟我来实现一个简单的桶排序吧。

public class BubbleSort {

    private int[] array;



    public BubbleSort(int[] array) {
        this.array = array;
    }

    /**
     * 从小到大
     */
    public void sort() {
        int length = array.length;
        if (length > 0) {
            for (int i = 1; i < length; i++) {
                for (int j = 0; j < length - i; j++) {
                    if (array[j] >  array [j + 1 ]) {
                        int temp = array[j];
                        array[j] = array[j + 1];
                        array[j + 1] = temp;
                    }
                }
            }
        }
    }

    /**
     * 从大到小
     */

    public void sort2() {
        int length = array.length;
        if (length > 0) {
            for (int i = length - 1; i > 0; i--) {
                for (int j = length - 1; j > length - 1 -i; j--) {
                    if (array[j] >  array [j - 1 ]) {
                        int temp = array[j];
                        array[j] = array[j - 1];
                        array[j - 1] = temp;
                    }
                }
            }
        }
    }

    public void print() {
        for (int i = 0; i < array.length; i++) {
            System.out.println(array[i]);
        }
    }   
}
public static void testBucketSort() {
        int[] array = {5, 9, 1, 9, 5, 8, 4, 3, 2, 9, 15, 7, 0};
        BucketSort bucketSort = new BucketSort(16, array);
        bucketSort.sort();
        bucketSort.print();
    }

进行桶排序的时候需要遍历一遍所有的待排序元素,然后依次放入指定位置。如果加上输出排序的时间,那么需要遍历所有的桶,时间复杂度就是O(n+m),其中n为待排序元素的个数,m为桶的个数,排序速度没毛病,可就是空间消耗来说太多了,特别是当元素跨度太大的时候,空间浪费就越多,元素分布得太分散,当这种情况的时候就不适合桶排序算法。

二、冒泡排序

冒泡排序是我接触的第一个排序算法,那时候还是大一,在学C语言。冒泡排序也是一个比较简单的排序,它重复得走访要排序的数列,一次比较两个元素,如果顺序不对,则进行交换,一直重复这样的步骤,直到找到没有交换的元素为止。

冒泡排序的原理

首先,有一个数组,里面存储着待排序的元素,我们需要把元素从大到小排序,然后我们从尾部到头开始下面的步骤:

  1. 从尾部开始比较相邻的两个元素,如果尾部元素比前面的大,就交换两个元素。
  2. 然后向前面对每个相邻的元素做这样的比较,交换,然后当比较到头部的时候,第一个元素就是最大的元素。
  3. 重新从尾部开始第1、2步骤的操作,除了前面已经排好的元素。
  4. 继续对越来越少的数据进行比较,交换,直到没有可以比较的数据为止,排序就完成了。

当然,我这里说的是从大到小排序,当需要从小到大排序的时候,从头部到尾部进行操作即可。
下面,我们一起来实现这个冒泡排序算法。

public class BubbleSort {

    private int[] array;



    public BubbleSort(int[] array) {
        this.array = array;
    }

    /**
     * 从小到大
     */
    public void sort() {
        int length = array.length;
        if (length > 0) {
            for (int i = 1; i < length; i++) {
                for (int j = 0; j < length - i; j++) {
                    if (array[j] >  array [j + 1 ]) {
                        int temp = array[j];
                        array[j] = array[j + 1];
                        array[j + 1] = temp;
                    }
                }
            }
        }
    }

    /**
     * 从大到小
     */

    public void sort2() {
        int length = array.length;
        if (length > 0) {
            for (int i = length - 1; i > 0; i--) {
                for (int j = length - 1; j > length - 1 -i; j--) {
                    if (array[j] >  array [j - 1 ]) {
                        int temp = array[j];
                        array[j] = array[j - 1];
                        array[j - 1] = temp;
                    }
                }
            }
        }
    }

    public void print() {
        for (int i = 0; i < array.length; i++) {
            System.out.println(array[i]);
        }
    }   
}
public static void testBubbleSort() {
        int[] array = {5, 9, 1, 6, 5, 8, 4, 3, 2, 19, 15, 7, 0};
        BubbleSort bubbleSort = new BubbleSort(array);
        bubbleSort.sort2();
        bubbleSort.print();
    }

冒泡排序算法每轮排序使一个元素排到一端,最终进行n-1次这样的排序(n为待排序的数列的的长度),而在每轮排序中都需要对相邻的两个元素进行比较,最坏的情况下,每次比较都需要交换位置,所以这里的时间复杂度为O()。其实冒泡排序在最好的情况下,可以达到O(n),这当然是在待排序数列有序的情况下,但是这种情况很少,所以冒泡排序的平均时间复杂度为O()。

当然,冒泡排序还是可以优化的。

1. 增加标志位。增加一个标志位来标记每趟排序中最后一次交换的位置,由于这个元素之后的位置已经不用交换了,说明后面的元素都完成了排序,所以下次就可以直接从尾部比较到这个标记的元素。

2. 一次冒两个元素。每一趟排序都是把最大的元素冒上去,把最小的元素沉下去。排序次数可以减少一半。

你可能感兴趣的:(数据结构与算法设计)