数据结构 -- 基本排序算法

算法学习 -- 基本排序算法

 

  算法总述:

    1、冒泡排序

    2、插入排序

    3、选择排序

    4、快速排序

    5、归并排序

    6、希尔排序

    7、堆排序

    8、基数排序

 

  1、冒泡排序算法 

    冒泡排序算法,又称之为相邻交换排序法,就像是水中的泡泡一样,大的泡泡向上浮动,就像是待排序中的最大数在最后一样。 

    算法思路:待排序的序列中,数字之间两两比较,若相邻的元素大小顺序有误,就将其交换,如此,将序列扫描一遍,就能将最大的元素排在后面,一共将会循环排序(n个元素-1)次。

    算法代码:

/**
 * 冒泡排序
 */
public class Demone1 {
    public static void main(String[] args) {
        int[] arrary = new int[]{2,6,1,4,8,3,9,5};
        bubbling(arrary);
    }
    private static void bubbling(int[] arrary) {
        int temp = 0;
        // 一共需要循环扫描 n - 1 次 ,没循环一次将最大的元素放在最后,所以最后的元素就不必在参与比较
        for (int i = arrary.length - 1; i > 0; i--) {
            for (int j = 0; j < i; j++) { // i : 7、6、5、4、3、2、1
                if (arrary[j] > arrary[j + 1]) {
                    temp = arrary[j];
                    arrary[j] = arrary[j + 1];
                    arrary[j + 1] = temp;
                }
            }
            /**
             * 输出每一遍的扫描结果
             */
            printArray(arrary);
        }
    }
    public static void printArray(int[] array) {
        for (int i = 0; i < array.length; i++) {
            System.out.print(array[i] + "\t");
        }
        System.out.println();
    }
}

    算法结果:

 

    问题:由结果可以看出来,前三次,就排序好了,但是还是无脑的走了后面的四次步骤。可见算法还不是很好。

    改进:冒泡算法(二)

    改进的算法思路:就是定义一个变量,用于监控,是否每一次循环扫描是否有数字进行了交换,若是发现已经不需要交换了(即count==0),即退出。

/**
 * 改进版
 */
public class Demone1 {
    public static void main(String[] args) {
        int[] arrary = new int[]{2,6,1,4,8,3,9,5};
        bubbling(arrary);
    }
    private static void bubbling(int[] arrary) {
        int temp = 0;
        // 一共需要循环扫描 n - 1 次 ,没循环一次将最大的元素放在最后,所以最后的元素就不必在参与比较
        for (int i = arrary.length - 1; i > 0; i--) {
            int count = 0;//记录交换的次数,因为只有需要交换才是值得花时间的,若是发现已经不需要就直接退出循环扫描。
            for (int j = 0; j < i; j++) { // i : 7、6、5、4、3、2、1
                if (arrary[j] > arrary[j + 1]) {
                    temp = arrary[j];
                    arrary[j] = arrary[j + 1];
                    arrary[j + 1] = temp;
                    count++;
                }
            }
            /**
             * 输出每一遍的扫描结果
             */
            if (count == 0) {
                break;
            }
            printArray(arrary);
        }
    }
    public static void printArray(int[] array) {
        for (int i = 0; i < array.length; i++) {
            System.out.print(array[i] + "\t");
        }
        System.out.println();
    }
}

    算法结果:

    

    算法分析(时空复杂度):

    冒泡排序中,n 个元素需要进行 n-1 次扫描。

    最好情况下:就是一边扫描过去后,不需要交换,只进行了 n-1 次比较,时间复杂度为 O(n)

    最坏情况下和平均情况下:需要进行 (n - 1) + (n - 2) + (n - 3) + ... + 3 + 2 + 1 = n (n - 1) / 2  即时间复杂度 O(n^2)

    算法稳定性:当两个数字相同时,不会进行交换顺序的,所以就不会出现算法不稳定性。

 

  2、插入排序算法

    算法思路:插入排序,就是将数组中的元素逐一与已经排好序的数列进行比较,然后放在适当的位置。考虑的角度,可以是由后往前考虑,前面是已经排好序的数列,后面是还未排序的数组。角度刚好与选择排序的角度相反,选择排序的角度是由前往后,前面是已经排好的顺序,后面是待排序的数组。

    算法代码:

/**
 * 插入排序
 */
public class Demone2 {
    public static void main(String[] args) {
        int[] arrary = new int[]{2,6,1,4,8,3,9,5};
        insertSort(arrary);
    }
    private static void insertSort(int[] arrary) {
        // 需要循环 n - 1 次 ,从第2个元素开始,因为第一个元素没有必要,无意义。
        for (int i = 1; i < arrary.length; i++) {
            int temp = arrary[i]; // 暂存数据
            int j = i - 1; // 得到当前元素的前一个元素的下标,用于后期可以循环后移数据
            while (j >= 0 && temp < arrary[j]) {
                arrary[j + 1] = arrary[j];
                j--;
            }
            /**
             * 最小的元素放在适当的位置,前面的 j-- 将会多减一个1,所以在这加上1就是适当的位置,例如:2、6、4 ,4就会放在2、6之间
             * j 会减到 0,但是应该放在的位置是 1 则需要加 1
             */
            arrary[j + 1] = temp;
        }
        printArray(arrary);
    }
    public static void printArray(int[] array) {
        for (int i = 0; i < array.length; i++) {
            System.out.print(array[i] + "\t");
        }
        System.out.println();
    }
}

    算法结果:

    算法分析(时空复杂度):

    最好情况下:就是一边扫描过去后,不需要交换,只进行了 n-1 次比较,时间复杂度为 O(n)

    最坏情况下与平均情况下:需要进行 (n - 1) + (n - 2) + (n - 3) + ... + 3 + 2 + 1 = n (n - 1) / 2  即时间复杂度 O(n^2)

    算法稳定性:算法稳定,因为只有小于才会交换,而两个数相同时,不会交换,则算法稳定。

    空间复杂度:只需要使用变量就可以,则空间复杂度最佳。

 

  3、选择排序算法

    算法思路:选择排序就是从未排序的数字序列中,挑选一个最小的数,与当前的元素进行比较,若当前的数大于最小的数,就进行交换,反之就不交换,当前的元素向前移动。

    算法代码:

/**
 * 选择排序
 */
public class Demone3 {
    public static void main(String[] args) {
        int[] arrary = new int[]{2, 6, 1, 4, 8, 3, 9, 5};
        choiceSort(arrary);
    }
    private static void choiceSort(int[] arrary) {

        /**
         * 循环 n - 1 次,最后一个元素不需要循环。
         */
        int minNum = 0;
        int index = 0;
        for (int i = 0; i < arrary.length - 1; i++) {
            minNum = arrary[i];//记录最小值,与后边的数据进行比较
            index = i;// 记录当前的元素的下标
            for (int j = i + 1; j < arrary.length; j++) {
                if (arrary[j] < minNum) {
                    minNum = arrary[j];
                    index = j;
                }
            }
            int temp = arrary[index];
            arrary[index] = arrary[i];
            arrary[i] = temp;
            printArray(arrary);
        }
    }
    public static void printArray(int[] array) {
        for (int i = 0; i < array.length; i++) {
            System.out.print(array[i] + "\t");
        }
        System.out.println();
    }
}

    算法结果:

    算法分析(时空复杂度):

    最好情况下、最坏情况下与平均情况下:(由于都是需要扫描每一个元素,并且还要扫描该元素后面的所有的元素,比较大小)都是需要进行比较 (n - 1) + (n - 2) + (n - 3) + ... + 3 + 2 + 1 = n (n - 1) / 2。时间复杂度:O(n^2)

    算法稳定性:由于该算法的思想是,将当前元素后的未排序的元素进行选择比较出最下的,与元素交换,数据的排列有可能会改变。比如:他是扫描未排序的全部的元素比较大小,现在有两个7(前)、7(后),最后将7(后)添加到了头,所以就会出现算法的不稳定性。

    空间复杂度:由于只是使用了一个额外的空间,空间复杂度为:O(1),为最佳。

 

  4、快速排序算法

 

    算法思路:

    算法代码:

    算法分析(时空复杂度):

 

  5、归并排序算法

 

    算法思路:

    算法代码:

    算法分析(时空复杂度):

 

  6、希尔排序算法

 

    算法思路:

    算法代码:

    算法分析(时空复杂度):

 

  7、堆排序算法

 

    算法思路:

    算法代码:

    算法分析(时空复杂度):

 

  8、基数排序算法

 

    算法思路:

    算法代码:

    算法分析(时空复杂度):

 

posted @ 2021-10-27 15:35  心向未来  Views(14)  Comments(0)    收藏  举报