Radix Sort | GeeksforGeeks


Radix Sort | GeeksforGeeks
What if the elements are in range from 1 to n2
The lower bound for Comparison based sorting algorithm is\Omega(nLogn), i.e., they cannot do better than nLogn.
Counting sort is a linear tine sorting algorithm that sort in O(n+k) time when elements are in range from 1 to k.

overall time complexity is O((n+b) * logb(k)).  b is the base for representing numbers

Why Radix Sort Works?
In mathematics, radix means base, where decimal would be base 10.


The idea of Radix Sort is to do digit by digit sort starting from least significant digit to most significant digit. Radix sort uses counting sort as a subroutine to sort.

1) Do following for each digit i where i varies from least significant digit to the most significant digit.
………….a) Sort input array using counting sort (or any stable sort) according to the i’th digit.

Example:
Original, unsorted list:
170, 45, 75, 90, 802, 24, 2, 66
Sorting by least significant digit (1s place) gives: [*Notice that we keep 802 before 2, because 802 occurred before 2 in the original list, and similarly for pairs 170 & 90 and 45 & 75.]
170, 90, 8022, 24, 45, 75, 66
Sorting by next digit (10s place) gives: [*Notice that 802 again comes before 2 as 802 comes before 2 in the previous list.]
802, 2, 24, 45, 66, 170, 75, 90
Sorting by most significant digit (100s place) gives:
2, 24, 45, 66, 75, 90, 170, 802
// A function to do counting sort of arr[] according to
// the digit represented by exp.
void countSort(int arr[], int n, int exp)
{
    int output[n]; // output array
    int i, count[10] = {0};
    // Store count of occurrences in count[]
    for (i = 0; i < n; i++)
        count[ (arr[i]/exp)%10 ]++;
    // Change count[i] so that count[i] now contains actual position of
    // this digit in output[]
    for (i = 1; i < 10; i++)
        count[i] += count[i - 1];
    // Build the output array
    for (i = n - 1; i >= 0; i--)
    {
        output[count[ (arr[i]/exp)%10 ] - 1] = arr[i];
        count[ (arr[i]/exp)%10 ]--;
    }
    // Copy the output array to arr[], so that arr[] now
    // contains sorted numbers according to curent digit
    for (i = 0; i < n; i++)
        arr[i] = output[i];
}
// The main function to that sorts arr[] of size n using Radix Sort
void radixsort(int arr[], int n)
{
    // Find the maximum number to know number of digits
    int m = getMax(arr, n);
    // Do counting sort for every digit. Note that instead of passing digit
    // number, exp is passed. exp is 10^i where i is current digit number
    for (int exp = 1; m/exp > 0; exp *= 10)
        countSort(arr, n, exp);
}
基数排序
基数排序的主要思想是把数字按位进行比较,通过比较每个数特定位的大小来移动数组元素。既然是按位进行比较,那么既可以从左往右,也可以从右往左.

基数排序号称可以在O(n)的时间复杂度完成排序,其实所言非虚,只是真正的时间复杂度应该是O(kN),k指待排序列最大值的位数,同时不能遗漏的是基数排序需要O(N)的空间充当“桶”的角色。根据基数排序的排序的原理,可知它比较适合于正整数的排序,而对于负数或者浮点数,字符串等排序,需要将待排序列做一定得变换.

根据按位比较的方向,可以将基数排序的实现分为两种,MSD(Most significant digital,从高到低)和LSD(Least significant digital,从低到高)。
首先写一个获取指定位的辅助函数
private static final int radix = 10;
 
private static int getDigit(int num, int d){
    int[] rd = new int[]{1,1,10,100,1000};     
    return (num / rd[d])%10;
}
先实现MSD算法,也就是从高到低位的比较顺序。
public static void msdRadixSort(int[] nums, int start, int end, int d){
    if(nums == null || nums.length < 2) return;
    int len = end - start + 1;
    int[] bucket = new int[len];
    int[] count = new int[radix+1];
    int i = 0;
    int j = 0;
     
    for(i=start; i<=end; i++){
        count[getDigit(nums[i], d)]++;
    }
     
    for(i=1; i<=radix; i++){
        count[i] += count[i-1];
    }
     
    for(i = end; i>=start; i--){
        j = getDigit(nums[i], d);
        bucket[count[j] - 1] = nums[i];
        count[j]--;
    }
     
    for(i=start, j=0; i<=end; i++,j++)
        nums[i] = bucket[j];
     
    for(i=0; i<radix; i++){
        int left = start + count[i];
        int right = start + count[i+1]-1;
        if(left < right && d>1){
            msdRadixSort(nums, left, right, d-1);
        }
    }
}
再实现LSD算法。
public static void lsdRadixSort(int[] nums, int d){
    if(nums == null || nums.length <2 || d<1) return;
    int[] count = new int[radix + 1];
    int[] bucket = new int[nums.length];
     
    for(int k=1; k<=d; k++){
        Arrays.fill(count, 0);
        for(int i=0; i<nums.length; i++){
            count[getDigit(nums[i], k)]++;
        }
         
        for(int i=1; i<=radix; i++)
            count[i] += count[i-1];
         
        // fill the bucket
        for(int i=nums.length-1; i>=0; i--){
            int j = getDigit(nums[i], k);
            bucket[count[j] - 1] = nums[i];
            --count[j];
        }
         
        // copy to the original array
        System.arraycopy(bucket, 0, nums, 0, nums.length);
    }
}
http://www.sanfoundry.com/java-program-implement-radix-sort/
public static void sort(int[] a) {
int m = Collections.max(Ints.asList(a)), exp = 1;
while (m / exp > 0) {
countSort(a, exp);
exp *= 10;
}
}

public static void countSort(int[] a, int exp) {
int[] bucket = new int[10];
int i, n = a.length;
int[] b = new int[10];
for (i = 0; i < n; i++)
bucket[(a[i] / exp) % 10]++;
for (i = 1; i < 10; i++)
bucket[i] += bucket[i - 1];
for (i = n - 1; i >= 0; i--)
b[--bucket[(a[i] / exp) % 10]] = a[i];
for (i = 0; i < n; i++)
a[i] = b[i];
}
Correctness Proofs for Radix Sort
First proof of correctness. Consider any two elements in the unsorted array, say A[i] and
A[j] for i < j. Let us denote the digits of these numbers as follows:
A[i] = b1b2 · · · bd
A[j] = c1c2 · · · cd
Suppose that A[i] != A[j], and let t be the first digit where they differ. That is, we have
b1 = c1, . . . , bt−1 = ct−1 but bt != ct
. For concreteness, suppose that bt < ct
. Then A[i]
should be sorted before A[j]. (The case bt > ct
is analogous.)
When j = t in Radix-Sort, we will perform a sort by the t-th digit, which will
ensure that A[i] is before A[j]. All sorts after this are for digits j < t, where A[i] and
A[j] have equal digits. Since Counting-Sort is stable, each of these sorts leaves A[i]
before A[j] in the array. Hence, A[i] is before A[j] when Radix-Sort finishes.

The next proof relies on the following lemma. This proof plus the lemma is a bit
longer than the proof above, but it tells us a bit more about what Radix-Sort is doing.
Lemma 1. After t sorts in Radix-Sort, the elements of A are sorted according to
their last t digits (i.e., digits d − t + 1, . . . , d).
The second proof is a trivial consequence of this lemma.
Second proof of correctness. Apply the above lemma to the case t = d. This says that,
after all d sorts, the numbers are sorted according to all their digits.

Proof of Lemma. We will prove this by induction on t.
For t = 1, the claim is that, after the first sort, the numbers are sorted according to
their last digit. Since j starts at d, the first call to Counting-Sort is for the d-th digit,
so after that first sort is done, they are properly sorted according to the d-th digit.
For t > 1, the t-th sort comes after the t − 1 previous sorts. By induction, after the
(t − 1)-st sort, the numbers are sorted according to their last t − 1 digits (i.e., digits
d − t + 2, . . . , d). The t-th sort now sorts them by digit k := d − t + 1.
Consider any two elements A[i] and A[j] and label their digits as above:
A[i] = b1b2 · · · bd
A[j] = c1c2 · · · cd
If we have bk < ck, then the number represented by the last t digits of A[i], which is
bkbk+1 · · · bd, is smaller than A[j], which is ckck+1 · · · cd. Since bk < ck and the last call
to Counting-Sort was for digit k, this will have ensured that A[i] is before A[j].
It only remains to consider the case that bk = ck. In that case, the number
bkbk+1 · · · bd is smaller than ckck+1 · · · cd if and only if bk+1bk+2 · · · bd is smaller than
ck+1ck+2 · · · cd. By the inductive hypothesis, after the (t−1)-st sort (just before the t-th
sort), the numbers were sorted properly according to these digits. As we just argued,
the proper order of A[i] and A[j] according to digits k, . . . , d is the same as according to
digits k + 1, . . . , d. And since bk = ck and Counting-Sort is stable, the t-th sort will
leave them in the same order, which is properly ordered.
Read full article from Radix Sort | GeeksforGeeks

Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts