• Sorting Algorithms Overview


      Time Complexity of an algorithm is usually estimated as the asymptotic number of elementary operations with respect to an input size. When it comes to comparison-based sorting algorithms, the so-called elementary operation is usually referred to the comparison of key values.

    1. Comparison-Based Sorting Algorithms

      Comparison-based sorting algorithms have a lower bound of time complexity as O(n*log n). Here I shall provide a Java program involving following sorting algorithms:
      (1)  Selection Sort:  unstable and of quadratic time complexity

      (2)  Insertion Sort:  stable and of quadratic time complexity

      (3)  Binary Insertion Sort:  stable and of O(n*log n) time complexity in terms of comparisons

      (4)  Quick Sort:  unstable and of O(n*log n) average time as long as pivot is randomly chosen

      (5)  Merge Sort:  stable and of O(n*log n) worst-case time complexity

      (6)  Heap Sort:  unstable and of O(n*log n) worst-case time complexity

      1 class Array<T extends Comparable> {
      2     private T[] items;        // data of array items
      3     private int len;            // current length
      4     private int size;           // size of space
      5     
      6     public Array(int size) {
      7         if (size<=0) {
      8             throw new RuntimeException("Illegal Initial Size");
      9         } else {
     10             this.size = size;
     11             items = (T[]) new Comparable[size];
     12         }
     13     }
     14     public void append(T item) {
     15         // Insert a new item in items[len]
     16         if (len==size) {
     17             doubleSize();
     18         }
     19         items[len++] = item;
     20     }
     21     private void doubleSize() {
     22         // Double the space size when it's filled up
     23         if ((size<<1)<0) {
     24             throw new RuntimeException("Size Expansion Failed");
     25         } else {
     26             T[] tmp = items;
     27             items = (T[]) new Comparable[size<<1];
     28             for (int i=0;i<len;i++) {
     29                 items[i] = tmp[i];
     30             }
     31             size <<= 1;
     32         }
     33     }
     34     public void selectSort() {
     35         // Implement Selection Sort Algorithm
     36         for (int i=0;i<len-1;i++) {
     37             int idx = i;
     38             T key = items[idx];
     39             for (int j=i+1;j<len;j++) {
     40                 if (items[j].compareTo(key)<0) {
     41                     idx = j;
     42                     key = items[idx];
     43                 }
     44             }
     45             items[idx] = items[i];
     46             items[i] = key;
     47         }
     48     }
     49     public void insertSort() {
     50         // Implement Insertion Sort Algorithm
     51         for (int i=1;i<len;i++) {
     52             T key = items[i];
     53             int j = i-1;
     54             for (;j>=0&&items[j].compareTo(key)>0;j--) {
     55                 items[j+1] = items[j];
     56             }
     57             items[j+1] = key;
     58         }
     59     }
     60     public void binInsSort() {
     61         // Implement Binary Insertion Sort
     62         for (int i=1;i<len;i++) {
     63             T key = items[i];
     64             int pos = binSrch(0,i-1,key);
     65             for (int j=i;j>pos;j--) {
     66                 items[j] = items[j-1];
     67             }
     68             items[pos] = key;
     69         }
     70     }
     71     private int binSrch(int p,int r,T key) {
     72         //   Search for the position to insert key in itmes[p...r]
     73         //   Precondition:        items[p...r] is a sorted array
     74         //   Postcondition:    the position of  the least item larger than
     75         //               key in items[p...r] if it exists, otherwise return r+1
     76         if (p==r)  {
     77             if (items[p].compareTo(key)<=0) {
     78                 return p+1;
     79             } else {
     80                 return p;
     81             }
     82         } else  {
     83             int q = (p+r)/2;
     84             if (items[q+1].compareTo(key)>0) {
     85                 return binSrch(p,q,key);
     86             } else {
     87                 return binSrch(q+1,r,key);
     88             }
     89         }
     90     }
     91     public void quickSort() {
     92         //    Implement Quick Sort Algorithm
     93         genRandPerm();
     94         qsort(0,len-1);
     95     }
     96     private void genRandPerm() {
     97         // Perturb items into a random permutation
     98         Random rand = new Random();
     99         for (int i=0;i<len-1;i++) {
    100             int idx = i+rand.nextInt(len-i);
    101             T tmp = items[idx];
    102             items[idx] = items[i];
    103             items[i] = tmp;
    104         }
    105     }
    106     private void qsort(int p,int r) {
    107         // Divide & Conquer for quick sort
    108         if (p<r) {
    109             int q = partition(p,r);
    110             qsort(p,q-1);
    111             qsort(q+1,r);
    112         }
    113     }
    114     private int partition(int p,int r) {
    115         // Partition items[p...r] for qsort procedure
    116         //  Precondition:        items[p...r] is a random permutation
    117         //  Postcondition:    items[q+1...r] are larger than items[q]
    118         //        items[p...q-1] are smaller than or equal to items[q]
    119         //        pivot index q is returned
    120         T key = items[r];
    121         int i = p-1;
    122         for (int j=p;j<r;j++) {
    123             //    Loop Invariant:    items[i...j-1] are larger than key
    124             //          items[p...i-1] are smaller than or equal to key
    125             if (items[j].compareTo(key)<=0) {
    126                 i = i+1;
    127                 T tmp = items[i];
    128                 items[i] = items[j];
    129                 items[j] = tmp;
    130             }
    131         }
    132         items[r] = items[i+1];
    133         items[i+1] = key;
    134         return i+1;
    135     }
    136     public void mergeSort() {
    137         // Implement Merge Sort Algorithm
    138         T[] tmp = (T[]) new Comparable[len];
    139         msort(tmp,0,len-1);
    140     }
    141     private void msort(T[] tmp,int p,int r) {
    142         // Divide & Conquer for merge sort
    143         if (p<r) {
    144             int q = ((p+r)>>1);
    145             msort(tmp,p,q);
    146             msort(tmp,q+1,r);
    147             merge(tmp,p,q,r);
    148         }
    149     }
    150     private void merge(T[] tmp,int p,int q,int r) {
    151         // Merge items[p...q] and items[q+1...r] into a whole
    152         //  Precondition:        items[p...q] and items[q+1....r] are sorted
    153         //  Postcondition:    items[p...r] is sorted
    154         for (int i=p;i<=r;i++) {
    155             tmp[i] = items[i];
    156         }
    157         int i = p, j = q+1, k = p;
    158         while (i<=q&&j<=r)  {
    159             //    both left[] and right[] haven't run out
    160             if (tmp[i].compareTo(tmp[j])<0) {
    161                 items[k++] = tmp[i++];
    162             } else {
    163                 items[k++] = tmp[j++];
    164             }
    165         }
    166         while (i<=q) {
    167             // only left[] hasn't run out
    168             items[k++] = tmp[i++];
    169         }
    170         while (j<=r) {
    171             // only right[] hasn't run out
    172             items[k++] = tmp[j++];
    173         }
    174     }
    175     public void heapsort() {
    176         // Implement Heap Sort Algorithm
    177         for (int i=((len-3)>>1);i>=0;i--) {
    178             // build a max-heap
    179             sift_down(len,i);
    180         }
    181         int n = len;
    182         for (int i=len-1;i>0;i--) {
    183             // extract the max item
    184             T tmp = items[0];
    185             items[0] = items[i];
    186             items[i] = tmp;
    187             sift_down(--n,0);
    188         }
    189     }
    190     public void sift_down(int n,int i) {
    191         // MAX_HEAPIFY from items[i] given n is the heap size
    192         int j = (i<<1)+1, k = (i<<1)+2, idx = i;
    193         if (j<n) {
    194             if (items[idx].compareTo(items[j])<0) {
    195                 idx = j;
    196             }
    197             if (k<n&&items[idx].compareTo(items[k])<0) {
    198                 idx = k;
    199             }
    200             if (idx>i) {
    201                 T tmp = items[i];
    202                 items[i] = items[idx];
    203                 items[idx] = tmp;
    204                 sift_down(n,idx);
    205             }
    206         }
    207     }
    208     public void display() {
    209         // Display the array items on the console
    210         if (len>0) {
    211             System.out.print(items[0]);
    212             for (int i=1;i<len;i++) {
    213                 System.out.print(" "+items[i]);
    214             }
    215         }
    216         System.out.println();
    217     }
    218     
    219 }

    2. Counting Sort

      Since Counting Sort is not based on comparisons, its time complexity has no lower bound as those mentioned above. As an integer sorting algorithm, counting sort takes O(N) time, where N is the range of the input integers (MAX - MIN).

      Talk is cheap, show you my code.  ╮( ̄. ̄)╭

     1     public static void countSort(int[] arr) {
     2         int n = arr.length;
     3                 int min = arr[0], max = arr[0];
     4         for (int i=1;i<n;i++) {
     5             // Determine the minimum and maximum values
     6             if (min>arr[i]) {
     7                 min = arr[i];
     8             } else if (max<arr[i]){
     9                 max = arr[i];
    10             }
    11         }
    12         max -= min;
    13         int[] cnt = new int[max+1];
    14         for (int i=0;i<n;i++) {
    15             // Count the frequency of each value in arr[]
    16             cnt[arr[i]-min]++;
    17         }
    18         for (int i=1;i<=max;i++) {
    19             // Determine the starting position of each value
    20             cnt[i] += cnt[i-1];
    21         }
    22         int pos = 0;
    23         for (int i=0;i<=max;i++) {
    24             // Put the values in their proper positions
    25             while (cnt[i]>pos) {
    26                 arr[pos++] = i+min;
    27             }
    28         }
    29     }

    3. Applications of Sorting Algorithms

      We can apply the sorting algorithms described above to many other problems. For instance, we can select a certain Order Statistic of an integer array by drawing on the partition method in Quick Sort:

     1     public static int select(int[] arr,int idx) {
     2         // Determine the idxth Order Statistic in arr[]
     3         // Precondition: 1<=idx<=arr.length
     4         // Postcondition: the value desired is returned
     5         int n = arr.length;
     6         int[] tmp = new int[n];
     7         for (int i=0;i<n;i++) {
     8             tmp[i] = arr[i];
     9         }
    10         return selectHelp(tmp,0,n-1,idx);
    11     }
    12     private static int selectHelp(int[] arr,int p,int r,int idx) {
    13         // Determine the idxth Order Statistic among arr[p...r]
    14         // Precondition: 1<=idx<=r+1-p (p<=r)
    15         // Postcondition: the value desired is returned
    16         if (p==r) {
    17             return arr[p];
    18         } 
    19         int key = arr[r];
    20         int q = p;
    21         for (int j=p;j<r;j++) {
    22             // arr[p...q-1]<=key<arr[q...j]
    23             if (arr[j]<=key) {
    24                 int tmp = arr[q];
    25                 arr[q] = arr[j];
    26                 arr[j] = tmp;
    27                 q++;
    28             }
    29         }
    30         arr[r] = arr[q];
    31         arr[q] = key;
    32         if (idx<=q-p) {
    33             return selectHelp(arr,p,q-1,idx);
    34         } else {
    35             return selectHelp(arr,q,r,idx+p-q);
    36         }
    37     }

      Another example is that we use the merge method in Merge Sort to count the number of inversions in a given integer array:

     1     public static int invNum(int[] arr) {
     2         int n = arr.length;
     3         int[] tmp = new int[n];
     4         for (int i=0;i<n;i++) {
     5             tmp[i] = arr[i];
     6         }
     7         int[] left = new int[(n-1)/2+2];
     8         int[] right = new int[n/2+1];
     9         return invNumHelp(tmp,0,n-1,left,right);
    10     }
    11     private static int invNumHelp(int[] arr,int p,int r,int[] left,int[] right) {
    12         // Determine the number of inversions in arr[p...r]
    13         //        and meanwhile turn it into increasing order
    14         if (p==r) {
    15             return 0;
    16         } 
    17         int q = ((p+r)>>1), val = 0;
    18         // solve subproblems recursively
    19         val += invNumHelp(arr,p,q,left,right);
    20         val += invNumHelp(arr,q+1,r,left,right);
    21         // copy arr[] to left[] and right[]
    22         for (int i=p;i<=q;i++) {
    23             left[i-p] = arr[i];
    24         }
    25         for (int i=q+1;i<=r;i++) {
    26             right[i-q-1] = arr[i];
    27         }
    28         // set sentinels in left[] and right[]
    29         left[q+1-p] = (1<<31)-1;
    30         right[r-q] = (1<<31)-1;
    31         // count inversions across left and right
    32         for (int i=0,j=0,k=p;k<=r;k++) {
    33             if (left[i]>right[j]) {
    34                 arr[k] = right[j++];
    35                 val += (q+1-p-i);
    36             } else {
    37                 arr[k] = left[i++];
    38             }
    39         }
    40         return val;
    41     }

      As a matter of fact, Quick Sort is a Divide-and-Conquer Algorithm that solves the problem in a top-down way, while Merge Sort adopts a bottom-up approach instead.


    References:

      1. Cormen, T. H. et al. Introduction to Algorithms [M] .  北京:机械工业出版社, 2006-09



  • 相关阅读:
    Java中使用Jedis操作Redis
    Predicate与filter
    Joiner的用法
    Immutable集合
    【Excle数据透视】如何在数据透视表字段列表中显示更多的字段
    【Excle数据透视表】如何显示/隐藏数据透视表字段列表
    【Excle数据透视】如何创建多条件汇总的数据透视表
    【Excle数据透视表】如何创建非共享缓存的数据透视表
    【Excle数据透透视表】如何删除数据透视表
    【Excle数据透视表】如何复制数据透视表
  • 原文地址:https://www.cnblogs.com/DevinZ/p/4415428.html
Copyright © 2020-2023  润新知