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



posted on 2015-03-19 08:11  DevinZ  阅读(168)  评论(0编辑  收藏  举报

导航