📜  MSD(最高位)基数排序

📅  最后修改于: 2021-09-02 06:37:17             🧑  作者: Mango

在本文中,讨论了两种基数排序:

  • LSD 基数排序:它从字符串的末尾(最低有效数字)开始排序。
  • MSD 基数排序:从字符串的开头(最高位)开始排序。

在本文中,任务是讨论 MSD 基数排序并将其与 LSD 基数排序进行比较。

方法:我们的想法是执行针对每个数字以下步骤i其中i的值从最显著位到最低位显著变化:

  • 根据i数字将元素存储在不同的桶中。
  • 对包含多个元素的每个桶进行递归排序。

最高与最低有效数字基数排序

  • 这个想法是对固定长度的整数进行排序,MSD 比 LSD 更有效,因为它可能不必检查每个整数的每个数字:

LSD 基数排序:

MSD基数排序

  • 与 LSD 不同,MSD 可用于对可变长度的字符串进行排序。 LSD 必须稳定才能正常工作,但 MSD 可以变得稳定或不稳定,并且 MSD 可以处理随机字符串。

MSD 基数排序变长字符串

  • 时间复杂度:
    • LSD 基数排序:最佳和最坏情况时间复杂度为O(N*M) ,其中 M = 最长字符串的长度。
      MSD 基数排序:最佳情况时间复杂度为O(N) ,最坏情况时间复杂度为O(N*M) ,其中 M =字符串的平均长度。
  • 辅助空间:
    • LSD基数排序: O(N + B)
    • MSD 基数排序: O(N + MB ),其中 M = 最长字符串的长度,B = 基数的大小(B=10 个可能的数字或 B=256 个字符或 B=2 的二进制)。
  • MSD 使用递归,因此它比 LSD 需要更多空间。这意味着在处理少量输入时,MSD 比 LSD 慢得多。

MSD基数排序的实现

使用链表此实现适用于使用链表的整数。每个节点的固定长度数组将占用非常大量的存储空间。

下面是使用链表实现 MSD 基数排序:

C++
// C++ program for the implementation
// of MSD Radix Sort using linked list
#include 
#include 
 
using namespace std;
 
// Linked list node structure
struct node {
    vector arr;
    struct node* nxt[10];
};
 
// Function to create a new node of
// the Linked List
struct node* new_node(void)
{
    struct node* tempNode = new node;
 
    for (int i = 0; i < 10; i++) {
        tempNode->nxt[i] = NULL;
    }
 
    // Return the created node
    return tempNode;
}
 
// Function to sort the given array
// using MSD Radix Sort recursively
void msd_sort(struct node* root, int exp,
              vector& sorted_arr)
{
    if (exp <= 0) {
        return;
    }
 
    int j;
 
    // Stores the numbers in different
    // buckets according their MSD
    for (int i = 0;
         i < root->arr.size();
         i++) {
 
        // Get the MSD in j
        j = (root->arr[i] / exp) % 10;
 
        // If j-th index in the node
        // array is empty create and
        // link a new node in index
        if (root->nxt[j] == NULL) {
            root->nxt[j] = new_node();
        }
 
        // Store the number in j-th node
        root->nxt[j]->arr.push_back(
            root->arr[i]);
    }
 
    // Sort again every child node that
    // has more than one number
    for (int i = 0; i < 10; i++) {
 
        // If root->next is NULL
        if (root->nxt[i] != NULL) {
 
            if (root->nxt[i]->arr.size()
                > 1) {
 
                // Sort recursively
                msd_sort(root->nxt[i],
                         exp / 10,
                         sorted_arr);
            }
 
            // If any node have only
            // one number then it means
            // the number is sorted
            else {
                sorted_arr.push_back(
                    root->nxt[i]->arr[0]);
            }
        }
    }
}
 
// Function to calculate the MSD of the
// maximum  value in the array
int get_max_exp(vector arr)
{
    // Stores the maximum element
    int mx = arr[0];
 
    // Traverse the given array
    for (int i = 1; i < arr.size(); i++) {
 
        // Update the value of maximum
        if (arr[i] > mx) {
            mx = arr[i];
        }
    }
 
    int exp = 1;
 
    while (mx > 10) {
        mx /= 10;
        exp *= 10;
    }
 
    // Return the resultant value
    return exp;
}
 
// Function to print an array
void print(vector arr)
{
    for (int i = 0; i < arr.size(); i++)
        cout << arr[i] << " ";
 
    cout << endl;
}
 
// Driver Code
int main()
{
    // create the root node
    struct node* root = new_node();
 
    // Stores the unsorted array
    // in the root node
    root->arr.insert(root->arr.end(),
                     { 9330, 9950, 718,
                       8977, 6790, 95,
                       9807, 741, 8586,
                       5710 });
 
    cout << "Unsorted array : ";
 
    // Print the unsorted array
    print(root->arr);
 
    // Find the optimal longest exponent
    int exp = get_max_exp(root->arr);
 
    // Stores the sorted numbers
    vector sorted_arr;
 
    // Function Call
    msd_sort(root, exp, sorted_arr);
 
    cout << "Sorted array : ";
 
    // Print the sorted array
    print(sorted_arr);
 
    return 0;
}


C++
// C++ program for the implementation
// of MSD Radix Sort using counting sort()
#include 
#include 
using namespace std;
 
// Utility function to get the ASCII
// value of the character at index d
// in the string
int char_at(string str, int d)
{
    if (str.size() <= d)
        return -1;
    else
        return str.at(d);
}
 
// Function to sort the array using
// MSD Radix Sort recursively
void MSD_sort(string* str, int lo,
              int hi, int d)
{
    // Recursive break condition
    if (hi <= lo) {
        return;
    }
 
    // Stores the ASCII Values
    int count[256 + 1] = { 0 };
 
    // Temp is created to easily
    // swap strings in str[]
    unordered_map temp;
 
    // Store the occurrences of the most
    // significant character from
    // each string in count[]
    for (int i = lo; i <= hi; i++) {
        int c = char_at(str[i], d);
        count++;
    }
 
    // Change count[] so that count[]
    // now contains actual position
    // of this digits in temp[]
    for (int r = 0; r < 256 + 1; r++)
        count[r + 1] += count[r];
 
    // Build the temp
    for (int i = lo; i <= hi; i++) {
        int c = char_at(str[i], d);
        temp[count++] = str[i];
    }
 
    // Copy all strings of temp to str[],
    // so that str[] now contains
    // partially sorted strings
    for (int i = lo; i <= hi; i++)
        str[i] = temp[i - lo];
 
    // Recursively MSD_sort() on each
    // partially sorted strings set to
    // sort them by their next character
    for (int r = 0; r < 256; r++)
        MSD_sort(str, lo + count[r],
                 lo + count[r + 1] - 1,
                 d + 1);
}
 
// Function to print an array
void print(string* str, int n)
{
    for (int i = 0; i < n; i++) {
        cout << str[i] << " ";
    }
    cout << endl;
}
 
// Driver Code
int main()
{
    // Input String
    string str[] = { "midnight", "badge",
                     "bag", "worker",
                     "banner", "wander" };
 
    // Size of the string
    int n = sizeof(str) / sizeof(str[0]);
 
    cout << "Unsorted array : ";
 
    // Print the unsorted array
    print(str, n);
 
    // Function Call
    MSD_sort(str, 0, n - 1, 0);
 
    cout << "Sorted array : ";
 
    // Print the sorted array
    print(str, n);
 
    return 0;
}


Java
// Java program for the above approach
import java.io.*;
import java.lang.*;
import java.util.*;
 
public class GFG {
 
    // Utility function to get the ASCII
    // value of the character at index d
    // in the string
    static int char_at(String str, int d)
    {
        if (str.length() <= d)
            return -1;
        else
            return (int)(str.charAt(d));
    }
 
    // Function to sort the array using
    // MSD Radix Sort recursively
    static void MSD_sort(String str[], int lo, int hi,
                         int d)
    {
        // Recursive break condition
        if (hi <= lo) {
            return;
        }
 
        // Stores the ASCII Values
        int count[] = new int[256 + 1];
 
        // Temp is created to easily
        // swap strings in str[]
        HashMap temp = new HashMap<>();
 
        // Store the occurrences of the most
        // significant character from
        // each string in count[]
        for (int i = lo; i <= hi; i++) {
            int c = char_at(str[i], d);
            count++;
        }
 
        // Change count[] so that count[]
        // now contains actual position
        // of this digits in temp[]
        for (int r = 0; r < 256; r++)
            count[r + 1] += count[r];
 
        // Build the temp
        for (int i = lo; i <= hi; i++) {
            int c = char_at(str[i], d);
            temp.put(count++, str[i]);
        }
 
        // Copy all strings of temp to str[],
        // so that str[] now contains
        // partially sorted strings
        for (int i = lo; i <= hi; i++)
            str[i] = temp.get(i - lo);
 
        // Recursively MSD_sort() on each
        // partially sorted strings set to
        // sort them by their next character
        for (int r = 0; r < 256; r++)
            MSD_sort(str, lo + count[r],
                     lo + count[r + 1] - 1, d + 1);
    }
 
    // Function to print an array
    static void print(String str[], int n)
    {
        for (int i = 0; i < n; i++) {
            System.out.print(str[i] + " ");
        }
        System.out.println();
    }
 
    // Driver Code
    public static void main(String[] args)
    {
 
        // Input String
        String str[] = { "midnight", "badge",  "bag",
                         "worker",   "banner", "wander" };
 
        // Size of the string
        int n = str.length;
 
        System.out.print("Unsorted array : ");
 
        // Print the unsorted array
        print(str, n);
 
        // Function Call
        MSD_sort(str, 0, n - 1, 0);
 
        System.out.print("Sorted array : ");
 
        // Print the sorted array
        print(str, n);
    }
}
 
// This code is contributed by Kingash.


C#
// C# program for the above approach
using System;
using System.Collections.Generic;
 
class GFG{
 
// Utility function to get the ASCII
// value of the character at index d
// in the string
static int char_at(String str, int d)
{
    if (str.Length <= d)
        return -1;
    else
        return(int)(str[d]);
}
 
// Function to sort the array using
// MSD Radix Sort recursively
static void MSD_sort(String []str, int lo,
                           int hi, int d)
{
     
    // Recursive break condition
    if (hi <= lo)
    {
        return;
    }
 
    // Stores the ASCII Values
    int []count = new int[256 + 1];
 
    // Temp is created to easily
    // swap strings in []str
    Dictionary temp = new Dictionary();
 
    // Store the occurrences of the most
    // significant character from
    // each string in []count
    for(int i = lo; i <= hi; i++)
    {
        int c = char_at(str[i], d);
        count++;
    }
 
    // Change []count so that []count
    // now contains actual position
    // of this digits in []temp
    for(int r = 0; r < 256; r++)
        count[r + 1] += count[r];
 
    // Build the temp
    for(int i = lo; i <= hi; i++)
    {
        int c = char_at(str[i], d);
        temp.Add(count++, str[i]);
    }
 
    // Copy all strings of temp to []str,
    // so that []str now contains
    // partially sorted strings
    for(int i = lo; i <= hi; i++)
        str[i] = temp[i - lo];
 
    // Recursively MSD_sort() on each
    // partially sorted strings set to
    // sort them by their next character
    for(int r = 0; r < 256; r++)
        MSD_sort(str, lo + count[r],
                      lo + count[r + 1] - 1,
                       d + 1);
}
 
// Function to print an array
static void print(String []str, int n)
{
    for(int i = 0; i < n; i++)
    {
        Console.Write(str[i] + " ");
    }
    Console.WriteLine();
}
 
// Driver Code
public static void Main(String[] args)
{
 
    // Input String
    String []str = { "midnight", "badge", "bag",
                     "worker", "banner", "wander" };
 
    // Size of the string
    int n = str.Length;
 
    Console.Write("Unsorted array : ");
 
    // Print the unsorted array
    print(str, n);
 
    // Function Call
    MSD_sort(str, 0, n - 1, 0);
 
    Console.Write("Sorted array : ");
 
    // Print the sorted array
    print(str, n);
}
}
 
// This code is contributed by shikhasingrajput


输出:
Unsorted array : 9330 9950 718 8977 6790 95 9807 741 8586 5710 
Sorted array : 95 718 741 5710 6790 8586 8977 9330 9807 9950

使用 Counting Sort() 方法:此实现适用于基于计数 sort() 方法的字符串。由于 C 风格的 ASCII字符是1 个字节。因此, 256 大小的数组用于计算字符的出现次数,并按字典顺序对字符串排序。

下面是使用计数 sort() 方法实现 MSD 基数排序:

C++

// C++ program for the implementation
// of MSD Radix Sort using counting sort()
#include 
#include 
using namespace std;
 
// Utility function to get the ASCII
// value of the character at index d
// in the string
int char_at(string str, int d)
{
    if (str.size() <= d)
        return -1;
    else
        return str.at(d);
}
 
// Function to sort the array using
// MSD Radix Sort recursively
void MSD_sort(string* str, int lo,
              int hi, int d)
{
    // Recursive break condition
    if (hi <= lo) {
        return;
    }
 
    // Stores the ASCII Values
    int count[256 + 1] = { 0 };
 
    // Temp is created to easily
    // swap strings in str[]
    unordered_map temp;
 
    // Store the occurrences of the most
    // significant character from
    // each string in count[]
    for (int i = lo; i <= hi; i++) {
        int c = char_at(str[i], d);
        count++;
    }
 
    // Change count[] so that count[]
    // now contains actual position
    // of this digits in temp[]
    for (int r = 0; r < 256 + 1; r++)
        count[r + 1] += count[r];
 
    // Build the temp
    for (int i = lo; i <= hi; i++) {
        int c = char_at(str[i], d);
        temp[count++] = str[i];
    }
 
    // Copy all strings of temp to str[],
    // so that str[] now contains
    // partially sorted strings
    for (int i = lo; i <= hi; i++)
        str[i] = temp[i - lo];
 
    // Recursively MSD_sort() on each
    // partially sorted strings set to
    // sort them by their next character
    for (int r = 0; r < 256; r++)
        MSD_sort(str, lo + count[r],
                 lo + count[r + 1] - 1,
                 d + 1);
}
 
// Function to print an array
void print(string* str, int n)
{
    for (int i = 0; i < n; i++) {
        cout << str[i] << " ";
    }
    cout << endl;
}
 
// Driver Code
int main()
{
    // Input String
    string str[] = { "midnight", "badge",
                     "bag", "worker",
                     "banner", "wander" };
 
    // Size of the string
    int n = sizeof(str) / sizeof(str[0]);
 
    cout << "Unsorted array : ";
 
    // Print the unsorted array
    print(str, n);
 
    // Function Call
    MSD_sort(str, 0, n - 1, 0);
 
    cout << "Sorted array : ";
 
    // Print the sorted array
    print(str, n);
 
    return 0;
}

Java

// Java program for the above approach
import java.io.*;
import java.lang.*;
import java.util.*;
 
public class GFG {
 
    // Utility function to get the ASCII
    // value of the character at index d
    // in the string
    static int char_at(String str, int d)
    {
        if (str.length() <= d)
            return -1;
        else
            return (int)(str.charAt(d));
    }
 
    // Function to sort the array using
    // MSD Radix Sort recursively
    static void MSD_sort(String str[], int lo, int hi,
                         int d)
    {
        // Recursive break condition
        if (hi <= lo) {
            return;
        }
 
        // Stores the ASCII Values
        int count[] = new int[256 + 1];
 
        // Temp is created to easily
        // swap strings in str[]
        HashMap temp = new HashMap<>();
 
        // Store the occurrences of the most
        // significant character from
        // each string in count[]
        for (int i = lo; i <= hi; i++) {
            int c = char_at(str[i], d);
            count++;
        }
 
        // Change count[] so that count[]
        // now contains actual position
        // of this digits in temp[]
        for (int r = 0; r < 256; r++)
            count[r + 1] += count[r];
 
        // Build the temp
        for (int i = lo; i <= hi; i++) {
            int c = char_at(str[i], d);
            temp.put(count++, str[i]);
        }
 
        // Copy all strings of temp to str[],
        // so that str[] now contains
        // partially sorted strings
        for (int i = lo; i <= hi; i++)
            str[i] = temp.get(i - lo);
 
        // Recursively MSD_sort() on each
        // partially sorted strings set to
        // sort them by their next character
        for (int r = 0; r < 256; r++)
            MSD_sort(str, lo + count[r],
                     lo + count[r + 1] - 1, d + 1);
    }
 
    // Function to print an array
    static void print(String str[], int n)
    {
        for (int i = 0; i < n; i++) {
            System.out.print(str[i] + " ");
        }
        System.out.println();
    }
 
    // Driver Code
    public static void main(String[] args)
    {
 
        // Input String
        String str[] = { "midnight", "badge",  "bag",
                         "worker",   "banner", "wander" };
 
        // Size of the string
        int n = str.length;
 
        System.out.print("Unsorted array : ");
 
        // Print the unsorted array
        print(str, n);
 
        // Function Call
        MSD_sort(str, 0, n - 1, 0);
 
        System.out.print("Sorted array : ");
 
        // Print the sorted array
        print(str, n);
    }
}
 
// This code is contributed by Kingash.

C#

// C# program for the above approach
using System;
using System.Collections.Generic;
 
class GFG{
 
// Utility function to get the ASCII
// value of the character at index d
// in the string
static int char_at(String str, int d)
{
    if (str.Length <= d)
        return -1;
    else
        return(int)(str[d]);
}
 
// Function to sort the array using
// MSD Radix Sort recursively
static void MSD_sort(String []str, int lo,
                           int hi, int d)
{
     
    // Recursive break condition
    if (hi <= lo)
    {
        return;
    }
 
    // Stores the ASCII Values
    int []count = new int[256 + 1];
 
    // Temp is created to easily
    // swap strings in []str
    Dictionary temp = new Dictionary();
 
    // Store the occurrences of the most
    // significant character from
    // each string in []count
    for(int i = lo; i <= hi; i++)
    {
        int c = char_at(str[i], d);
        count++;
    }
 
    // Change []count so that []count
    // now contains actual position
    // of this digits in []temp
    for(int r = 0; r < 256; r++)
        count[r + 1] += count[r];
 
    // Build the temp
    for(int i = lo; i <= hi; i++)
    {
        int c = char_at(str[i], d);
        temp.Add(count++, str[i]);
    }
 
    // Copy all strings of temp to []str,
    // so that []str now contains
    // partially sorted strings
    for(int i = lo; i <= hi; i++)
        str[i] = temp[i - lo];
 
    // Recursively MSD_sort() on each
    // partially sorted strings set to
    // sort them by their next character
    for(int r = 0; r < 256; r++)
        MSD_sort(str, lo + count[r],
                      lo + count[r + 1] - 1,
                       d + 1);
}
 
// Function to print an array
static void print(String []str, int n)
{
    for(int i = 0; i < n; i++)
    {
        Console.Write(str[i] + " ");
    }
    Console.WriteLine();
}
 
// Driver Code
public static void Main(String[] args)
{
 
    // Input String
    String []str = { "midnight", "badge", "bag",
                     "worker", "banner", "wander" };
 
    // Size of the string
    int n = str.Length;
 
    Console.Write("Unsorted array : ");
 
    // Print the unsorted array
    print(str, n);
 
    // Function Call
    MSD_sort(str, 0, n - 1, 0);
 
    Console.Write("Sorted array : ");
 
    // Print the sorted array
    print(str, n);
}
}
 
// This code is contributed by shikhasingrajput
输出:
Unsorted array : midnight badge bag worker banner wander 
Sorted array : badge bag banner midnight wander worker

如果您想与行业专家一起参加直播课程,请参阅Geeks Classes Live