zoukankan      html  css  js  c++  java
  • Java 与常用排序算法

    Comparison

     

    • 时间复杂度
    • 空间复杂度

        算法在计算机上所占用的存储空间,包括存储算法本身所占用的存储空间、算法的输入输出数据所占用的存储空间和算法在运行过程中临时占用的存储空间这三个方面。

        但在评估一个算法的优良性的时候,前两个基本是固定的,只有算法运行是临时占用的存储空间才会随着数据量的增大而有较大影响。因此,一般以程序运行时占用的临时存储大小作为评估指标。

       

    快速排序 (Divide and Conquer)

     1     public void quickSort(int[] arr, int l, int r) {
     2         if (l < r) {
     3             int p = partition(arr, l, r);  // divide and conquer
     4             quickSort(arr, l, p - 1);
     5             quickSort(arr, p + 1, r);
     6         }
     7     }
     8 
     9     // select the first element as pivot
    10     // use do while loop
    11     public int partition(int[] arr, int l, int r) {
    12         int i, j, pivot, tmp;
    13         pivot = arr[l];
    14         i = l;
    15         j = r + 1;
    16 
    17         do {
    18             for (i++; i < r && arr[i] <= pivot; i++) ;// do while loop, less than or equal to pivot
    19             for (j--; j > l && arr[j] > pivot; j--) ;// do while loop, greater than pivot
    20 
    21             // swap arr i,j
    22             tmp = arr[i];
    23             arr[i] = arr[j];
    24             arr[j] = tmp;
    25         } while (i < j);
    26         if (i > j) {  // cross line, swap back
    27             tmp = arr[i];
    28             arr[i] = arr[j];
    29             arr[j] = tmp;
    30         }
    31 
    32         arr[l] = arr[j];  // place the pivot to appropriate position
    33         arr[j] = pivot;
    34 
    35         return j;
    36     }

    Best: O(nlogn); Worst: O(n^2)  Average: O(nlogn)   1.38nlogn

    归并排序 (Divide and Conquer)

     1    void mergeSort(int[] arr, int l, int r) {
     2         if (l < r) {
     3             int m = l + (r - l) / 2;
     4             mergeSort(arr, l, m);      // divide and conquer
     5             mergeSort(arr, m + 1, r);
     6             merge(arr, l, m, r);
     7         }
     8     }
     9 
    10     void merge(int[] arr, int l, int m, int r) {
    11         int i, j, k, n1, n2;
    12         n1 = m - l + 1;   // size of the left part arr
    13         n2 = r - m;        // size of the right part arr
    14 
    15         int[] L = new int[n1];  // tmp arrays
    16         int[] R = new int[n2];
    17 
    18         // copy elements to the tmp arrays
    19         for (i = 0; i < n1; i++) {
    20             L[i] = arr[l + i];
    21         }
    22         for (j = 0; j < n2; j++) {
    23             R[j] = arr[m + 1 + j];
    24         }
    25 
    26         i = j = 0;
    27         k = l;  // point at the beginning position
    28 
    29         // Copy smaller elements back to arr (overwrite)
    30         while (i < n1 && j < n2) {
    31             if (L[i] <= R[j]) {
    32                 arr[k++] = L[i++];
    33             } else {
    34                 arr[k++] = R[j++];
    35             }
    36         }
    37 
    38         // copy the remaining elements
    39         while (i < n1) {
    40             arr[k++] = L[i++];
    41         }
    42         while (j < n2) {
    43             arr[k++] = R[j++];
    44         }
    45     }

    always: O(nlogn)

    堆排序 From wikipedia  (Transform and Conquer)

    注意,建堆过程可能与代码中不太一样,代码中数组已存在,图示中是逐渐插入过程。

    基本思想: 

      创建堆(-->maxHeapify) --> 反复的调用del_max()函数获取最大值

        排序具体过程:  

      1. 建立一个堆H[0..n-1]
      2. 把堆首(最大值)和堆尾互换
      3. 把堆的尺寸缩小1,并调用shift_down(0),目的是把新的数组顶端数据调整到相应位置
      4. 重复步骤2,直到堆的尺寸为1
      1 public class HeapSort {
      2     private static int[] sort = new int[]{1,0,10,20,3,5,6,4,9,8,12,17,34,11};
      3     public static void main(String[] args) {
      4         buildMaxHeapify(sort);    // build a max heap
      5         heapSort(sort);             // sort the array
      6         print(sort);
      7     }
      8 
      9     private static void buildMaxHeapify(int[] data){
     10         //没有子节点的才需要创建最大堆,从最后一个的父节点开始
     11         int startIndex = getParentIndex(data.length - 1);
     12         //从尾端开始创建最大堆,每次都是正确的堆
     13         for (int i = startIndex; i >= 0; i--) {
     14             maxHeapify(data, data.length, i);
     15         }
     16     }
     17 
     18     /**
     19      * 创建最大堆
     20      * @param data
     21      * @param heapSize需要创建最大堆的大小,一般在sort的时候用到,因为最多值放在末尾,末尾就不再归入最大堆了
     22      * @param index当前需要创建最大堆的位置
     23      */
     24     private static void maxHeapify(int[] data, int heapSize, int index){
     25         // 当前点与左右子节点比较
     26         int left = getChildLeftIndex(index);
     27         int right = getChildRightIndex(index);
     28 
     29         int largest = index;
     30         if (left < heapSize && data[index] < data[left]) {
     31             largest = left;
     32         }
     33         if (right < heapSize && data[largest] < data[right]) {
     34             largest = right;
     35         }
     36         //得到最大值后可能需要交换,如果交换了,其子节点可能就不是最大堆了,需要重新调整
     37         if (largest != index) {
     38             int temp = data[index];
     39             data[index] = data[largest];
     40             data[largest] = temp;
     41             maxHeapify(data, heapSize, largest);    // recursive to the root node
     42         }
     43     }
     44 
     45     /**
     46      * 排序,最大值放在末尾,data虽然是最大堆,在排序后就成了递增的
     47      * @param data
     48      */
     49     private static void heapSort(int[] data) {
     50         //末尾与头交换,交换后调整最大堆
     51         for (int i = data.length - 1; i > 0; i--) {     // i--, ignore the last one element for length i
     52             int temp = data[0];
     53             data[0] = data[i];      // put it to the end
     54             data[i] = temp;
     55             maxHeapify(data, i, 0);
     56         }
     57     }
     58 
     59     /**
     60      * 父节点位置
     61      * @param current
     62      * @return
     63      */
     64     private static int getParentIndex(int current){
     65         return (current - 1) >> 1;         // shift one bit to the right, equals to (current -1) / 2
     66     }
     67 
     68     /**
     69      * 左子节点position注意括号,加法优先级更高
     70      * @param current
     71      * @return
     72      */
     73     private static int getChildLeftIndex(int current){
     74         return (current << 1) + 1;
     75     }
     76 
     77     /**
     78      * 右子节点position
     79      * @param current
     80      * @return
     81      */
     82     private static int getChildRightIndex(int current){
     83         return (current << 1) + 2;
     84     }
     85 
     86     private static void print(int[] data){
     87         int pre = -2;
     88         for (int i = 0; i < data.length; i++) {
     89             if (pre < (int)getLog(i+1)) {
     90                 pre = (int)getLog(i+1);
     91                 System.out.println();
     92             }
     93             System.out.print(data[i] + " |");
     94         }
     95     }
     96 
     97     /**
     98      * 以2为底的对数
     99      * @param param
    100      * @return
    101      */
    102     private static double getLog(double param){
    103         return Math.log(param)/Math.log(2);
    104     }
    105 }

    avg: O(nlogn)  <= 2nlogn   在随机文件上时间测试的结果显示heapsort比快速排序要慢,但是可以比得上mergeSort. (来源于算法设计与分析基础 2rd Edition P228)

    选择排序

     1     void selectSort(int[] arr){
     2         int min;
     3         for(int i = 0;i<arr.length-1;i++){
     4             min = i;
     5             for(int j=i;j<arr.length;j++){
     6                 if(arr[min] > arr[j]){         // find the smallest elements
     7                     min = j;
     8                 }
     9             }
    10             int tmp = arr[min];
    11             arr[min] = arr[i];
    12             arr[i] = tmp;
    13         }
    14     }

    Best: O(n^2); Worst: O(n^2) Average: O(n^2)

    冒泡排序

        void bubbleSort(int[] arr){
            for(int i=0;i<arr.length;i++){
                for(int j = arr.length-1; j > i; j--){
                    if(arr[j] < arr[j-1]){    // find the smallest through bubble
                        int tmp = arr[j];
                        arr[j] = arr[j-1];
                        arr[j-1] = tmp;
                    }
                }
            }
        }

    Best: O(n^2); Worst: O(n^2) Average: O(n^2)

    此代码实现的最佳时间消耗 O(n^2), 若要使最佳情况时间开销达到O(n),可以设置一个sentinel实现:当不发生交换的时候就break退出,完成了排序。

    插入排序

     1     void insertSort(int[] arr) {
     2         if (arr.length < 2) {
     3             return;
     4         }
     5 
     6         int i, j;
     7         int temp;
     8         for (i = 1; i < arr.length; i++) {
     9             temp = arr[i];
    10             for (j = i - 1; j >= 0 && arr[j] > temp; j--) {  // in-place
    11                 arr[j + 1] = arr[j];    // shift
    12             }
    13             arr[j + 1] = temp;
    14         }
    15     }

    Best: O(n); Worst: O(n^2) Average: O(n^2)

    Java工具类排序 

    java.util.Arrays.sort(arr);
    •  The sorting algorithm is a Dual-Pivot Quicksort by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. 比上面的快速排序更快。

    计算Java程序运行时间:

    1 long startTime = System.nanoTime();
    2 //code
    3 long endTime = System.nanoTime();
    4 System.out.println("Took "+(endTime - startTime) + " ns"); 

     Test It:

     1 public static void main(String[] args) {
     2         int arr[] = {1, 3, 1, 8, 4, 8,3,23,2};
     3         Main main = new Main();
     4         long startTime = System.nanoTime();
     5 //        main.quickSort(arr, 0, arr.length - 1);
     6 //        main.selectSort(arr);
     7 //        main.insertSort(arr);
     8 //        main.bubbleSort(arr);
     9 
    10 //code
    11         long endTime = System.nanoTime();
    12         System.out.println("Took "+(endTime - startTime) + " ns");
    13         for (int a : arr) {
    14             System.out.println(a);
    15         }
    16     }
  • 相关阅读:
    Requests发送带cookies请求
    Python3 + requests + unittest接口测试
    「完结篇」网络爬虫+实时监控+推送微信
    「爬虫」从某网站爬取数据
    定时从某网站爬取压缩包
    如何转载文章...............
    数据库连接远程服务器报错
    记录常用的Java方法
    链接服务器 不同服务器查询,插入数据
    【学习笔记】树状数组
  • 原文地址:https://www.cnblogs.com/7explore-share/p/5918419.html
Copyright © 2011-2022 走看看