📜  基数排序

📅  最后修改于: 2021-05-05 00:37:59             🧑  作者: Mango

基于比较的排序算法(合并排序,堆排序,快速排序等)的下限是Ω(nLogn),即它们不能比nLogn更好。

计数排序是一种线性时间排序算法,当元素的范围从1到k时,它以O(n + k)时间排序。

如果元素范围是1到n 2怎么办?
我们不能使用计数排序,因为计数排序将花费O(n 2 ),这比基于比较的排序算法差。我们可以在线性时间内对这样的数组排序吗?

答案是基数排序。基数排序的想法是从最低有效位到最高有效位逐位进行排序。基数排序使用计数排序作为排序的子例程。

基数排序算法

  1. 对于i从最低有效数字到最高有效数字变化的每个数字i,都要执行以下操作。
    • 根据第i位使用计数排序(或任何稳定排序)对输入数组进行排序。

例子:

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, 802, 2, 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 the most significant digit (100s place) gives:
2, 24, 45, 66, 75, 90, 170, 802

Radix Sort的运行时间是几点?
设输入整数为d位。基数排序需要O(d *(n + b))时间,其中b是表示数字的基数,例如,对于十进制,b是10。d的值是什么?如果k是最大可能值,则d将为O(log b (k))。因此,总体时间复杂度为O((n + b)* log b (k))。它看起来比基于比较的排序算法对大k的时间复杂度更高。让我们首先限制k。令k <= n c ,其中c为常数。在这种情况下,复杂度变为O(nLog b (n))。但是它仍然没有超越基于比较的排序算法。
如果我们增大b的值怎么办?使时间复杂度线性化的b的值应该是多少?如果将b设置为n,则时间复杂度为O(n)。换句话说,如果数字以n为底(或者每个数字取对数2 (n)位),则可以对范围为1到n c的整数数组进行排序。

Radix Sort是否优于Quick-Sort等基于比较的排序算法?
如果我们每个数字都有2 n个对数位,那么对于各种各样的输入数字,Radix的运行时间似乎比快速排序要好。对于Radix Sort,隐藏在渐近符号中的常数因子更高,而Quick-Sort更有效地使用硬件缓存。同样,基数排序使用计数排序作为子例程,计数排序占用额外的空间来对数字进行排序。

基数排序的实现

以下是Radix Sort的简单实现。为简单起见,假定d的值为10。建议您在下面的代码中查看Counting Sort,以了解countSort()函数的详细信息。

C++
// C++ implementation of Radix Sort
#include 
using namespace std;
 
// A utility function to get maximum value in arr[]
int getMax(int arr[], int n)
{
    int mx = arr[0];
    for (int i = 1; i < n; i++)
        if (arr[i] > mx)
            mx = arr[i];
    return mx;
}
 
// 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 current 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);
}
 
// A utility function to print an array
void print(int arr[], int n)
{
    for (int i = 0; i < n; i++)
        cout << arr[i] << " ";
}
 
// Driver Code
int main()
{
    int arr[] = { 170, 45, 75, 90, 802, 24, 2, 66 };
    int n = sizeof(arr) / sizeof(arr[0]);
     
      // Function Call
      radixsort(arr, n);
    print(arr, n);
    return 0;
}


Java
// Radix sort Java implementation
import java.io.*;
import java.util.*;
 
class Radix {
 
    // A utility function to get maximum value in arr[]
    static int getMax(int arr[], int n)
    {
        int mx = arr[0];
        for (int i = 1; i < n; i++)
            if (arr[i] > mx)
                mx = arr[i];
        return mx;
    }
 
    // A function to do counting sort of arr[] according to
    // the digit represented by exp.
    static void countSort(int arr[], int n, int exp)
    {
        int output[] = new int[n]; // output array
        int i;
        int count[] = new int[10];
        Arrays.fill(count, 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
    static 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);
    }
 
    // A utility function to print an array
    static void print(int arr[], int n)
    {
        for (int i = 0; i < n; i++)
            System.out.print(arr[i] + " ");
    }
 
    /*Driver Code*/
    public static void main(String[] args)
    {
        int arr[] = { 170, 45, 75, 90, 802, 24, 2, 66 };
        int n = arr.length;
           
          // Function Call
        radixsort(arr, n);
        print(arr, n);
    }
}
/* This code is contributed by Devesh Agrawal */


Python
# Python program for implementation of Radix Sort
# A function to do counting sort of arr[] according to
# the digit represented by exp.
 
def countingSort(arr, exp1):
 
    n = len(arr)
 
    # The output array elements that will have sorted arr
    output = [0] * (n)
 
    # initialize count array as 0
    count = [0] * (10)
 
    # Store count of occurrences in count[]
    for i in range(0, n):
        index = (arr[i] / exp1)
        count[int(index % 10)] += 1
 
    # Change count[i] so that count[i] now contains actual
    # position of this digit in output array
    for i in range(1, 10):
        count[i] += count[i - 1]
 
    # Build the output array
    i = n - 1
    while i >= 0:
        index = (arr[i] / exp1)
        output[count[int(index % 10)] - 1] = arr[i]
        count[int(index % 10)] -= 1
        i -= 1
 
    # Copying the output array to arr[],
    # so that arr now contains sorted numbers
    i = 0
    for i in range(0, len(arr)):
        arr[i] = output[i]
 
# Method to do Radix Sort
def radixSort(arr):
 
    # Find the maximum number to know number of digits
    max1 = max(arr)
 
    # 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
    exp = 1
    while max1 / exp > 0:
        countingSort(arr, exp)
        exp *= 10
 
 
# Driver code
arr = [170, 45, 75, 90, 802, 24, 2, 66]
 
# Function Call
radixSort(arr)
 
for i in range(len(arr)):
    print(arr[i])
 
# This code is contributed by Mohit Kumra
# Edited by Patrick Gallagher


C#
// C# implementation of Radix Sort
using System;
 
class GFG {
    public static int getMax(int[] arr, int n)
    {
        int mx = arr[0];
        for (int i = 1; i < n; i++)
            if (arr[i] > mx)
                mx = arr[i];
        return mx;
    }
 
    // A function to do counting sort of arr[] according to
    // the digit represented by exp.
    public static void countSort(int[] arr, int n, int exp)
    {
        int[] output = new int[n]; // output array
        int i;
        int[] count = new int[10];
 
        // initializing all elements of count to 0
        for (i = 0; i < 10; i++)
            count[i] = 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 current
        // digit
        for (i = 0; i < n; i++)
            arr[i] = output[i];
    }
 
    // The main function to that sorts arr[] of size n using
    // Radix Sort
    public static 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);
    }
 
    // A utility function to print an array
    public static void print(int[] arr, int n)
    {
        for (int i = 0; i < n; i++)
            Console.Write(arr[i] + " ");
    }
 
    // Driver Code
    public static void Main()
    {
        int[] arr = { 170, 45, 75, 90, 802, 24, 2, 66 };
        int n = arr.Length;
 
        // Function Call
        radixsort(arr, n);
        print(arr, n);
    }
 
    // This code is contributed by DrRoot_
}


PHP
= 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 current digit
    for ($i = 0; $i < $n; $i++)
        $arr[$i] = $output[$i];
}
 
// The main function to that sorts arr[]
// of size n using Radix Sort
function radixsort(&$arr, $n)
{
     
    // Find the maximum number to know
    // number of digits
    $m = max($arr);
 
    // 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 ($exp = 1; $m / $exp > 0; $exp *= 10)
        countSort($arr, $n, $exp);
}
 
// A utility function to print an array
function PrintArray(&$arr,$n)
{
    for ($i = 0; $i < $n; $i++)
        echo $arr[$i] . " ";
}
 
// Driver Code
$arr = array(170, 45, 75, 90, 802, 24, 2, 66);
$n = count($arr);
 
// Function Call
radixsort($arr, $n);
PrintArray($arr, $n);
 
// This code is contributed by rathbhupendra
?>


C++
// implementation of radix sort using bin/bucket sort
#include 
using namespace std;
 
// structure for a single linked list to help further in the
// sorting
struct node {
    int data;
    node* next;
};
 
// function for creating a new node in the linked list
struct node* create(int x)
{
    node* temp = new node();
    temp->data = x;
    temp->next = NULL;
 
    return temp;
}
 
// utility function to append node in the linked list
// here head is passed by reference, to know more about this
// search pass by reference
void insert(node*& head, int n)
{
    if (head == NULL) {
        head = create(n);
        return;
    }
 
    node* t = head;
    while (t->next != NULL)
        t = t->next;
    t->next = create(n);
}
 
// utility function to pop an element from front in the list
// for the sake of stability in sorting
int del(node*& head)
{
    if (head == NULL)
        return 0;
    node* temp = head;
    // storing the value of head before updating
    int val = head->data;
 
    // updation of head to next node
    head = head->next;
 
    delete temp;
    return val;
}
 
// utility function to get the number of digits in the
// max_element
int digits(int n)
{
    int i = 1;
    if (n < 10)
        return 1;
 
    while (n > (int)pow(10, i))
        i++;
    return i;
}
 
void radix_sort(vector& arr)
{
    // size of the array to be sorted
    int sz = arr.size();
 
    // getting the maximum element in the array
    int max_val = *max_element(arr.begin(), arr.end());
 
    // getting digits in the maximum element
    int d = digits(max_val);
 
    // creating buckets to store the pointers
    node** bins;
 
    // array of pointers to linked list of size 10 as
    // integers are decimal numbers so they can hold numbers
    // from 0-9 only, that's why size of 10
 
    bins = new node*[10];
 
    // intialising the hash array with null to all
    for (int i = 0; i < 10; i++)
        bins[i] = NULL;
 
    // first loop working for a constan time only and inner
    // loop is iterating through the array to store elements
    // of array in the linked list by their digits value
    for (int i = 0; i < d; i++) {
        for (int j = 0; j < sz; j++) // bins updation
            insert(bins[(arr[j] / (int)pow(10, i)) % 10],
                   arr[j]);
 
        int x = 0, y = 0;
        // write back to the array after each pass
 
        while (x < 10) {
            while (bins[x] != NULL)
                arr[y++] = del(bins[x]);
            x++;
        }
    }
}
 
// a utility function to print the sorted array
void print(vector arr)
{
    for (int i = 0; i < arr.size(); i++)
        cout << arr[i] << " ";
    cout << endl;
}
 
int main()
{
    vector arr = { 573, 25, 415, 12, 161, 6 };
 
    // function call
    radix_sort(arr);
    print(arr);
 
    return 0;
}


输出
2 24 45 66 75 90 170 802 

以下是使用存储桶排序技术时实现基数排序的另一种方法,在查看代码时可能看起来并不简单,但是如果您尝试一下,那么很容易就可以了解有关存储桶排序的更多信息,请访问https: //www.geeksforgeeks.org/bucket-sort-2并了解该技术背后的逻辑。

C++

// implementation of radix sort using bin/bucket sort
#include 
using namespace std;
 
// structure for a single linked list to help further in the
// sorting
struct node {
    int data;
    node* next;
};
 
// function for creating a new node in the linked list
struct node* create(int x)
{
    node* temp = new node();
    temp->data = x;
    temp->next = NULL;
 
    return temp;
}
 
// utility function to append node in the linked list
// here head is passed by reference, to know more about this
// search pass by reference
void insert(node*& head, int n)
{
    if (head == NULL) {
        head = create(n);
        return;
    }
 
    node* t = head;
    while (t->next != NULL)
        t = t->next;
    t->next = create(n);
}
 
// utility function to pop an element from front in the list
// for the sake of stability in sorting
int del(node*& head)
{
    if (head == NULL)
        return 0;
    node* temp = head;
    // storing the value of head before updating
    int val = head->data;
 
    // updation of head to next node
    head = head->next;
 
    delete temp;
    return val;
}
 
// utility function to get the number of digits in the
// max_element
int digits(int n)
{
    int i = 1;
    if (n < 10)
        return 1;
 
    while (n > (int)pow(10, i))
        i++;
    return i;
}
 
void radix_sort(vector& arr)
{
    // size of the array to be sorted
    int sz = arr.size();
 
    // getting the maximum element in the array
    int max_val = *max_element(arr.begin(), arr.end());
 
    // getting digits in the maximum element
    int d = digits(max_val);
 
    // creating buckets to store the pointers
    node** bins;
 
    // array of pointers to linked list of size 10 as
    // integers are decimal numbers so they can hold numbers
    // from 0-9 only, that's why size of 10
 
    bins = new node*[10];
 
    // intialising the hash array with null to all
    for (int i = 0; i < 10; i++)
        bins[i] = NULL;
 
    // first loop working for a constan time only and inner
    // loop is iterating through the array to store elements
    // of array in the linked list by their digits value
    for (int i = 0; i < d; i++) {
        for (int j = 0; j < sz; j++) // bins updation
            insert(bins[(arr[j] / (int)pow(10, i)) % 10],
                   arr[j]);
 
        int x = 0, y = 0;
        // write back to the array after each pass
 
        while (x < 10) {
            while (bins[x] != NULL)
                arr[y++] = del(bins[x]);
            x++;
        }
    }
}
 
// a utility function to print the sorted array
void print(vector arr)
{
    for (int i = 0; i < arr.size(); i++)
        cout << arr[i] << " ";
    cout << endl;
}
 
int main()
{
    vector arr = { 573, 25, 415, 12, 161, 6 };
 
    // function call
    radix_sort(arr);
    print(arr);
 
    return 0;
}
输出

6 12 25 161 415 573 

时间复杂度与第一种方法相同,只是通过另一种方法的实现。

快照:

场景00577场景00649场景scene01009scene01225

基数测验

GeeksforGeeks / GeeksQuiz上的其他排序算法:

  • 选择排序
  • 气泡排序
  • 插入排序
  • 合并排序
  • 堆排序
  • 快速排序
  • 计数排序
  • 桶分类
  • 壳排序