排序I

来源:互联网 发布:七月算法视频pan 编辑:程序博客网 时间:2024/06/04 00:35

冒泡排序

冒泡排序的基本思想是两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止。

标准代码

package com.weixuan.sort.bubble;public class BubbleSort {    public static void bubbleSort(int[] data) {        for (int i = 0; i < data.length; i++) {            for (int j = data.length - 2; j >= i; j--) {                if (data[j] > data[j + 1])                    swap(data, j, j + 1);            }            System.out.println("第 " + (i+1) + " 次");            printArray(data);            System.out.println("\n");        }    }    private static void swap(int[] data, int j, int i) {        if (data == null || data.length <= 0)            return;        int temp = data[j];        data[j] = data[i];        data[i] = temp;    }    public static void printArray(int[] array) {        for (int i = 0; i < array.length; i++)            System.out.print(array[i] + "\t");    }}

过程详解 – {9,1,5,8,3,7,4,6,2}

第一趟:i==0,j = 8,j从j = 8 反循环遍历到j = 0,逐个比较,直到找到最小值放在i=0的位置上。

2 < 6 : 9, 1, 5, 8, 3, 7, 4, 2, 6 j = 8
2 < 4 : 9, 1, 5, 8, 3, 7, 2, 4, 6 j = 7
2 < 7 : 9, 1, 5, 8, 3, 2, 7, 4, 6 j = 6
2 < 3 : 9, 1, 5, 8, 2, 3, 7, 4, 6 j = 5
2 < 8 : 9, 1, 5, 2, 8, 3, 7, 4, 6 j = 4
2 < 5 : 9, 1, 2, 5, 8, 3, 7, 4, 6 j = 3
1 < 2<不交换> : 9, 1, 2, 5, 8, 3, 7, 4, 6 j = 2
1 < 9 : 1, 9, 2, 5, 8, 3, 7, 4, 6 j = 1

第一趟的结果就是:

1, 9, 2, 5, 8, 3, 7, 4, 6

第二趟:i==1,j = 8,j从j = 8 反循环遍历到j = 1,逐个比较,直到找到次最小值放在i=1的位置上。

4 < 6<不交换> : 1, 9, 2, 5, 8, 3, 7, 4, 6 j = 8
4 < 7 : 1, 9, 2, 5, 8, 3, 4, 7, 6 j = 7
3 < 4<不交换> : 1, 9, 2, 5, 8, 3, 4, 7, 6 j = 6
3 < 8 : 1, 9, 2, 5, 3, 8, 4, 7, 6 j = 5
3 < 5 : 1, 9, 2, 3, 5, 8, 7, 4, 6 j = 4
2 < 3<不交换> : 1, 9, 2, 3, 5, 8, 7, 4, 6 j = 2
2 < 9 : 1, 2, 9, 3, 5, 8, 7, 4, 6 j = 2
1 < 2<不交换> : 1, 2, 9, 3, 5, 8, 7, 4, 6 j = 1

第二趟的结果就是:

1, 2, 9, 3, 5, 8, 7, 4, 6

后面的同理

第 1 次1   9   2   5   8   3   7   4   6   第 2 次1   2   9   3   5   8   4   7   6   第 3 次1   2   3   9   4   5   8   6   7   第 4 次1   2   3   4   9   5   6   8   7   第 5 次1   2   3   4   5   9   6   7   8   第 6 次1   2   3   4   5   6   9   7   8   第 7 次1   2   3   4   5   6   7   9   8   第 8 次1   2   3   4   5   6   7   8   9   第 9 次1   2   3   4   5   6   7   8   9   

可以优化的地方

假设有序列{2,1,3,4,5,6,7,8,9},除了2和1需要交换之外,其他的已经有序了,无需再次循环。

优化之前

输出

第 1 次1   2   3   4   5   6   7   8   9   第 2 次1   2   3   4   5   6   7   8   9   第 3 次1   2   3   4   5   6   7   8   9   第 4 次1   2   3   4   5   6   7   8   9   第 5 次1   2   3   4   5   6   7   8   9   第 6 次1   2   3   4   5   6   7   8   9   第 7 次1   2   3   4   5   6   7   8   9   第 8 次1   2   3   4   5   6   7   8   9   第 9 次1   2   3   4   5   6   7   8   9   

可以看到,从第二次开始就是已经有序了,但是这个傻瓜式的程序还循环了7次!!!

优化的代码

    public static void bubbleSortSuper(int[] data) {        boolean flag = true;        for (int i = 0; i < data.length && flag; i++) {            flag = false;/*初始为false*/            for (int j = data.length - 2; j >= i; j--) {                if (data[j] > data[j + 1]) {                    swap(data, j, j + 1);                    flag = true; // 有数据交换,flag = true                }            }            System.out.println("第 " + (i + 1) + " 次");            printArray(data);            System.out.println("\n");        }    }

输出,只循环了两次

第 1 次1   2   3   4   5   6   7   8   9   第 2 次1   2   3   4   5   6   7   8   9

性能分析 序列长度为N

最好的情况:序列本身有序,那么就是N1次比较,没有交换,时间复杂度是O(N)

最差的情况:序列逆序,需要比较

i=0n1(i1)=1+2+3+...+(n1)=n(n1)2

基本也是这个数量级的交换,所以时间复杂度是O(N2)

快速排序

基本思想:每一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录关键字小,然后分别对这两部分进行排序,打到整个序列有序的目的。

package com.weixuan.sort.quicksort;public class QuickSort {    private static void swap(int[] data, int j, int i) {        if (data == null || data.length <= 0)            return;        int temp = data[j];        data[j] = data[i];        data[i] = temp;    }    public static void printArray(int[] array) {        for (int i = 0; i < array.length; i++)            System.out.print(array[i] + "\t");    }    private static int partition(int[] data, int low, int high) {        int pivot = data[low];// 轴值        while (low < high) {            while (low < high && data[high] >= pivot)                high--;            // 交换            swap(data, low, high);            while (low < high && data[low] <= pivot)                low++;            // 交换            swap(data, low, high);        }        System.out.println("------");        printArray(data);        System.out.println("------");        return low;    }    private static void quickSort(int[] data, int low, int high) {        if (low < high) {            int k = partition(data, low, high);            quickSort(data, low, k - 1);            quickSort(data, k + 1, high);        }    }    public static void quickSort(int[] data) {        quickSort(data, 0, data.length - 1);    }}

排序过程 – {50,10,90,30,70,40,80,60,20}

第一趟:
初始pivot = 50,low = 0,high = 8,data[low] = 50,data[high] = 20

data[high] = 20 < pivot ,交换,但是low和high没有变,直接跳出循环。
20,10,90,30,70,40,80,60,50 [此时 low = 0,high = 8]

data[low] = 20 < pivot,low++,只到low = 2,data[low] = 90 >pivot,退出循环,交换
20,10,50,30,70,40,80,60,90 [此时 low = 2,high = 8]

low = 2 < high = 8 ,继续大循环
初始pivot = 50,low = 2,high = 8

data[high]=90 > pivot,high–,只到high = 5,data[high] = 40 < pivot,跳出循环,交换
20,10,40,30,70,50,80,60,90 [此时 low = 2,high = 5]

data[low] = 40 < pivot,low++,只到low = 4,data[low] = 70 > pivot,跳出循环,交换
20,10,40,30,50,70,80,60,90 [此时 low = 4,high = 5]

low = 4 < high = 5 ,继续大循环

low = high = 4,退出循环,

返回low = 4

第一趟的结果就是

[20,10,40,30,50,70,80,60,90]

然后就是递归调用

对[20,10,40,30] 和 [70,80,60,90]分别执行第一趟的操作。

性能分析

快速排序的事件性能取决于快速排序递归的深度,上述的递归过程第一个关键字是50,正好是待排序序列的中间值,因此整个树是平衡的。此时性能最好。

在最优情况下,长度为n的序列递归的深度是O(log2N)+1,O(log2N)向下取整。即仅需递归O(log2N)次,需要时间为T(n)的话,第一次partition对整个数组扫描一遍,做n次比较,然后一分为二,各自需要T(n/2)的时间。

也就是说,在最优情况下,时间复杂度为O(nlogn),空间复杂度是O(logN)

最差情况下,序列为有序或者逆序,此时需要n-1次递归调用,第i次划分需要n-i次比较才能找到第i个记录,因此比较的次数是

i=0n1(Ni)=1+2+3+...+(n1)=n(n1)2

时间复杂度是O(N2),空间复杂度是O(N)

由于快速排序的关键字比较是跳跃进行的,所以是不稳定的排序方法。

快速排序优化

快排最好情况是第一个轴值就是整个序列的中间值,也就是说跨拍的性能瓶颈在与pivot在序列中的位置。

那么可以在low与hight之间随机选择一个数,随机选取轴值法。这样有些碰运气的感觉。

更优化的是三数取中法,即取三个关键字先进行排序,将中间数作为轴值,一般是取左端,右端和中间三个数。

  1. 选择合适的轴值
    private static int partition(int[] data, int low, int high) {        //int pivot = data[low];// 轴值        int pivot = medianOfThree(data,low,high);        while (low < high) {            while (low < high && data[high] >= pivot)                high--;            // 交换            swap(data, low, high);            while (low < high && data[low] <= pivot)                low++;            // 交换            swap(data, low, high);        }        System.out.println("------");        printArray(data);        System.out.println("------");        return low;    }    private static void quickSort(int[] data, int low, int high) {        if (low < high) {            int k = partition(data, low, high);            quickSort(data, low, k - 1);            quickSort(data, k + 1, high);        }    }    public static void quickSort(int[] data) {        quickSort(data, 0, data.length - 1);    }    private static int medianOfThree(int[] data, int low, int high) {        int pivot;        int media = low + (high - low) / 2;        // 保证左端较小        if (data[low] > data[high])            swap(data, low, high);        // 保证中间较小        if (data[media] > data[high])            swap(data, high, media);        // 保证左端较小        if (data[media] > data[low])            swap(data, media, low);        pivot = data[low];        return pivot;    }
  1. 避免不必要的交换
private static void quickSort(int[] data, int low, int high) {        if (low < high) {            // int k = partition(data, low, high);            int k = partitionSuper(data, low, high);            quickSort(data, low, k - 1);            quickSort(data, k + 1, high);        }    }    public static void quickSort(int[] data) {        quickSort(data, 0, data.length - 1);    }    private static int medianOfThree(int[] data, int low, int high) {        int pivot;        int media = low + (high - low) / 2;        // 保证左端较小        if (data[low] > data[high])            swap(data, low, high);        // 保证中间较小        if (data[media] > data[high])            swap(data, high, media);        // 保证左端较小        if (data[media] > data[low])            swap(data, media, low);        pivot = data[low];        return pivot;    }    private static int partitionSuper(int[] data, int low, int high) {        int pivot = medianOfThree(data, low, high);        while (low < high) {            while (low < high && data[high] >= pivot)                high--;            // 将交换改为替换            // swap(data, low, high);            data[low] = data[high];            while (low < high && data[low] <= pivot)                low++;            // 将交换改为替换            // swap(data, low, high);            data[high] = data[low];        }        return low;    }

选择排序

简单选择排序的基本思想是每一趟在Ni+1个记录中选取最小的记录作为有序序列的第i个记录。

package com.weixuan.sort.select;public class SelectSort {    private static void swap(int[] data, int j, int i) {        if (data == null || data.length <= 0)            return;        int temp = data[j];        data[j] = data[i];        data[i] = temp;    }    public static void printArray(int[] array) {        for (int i = 0; i < array.length; i++)            System.out.print(array[i] + "\t");    }    public static void selectSort(int[] data) {        int minIndex;        for (int i = 0; i < data.length; i++) {            minIndex = i;            for (int j = i + 1; j < data.length; j++) {                if (data[minIndex] > data[j])                    minIndex = j;            }            if (i != minIndex) //找到最小值                swap(data, i, minIndex);        }    }}

过程说明 – {9,1,5,8,3,7,4,6,2}

i = 0,minIndex = 0,j = 1
data[minIndex] > data[1],minIndex = 1, (比较8次)
minIndex = 1,j = 2…一直循环到j = 8
1,9,5,8,3,7,4,6,2

i = 1,minIndex = 1,j = 2
在剩余的部分找最小值,交换 (比较7次)
1,2,5,8,3,7,4,6,9

i = 2,minIndex = 1,j = 3
在剩余的部分找最小值,交换
1,2,3,8,5,7,4,6,9

i = 3,minIndex = 1,j = 4
在剩余的部分找最小值,交换
1,2,3,4,5,7,8,6,9

i = 4,minIndex = 1,j = 5
在剩余的部分找最小值,交换
1,2,3,4,5,6,8,7,9

i = 5,minIndex = 1,j = 6
在剩余的部分找最小值,交换
1,2,3,4,5,6,7,8,9

i = 6,minIndex = 1,j = 7
在剩余的部分找最小值,交换
1,2,3,4,5,6,7,8,9

i = 7,minIndex = 1,j = 1
在剩余的部分找最小值,交换
1,2,3,4,5,6,7,8,9

i = 8,minIndex = 1,j = 1
在剩余的部分找最小值,交换
1,2,3,4,5,6,7,8,9

性能分析

  1. 无论最好最差情况,比较次数是一样多。第i趟需要进行n-i次关键字比较,总的比较次数
    i=0n1(Ni)=1+2+3+...+(n1)=n(n1)2
  2. 交换次数,最好时,本身有序,交换0次,最差的时候,逆序,交换n-i次
  3. 时间复杂度是O(N2)
0 0
原创粉丝点击