Сортировка Цифровая - Поразрядная (Radix-Sort)

Числа сортируются по разрядам. Существует два варианта: least significant digit (LSD) и most significant digit (MSD). При LSD сортировке, сначала сортируются младшие разряды, затем старшие. При MSD сортировке все наоборот. При LSD сортировке получается следующий порядок: короткие ключи идут раньше длинных, ключи одного размера сортируются по алфавиту, это совпадает с нормальным представлением чисел: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10. При MSD сортировке получается алфавитный порядок, который подходит для сортировки строк. Например «b, c, d, e, f, g, h, i, j, ba» отсортируется как «b, ba, c, d, e, f, g, h, i, j». Если MSD применить к числам разной длины, то получим последовательность 1, 10, 2, 3, 4, 5, 6, 7, 8, 9.

 

 

Реализация алгоритма на различных языках программирования:

 

Ada

 

radix_sort.adb:

 

with Ada.Text_IO;
procedure Radix_Sort is
   type Integer_Array is array (Positive range <>) of Integer;
 
   procedure Least_Significant_Radix_Sort (Data : in out Integer_Array; Base : Positive := 10) is
      type Bucket is record
         Count   : Natural := 0;
         Content : Integer_Array (Data'Range);
      end record;
 
      subtype Bucket_Index is Integer range -Base + 1 .. Base - 1;
      type Bucket_Array is array (Bucket_Index) of Bucket;
 
      procedure Append (To : in out Bucket; Item : Integer) is
      begin
         To.Count := To.Count + 1;
         To.Content (To.Count) := Item;
      end Append;
 
      function Get_Nth_Digit (Value : Integer; N : Positive) return Integer is
         Result : Integer := (Value / (Base ** (N - 1))) mod Base;
      begin
         if Value < 0 then
            Result := -Result;
         end if;
         return Result;
      end Get_Nth_Digit;
 
      function Get_Maximum return Natural is
         Result : Natural := 0;
      begin
         for I in Data'Range loop
            if abs (Data (I)) > Result then
               Result := abs (Data (I));
            end if;
         end loop;
         return Result;
      end Get_Maximum;
 
      function Split (Pass : Positive) return Bucket_Array is
         Buckets : Bucket_Array;
      begin
         for I in Data'Range loop
            Append (To   => Buckets (Get_Nth_Digit (Data (I), Pass)),
                    Item => Data (I));
         end loop;
         return Buckets;
      end Split;
 
      function Merge (Buckets : Bucket_Array) return Integer_Array is
         Result        : Integer_Array (Data'Range);
         Current_Index : Positive := 1;
      begin
         for Sublist in Buckets'Range loop
            for Item in 1 .. Buckets (Sublist).Count loop
               Result (Current_Index) := Buckets (Sublist).Content (Item);
               Current_Index := Current_Index + 1;
            end loop;
         end loop;
         return Result;
      end Merge;
 
      Max_Number  : Natural := Get_Maximum;
      Digit_Count : Positive := 1;
   begin
      -- count digits of biggest number
      while Max_Number > Base loop
         Digit_Count := Digit_Count + 1;
         Max_Number := Max_Number / Base;
      end loop;
      for Pass in 1 .. Digit_Count loop
         Data := Merge (Split (Pass));
      end loop;
   end Least_Significant_Radix_Sort;
 
   Test_Array : Integer_Array := (170, 45, 75, -90, -802, 24, 2, 66);
begin
   Least_Significant_Radix_Sort (Test_Array, 4);
   for I in Test_Array'Range loop
      Ada.Text_IO.Put (Integer'Image (Test_Array (I)));
   end loop;
   Ada.Text_IO.New_Line;
end Radix_Sort;

 

AutoHotkey

 

Radix_Sort(data){
	loop, parse, data, `,
		n := StrLen(A_LoopField)>n?StrLen(A_LoopField):n
	loop % n {
		bucket := []	,	i := A_Index
		loop, parse, data, `,
			bucket[SubStr(A_LoopField,1-i)] .= (bucket[SubStr(A_LoopField,1-i)]?",":"") A_LoopField
		data := ""
		for i, v in bucket
			data .= (data?",":"") v
	}
	return data
}

 

BBC BASIC

 

Works with: BBC BASIC for Windows

 

The array index is assumed to start at zero. The third parameter of PROCradixsort() is the radix used.

 

DIM test%(9)
      test%() = 4, 65, 2, -31, 0, 99, 2, 83, 782, 1
      PROCradixsort(test%(), 10, 10)
      FOR i% = 0 TO 9
        PRINT test%(i%) ;
      NEXT
      PRINT
      END
 
      DEF PROCradixsort(a%(), n%, r%)
      LOCAL d%, e%, i%, l%, m%, b%(), bucket%()
      DIM b%(n%-1), bucket%(r%-1)
      FOR i% = 0 TO n%-1
        IF a%(i%) < l% l% = a%(i%)
        IF a%(i%) > m% m% = a%(i%)
      NEXT
      a%() -= l%
      m% -= l%
      e% = 1
      WHILE m% DIV e%
        bucket%() = 0
        FOR i% = 0 TO n%-1
          bucket%(a%(i%) DIV e% MOD r%) += 1
        NEXT
        FOR i% = 1 TO r%-1
          bucket%(i%) += bucket%(i% - 1)
        NEXT
        FOR i% = n%-1 TO 0 STEP -1
          d% = a%(i%) DIV e% MOD r%
          bucket%(d%) -= 1
          b%(bucket%(d%)) = a%(i%)
        NEXT
        a%() = b%()
        e% *= r%
      ENDWHILE
      a%() += l%
      ENDPROC

 

 

C

Radix sort, "digits" are most significant bits.

#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
 
typedef unsigned uint;
#define swap(a, b) { tmp = a; a = b; b = tmp; }
#define each(i, x) for (i = 0; i < x; i++)
 
/* sort unsigned ints */
static void rad_sort_u(uint *from, uint *to, uint bit)
{
	if (!bit || to < from + 1) return;
 
	uint *ll = from, *rr = to - 1, tmp;
	while (1) {
		/* find left most with bit, and right most without bit, swap */
		while (ll < rr && !(*ll & bit)) ll++;
		while (ll < rr &&  (*rr & bit)) rr--;
		if (ll >= rr) break;
		swap(*ll, *rr);
	}
 
	if (!(bit & *ll) && ll < to) ll++;
	bit >>= 1;
 
	rad_sort_u(from, ll, bit);
	rad_sort_u(ll, to, bit);
}
 
/* sort signed ints: flip highest bit, sort as unsigned, flip back */
static void radix_sort(int *a, const size_t len)
{
	size_t i;
	uint *x = (uint*) a;
 
	each(i, len) x[i] ^= INT_MIN;
	rad_sort_u(x, x + len, INT_MIN);
	each(i, len) x[i] ^= INT_MIN;
}
 
static inline void radix_sort_unsigned(uint *a, const size_t len)
{
	rad_sort_u(a, a + len, (uint)INT_MIN);
}
 
int main(void)
{
	int len = 16, x[16], i;
	size_t len = 16, i;
	each(i, len) x[i] = rand() % 512 - 256;
 
	radix_sort(x, len);
 
	each(i, len) printf("%d%c", x[i], i + 1 < len ? ' ' : '\n');
 
	return 0;
}

 

C++

#include <algorithm>
#include <iostream>
#include <iterator>
 
// Radix sort comparator for 32-bit two's complement integers
class radix_test
{
    const int bit; // bit position [0..31] to examine
public:
    radix_test(int offset) : bit(offset) {} // constructor
 
    bool operator()(int value) const // function call operator
    {
        if (bit == 31) // sign bit
            return value < 0; // negative int to left partition
        else
            return !(value & (1 << bit)); // 0 bit to left partition
    }
};
 
// Least significant digit radix sort
void lsd_radix_sort(int *first, int *last)
{
    for (int lsb = 0; lsb < 32; ++lsb) // least-significant-bit
    {
        std::stable_partition(first, last, radix_test(lsb));
    }
}
 
// Most significant digit radix sort (recursive)
void msd_radix_sort(int *first, int *last, int msb = 31)
{
    if (first != last && msb >= 0)
    {
        int *mid = std::partition(first, last, radix_test(msb));
        msb--; // decrement most-significant-bit
        msd_radix_sort(first, mid, msb); // sort left partition
        msd_radix_sort(mid, last, msb); // sort right partition
    }
}
 
// test radix_sort
int main()
{
    int data[] = { 170, 45, 75, -90, -802, 24, 2, 66 };
 
    lsd_radix_sort(data, data + 8);
    // msd_radix_sort(data, data + 8);
 
    std::copy(data, data + 8, std::ostream_iterator<int>(std::cout, " "));
 
    return 0;
}

 

C#

#include <algorithm>
#include <iostream>
#include <iterator>
 
// Radix sort comparator for 32-bit two's complement integers
class radix_test
{
    const int bit; // bit position [0..31] to examine
public:
    radix_test(int offset) : bit(offset) {} // constructor
 
    bool operator()(int value) const // function call operator
    {
        if (bit == 31) // sign bit
            return value < 0; // negative int to left partition
        else
            return !(value & (1 << bit)); // 0 bit to left partition
    }
};
 
// Least significant digit radix sort
void lsd_radix_sort(int *first, int *last)
{
    for (int lsb = 0; lsb < 32; ++lsb) // least-significant-bit
    {
        std::stable_partition(first, last, radix_test(lsb));
    }
}
 
// Most significant digit radix sort (recursive)
void msd_radix_sort(int *first, int *last, int msb = 31)
{
    if (first != last && msb >= 0)
    {
        int *mid = std::partition(first, last, radix_test(msb));
        msb--; // decrement most-significant-bit
        msd_radix_sort(first, mid, msb); // sort left partition
        msd_radix_sort(mid, last, msb); // sort right partition
    }
}
 
// test radix_sort
int main()
{
    int data[] = { 170, 45, 75, -90, -802, 24, 2, 66 };
 
    lsd_radix_sort(data, data + 8);
    // msd_radix_sort(data, data + 8);
 
    std::copy(data, data + 8, std::ostream_iterator<int>(std::cout, " "));
 
    return 0;
}

 

D

Короткая версия

 

import std.stdio, std.math, std.traits, std.range, std.algorithm;
 
ElementType!R[] radixSort(size_t N=10, R)(R r)
if (hasLength!R && isRandomAccessRange!R &&
    isIntegral!(ElementType!R)) {
    alias ElementType!R E;
 
    static if (isDynamicArray!R)
        alias r res;         // input is array => in place sort
    else
        E[] res = r.array(); // input is Range => return a new array
 
    E absMax = r.map!abs().reduce!max();
    immutable nPasses = 1 + cast(int)(log(absMax) / log(N));
 
    foreach (pass; 0 .. nPasses) {
        auto bucket = new E[][](2 * N - 1, 0);
        foreach (v; res) {
            int bIdx = abs(v / (N ^^ pass)) % N;
            bIdx = (v < 0) ? -bIdx : bIdx;
            bucket[N + bIdx - 1] ~= v;
        }
        res = bucket.join();
    }
 
    return res;
}
 
void main() {
    auto items = [170, 45, 75, -90, 2, 24, -802, 66];
    items.radixSort().writeln();
    items.map!q{1 - a}().radixSort().writeln();
}

 

 

 

Нормальная версия

 

import std.array, std.traits;
 
// considered pure for this program
extern(C) void* alloca(in size_t length) pure nothrow;
 
void radixSort(size_t MAX_ALLOCA=5_000, U)(U[] data)
pure nothrow if (isUnsigned!U) {
    static void radix(in uint byteIndex, in U[] source, U[] dest)
    pure nothrow {
        immutable size_t sourceSize = source.length;
        ubyte* curByte = (cast(ubyte*)source.ptr) + byteIndex;
        uint[ubyte.max + 1] byteCounter;
        for (size_t i = 0; i < sourceSize; i++, curByte += U.sizeof)
            byteCounter[*curByte]++;
 
        {
            uint indexStart;
            foreach (uint i; 0 .. byteCounter.length) {
                immutable size_t tempCount = byteCounter[i];
                byteCounter[i] = indexStart;
                indexStart += tempCount;
            }
        }
 
        curByte = (cast(ubyte*)source.ptr) + byteIndex;
        for (size_t i = 0; i < sourceSize; i++, curByte += U.sizeof) {
            uint* countPtr = byteCounter.ptr + *curByte;
            dest[*countPtr] = source[i];
            (*countPtr)++;
        }
    }
 
    U[] tempData;
    if (U.sizeof * data.length <= MAX_ALLOCA) {
        U* ptr = cast(U*)alloca(data.length * U.sizeof);
        if (ptr != null)
            tempData = ptr[0 .. data.length];
    }
    if (tempData.empty)
        tempData = uninitializedArray!(U[])(data.length);
 
    static if (U.sizeof == 1) {
        radix(0, data, tempData);
        data[] = tempData[];
    } else {
        for (uint i = 0; i < U.sizeof; i += 2) {
            radix(i + 0, data, tempData);
            radix(i + 1, tempData, data);
        }
    }
}
 
void main() {
    import std.stdio;
    uint[] items = [170, 45, 75, 4294967206, 2, 24, 4294966494, 66];
    items.radixSort();
    writeln(items);
}

 

 

 

Go

 

';

LSD radix 256, negatives handled by flipping the high bit.

 

package main
 
import (
    "bytes"
    "encoding/binary"
    "fmt"
)
 
// declarations for word size of data
type word int32
const wordLen = 4
const highBit = -1 << 31
 
var data = []word{170, 45, 75, -90, -802, 24, 2, 66}
 
func main() {
    buf := bytes.NewBuffer(nil)
    ds := make([][]byte, len(data))
    for i, x := range data {
        binary.Write(buf, binary.LittleEndian, x^highBit)
        b := make([]byte, wordLen)
        buf.Read(b)
        ds[i] = b
    }
    bins := make([][][]byte, 256)
    for i := 0; i < wordLen; i++ {
        for _, b := range ds {
            bins[b[i]] = append(bins[b[i]], b)
        }
        j := 0
        for k, bs := range bins {
            copy(ds[j:], bs)
            j += len(bs)
            bins[k] = bs[:0]
        }
    }
    fmt.Println("original:", data)
    var w word
    for i, b := range ds {
        buf.Write(b)
        binary.Read(buf, binary.LittleEndian, &w)
        data[i] = w^highBit
    }
    fmt.Println("sorted:  ", data)
}

 

Groovy

 

def radixSort = { final radixExponent, list ->
    def fromBuckets = new TreeMap([0:list])
    def toBuckets = new TreeMap()
    final radix = 2**radixExponent
    final mask = radix - 1
    final radixDigitSize = (int)Math.ceil(64/radixExponent)
    final digitWidth = radixExponent
    (0..<radixDigitSize).each { radixDigit ->
        fromBuckets.values().findAll { it != null }.flatten().each {
            print '.'
            long bucketNumber = (long)((((long)it) >>> digitWidth*radixDigit) & mask)
            toBuckets[bucketNumber] = toBuckets[bucketNumber] ?: []
            toBuckets[bucketNumber] << it
        }
        (fromBuckets, toBuckets) = [toBuckets, fromBuckets]
        toBuckets.clear()
    }
    final overflow = 2**(63 % radixExponent)
    final pos = {it < overflow}
    final neg = {it >= overflow}
    final keys = fromBuckets.keySet()
    final twosComplIndx = [] + (keys.findAll(neg)) + (keys.findAll(pos))
    twosComplIndx.collect { fromBuckets[it] }.findAll { it != null }.flatten()
}

 

Haskell

 

import Data.Bits (Bits(testBit, bitSize))
import Data.List (partition)
 
lsdSort :: (Ord a, Bits a) => [a] -> [a]
lsdSort = fixSort positiveLsdSort
 
msdSort :: (Ord a, Bits a) => [a] -> [a]
msdSort = fixSort positiveMsdSort
 
-- Fix a sort that puts negative numbers at the end, like positiveLsdSort and positiveMsdSort
fixSort sorter list = uncurry (flip (++)) (break (< 0) (sorter list))
 
positiveLsdSort :: (Bits a) => [a] -> [a]
positiveLsdSort list = foldl step list [0..bitSize (head list)] where
	step list bit = uncurry (++) (partition (not . flip testBit bit) list)
 
positiveMsdSort :: (Bits a) => [a] -> [a]
positiveMsdSort list = aux (bitSize (head list) - 1) list where
	aux _ [] = []
	aux (-1) list = list
	aux bit list = aux (bit - 1) lower ++ aux (bit - 1) upper where
		(lower, upper) = partition (not . flip testBit bit) list

 

 

 

 

Icon and Unicon

 

The following is nice and short and works in both languages. However it contains a subtle inefficiency: subscripting a numeric value first coerces it into a string.

 

procedure main(A)
    every writes((!rSort(A)||" ")|"\n")
end
 
procedure rSort(A)
    every (min := A[1]) >:= !A
    every (mlen := *(A[1]-min)) <:= (!A - min)
    every i := !*mlen do {
        every put(b := [], |[]\12)
        every a := !A do put(b[(a-min)[-i]+2|1], a)
        every put(A := [],!!b)
        }
    return A
end

 

J

 

radixSortR =: 3 : 0  NB. base radixSort data
16 radixSortR y
:
keys =. x #.^:_1 y NB. compute keys
length =. #{.keys
extra =. (-length) {."0 buckets =. i.x
for_pass. i.-length do.
   keys =. ; (buckets,pass{"1 keys) <@:}./.extra,keys
end.
x#.keys NB. restore the data
)

 

 

 

 

Java

 

public static int[] sort(int[] old) {
    // Loop for every bit in the integers
    for (int shift = Integer.SIZE - 1; shift > -1; shift--) {
        // The array to put the partially sorted array into
        int[] tmp = new int[old.length];
        // The number of 0s
        int j = 0;
 
        // Move the 0s to the new array, and the 1s to the old one
        for (int i = 0; i < old.length; i++) {
            // If there is a 1 in the bit we are testing, the number will be negative
            boolean move = old[i] << shift >= 0;
 
            // If this is the last bit, negative numbers are actually lower
            if (shift == 0 ? !move : move) {
                tmp[j] = old[i];
                j++;
            } else {
                // It's a 1, so stick it in the old array for now
                old[i - j] = old[i];
            }
        }
 
        // Copy over the 1s from the old array
        for (int i = j; i < tmp.length; i++) {
            tmp[i] = old[i - j];
        }
 
        // And now the tmp array gets switched for another round of sorting
        old = tmp;
    }
 
    return old;
}

 

 

 

Translation of: NetRexx

 

 
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
 
public class RSortingRadixsort00 {
 
  public RSortingRadixsort00() {
 
    return;
  }
 
  public static int[] lsdRadixSort(int[] tlist) {
 
    List<Integer> intermediates;
    int[] limits = getLimits(tlist);
    tlist = rescale(tlist, limits[1]);
 
    for (int px = 1; px <= limits[2]; ++px) {
      @SuppressWarnings("unchecked")
      Queue<Integer> bukits[] = new Queue[10];
      for (int ix = 0; ix < tlist.length; ++ix) {
        int cval = tlist[ix];
        int digit = (int) (cval / Math.pow(10, px - 1) % 10);
        if (bukits[digit] == null) {
          bukits[digit] = new LinkedList<>();
        }
        bukits[digit].add(cval);
      }
 
      intermediates = new ArrayList<>();
      for (int bi = 0; bi < 10; ++bi) {
        if (bukits[bi] != null) {
          while (bukits[bi].size() > 0) {
            int nextd;
            nextd = bukits[bi].poll();
            intermediates.add(nextd);
          }
        }
      }
 
      for (int iw = 0; iw < intermediates.size(); ++iw) {
        tlist[iw] = intermediates.get(iw);
      }
    }
 
    tlist = rescale(tlist, -limits[1]);
 
    return tlist;
  }
 
  private static int[] rescale(int[] arry, int delta) {
 
    for (int ix = 0; ix < arry.length; ++ix) {
      arry[ix] -= delta;
    }
 
    return arry;
  }
 
  private static int[] getLimits(int[] tlist) {
 
    int[] lims = new int[3];
 
    for (int i_ = 0; i_ < tlist.length; ++i_) {
      lims[0] = Math.max(lims[0], tlist[i_]);
      lims[1] = Math.min(lims[1], tlist[i_]);
    }
    lims[2] = (int) Math.ceil(Math.log10(lims[0] - lims[1]));
 
    return lims;
  }
 
  private static void runSample(String[] args) {
 
    int[][] lists = {
      new int[] { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10, },
      new int[] { -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, -0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, },
      new int[] { 2, 24, 45, 0, 66, 75, 170, -802, -90, 1066, 666, },
      new int[] { 170, 45, 75, 90, 2, 24, 802, 66, },
      new int[] { -170, -45, -75, -90, -2, -24, -802, -66, },
    };
 
    long etime;
    lsdRadixSort(Arrays.copyOf(lists[0], lists[0].length)); // do one pass to set up environment to remove it from timings
 
    for (int[] tlist : lists) {
      System.out.println(array2list(tlist));
      etime = System.nanoTime();
      tlist = lsdRadixSort(tlist);
      etime = System.nanoTime() - etime;
      System.out.println(array2list(tlist));
      System.out.printf("Elapsed time: %fs%n", ((double) etime / 1_000_000_000.0));
      System.out.println();
    }
 
    return;
  }
 
  private static List<Integer> array2list(int[] arry) {
 
    List<Integer> target = new ArrayList<>(arry.length);
 
    for (Integer iv : arry) {
      target.add(iv);
    }
 
    return target;
  }
 
  public static void main(String[] args) {
 
    runSample(args);
 
    return;
  }
}

 

 

jq

 

# Sort the input array;
# "base" must be an integer greater than 1
def radix_sort(base):
  # We only need the ceiling of non-negatives:
  def ceil: if . == floor then . else (. + 1 | floor) end;
 
  min as $min
  | map(. - $min)
  | ((( max|log) / (base|log)) | ceil) as $rounds
  | reduce range(0; $rounds) as $i
      # state: [ base^i, buckets ]
      ( [1, .];
        .[0] as $base_i
        | reduce .[1][] as $n 
            ([];
             (($n/$base_i) % base) as $digit
             | .[$digit] += [$n] )
        | [($base_i * base), (map(select(. != null)) | flatten)] )
  | .[1]
  | map(. + $min) ;
 
def radix_sort:
  radix_sort(10);
 

Mathematica

 

ClearAll[SortByPos, RadixSort]
SortByPos[data : {_List ..}, pos_Integer] := Module[{digs, order},
  digs = data[[All, pos]];
  order = Ordering[digs];
  data[[order]]
  ]
RadixSort[x : {_Integer ..}] := Module[{y, digs, maxlen, offset},
  offset = Min[x];
  y = x - offset;
  digs = IntegerDigits /@ y;
  maxlen = Max[Length /@ digs];
  digs = IntegerDigits[#, 10, maxlen] & /@ y;
  digs = Fold[SortByPos, digs, -Range[maxlen]];
  digs = FromDigits /@ digs;
  digs += offset;
  digs
  ]

NetRexx

 

/* NetRexx */
options replace format comments java crossref symbols nobinary
 
runSample(arg)
return
 
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
method radixSort(tlist = Rexx[]) public static returns Rexx[]
 
  -- scale the array to start at zero to allow handling of -ve values
  parse getLimits(tlist) maxn minn maxl .
  tlist = rescale(tlist, minn)
 
  loop px = maxl to 1 by -1
    bukits = ''
    loop ix = 0 to tlist.length - 1
      cval = tlist[ix].right(maxl, 0)
      parse cval . =(px) digit +1 .
      bukits[digit] = bukits[digit] (cval + 0) -- simulates a stack
      end ix
    intermediates = ''
    loop bi = 0 to 9
      intermediates = intermediates bukits[bi] -- sumulates unstack
      end bi
    -- reload array
    loop iw = 1 to intermediates.words()
      tlist[iw - 1] = intermediates.word(iw)
      end iw
    end px
 
  -- restore the array to original scale
  tlist = rescale(tlist, -minn)
  return tlist
 
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
method rescale(arry = Rexx[], newbase) private static returns Rexx[]
  loop ix = 0 to arry.length - 1
    arry[ix] = arry[ix] - newbase
    end ix
  return arry
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
method getLimits(arry = Rexx[]) private static returns Rexx
  maxn = 0
  minn = 0
  maxl = 0
  loop i_ = 0 to arry.length - 1
    maxn = maxn.max(arry[i_])
    minn = minn.min(arry[i_])
    end i_
  maxl = (maxn - minn).length()
  return maxn minn maxl
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
method runSample(arg) private static
  lists = [-
    [2, 24, 45, 0, 66, 75, 170, -802, -90, 1066, 666], -
    [170, 45, 75, 90, 2, 24, 802, 66], -
    [10, 9, 8, 7, 8, 5, 4, 3, 2, 1, 0], -
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], -
    [-10, -9, -8, -7, -8, -5, -4, -3, -2, -1, -0], -
    [-0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10], -
    [-10, -19, -18, -17, -18, -15, -14, -13, -12, -11, -100], -
    [10, 9, 8, 7, 8, 5, 4, 3, 2, 1, 0, -0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10], -
    [-10, -9, -8, -7, -8, -5, -4, -3, -2, -1, -0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] -
  ]
 
  loop il = 0 to lists.length - 1
    tlist = lists[il]
    say ' Input:' Arrays.asList(tlist)
    say 'Output:' Arrays.asList(radixSort(tlist))
    say
    end il
  return
 

 

Output:

 

 Input: [2, 24, 45, 0, 66, 75, 170, -802, -90, 1066, 666]
Output: [-802, -90, 0, 2, 24, 45, 66, 75, 170, 666, 1066]

 Input: [170, 45, 75, 90, 2, 24, 802, 66]
Output: [2, 24, 45, 66, 75, 90, 170, 802]

 Input: [10, 9, 8, 7, 8, 5, 4, 3, 2, 1, 0]
Output: [0, 1, 2, 3, 4, 5, 7, 8, 8, 9, 10]

 Input: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Output: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

 Input: [-10, -9, -8, -7, -8, -5, -4, -3, -2, -1, 0]
Output: [-10, -9, -8, -8, -7, -5, -4, -3, -2, -1, 0]

 Input: [0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10]
Output: [-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0]

 Input: [-10, -19, -18, -17, -18, -15, -14, -13, -12, -11, -100]
Output: [-100, -19, -18, -18, -17, -15, -14, -13, -12, -11, -10]

 Input: [10, 9, 8, 7, 8, 5, 4, 3, 2, 1, 0, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10]
Output: [-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 0, 1, 2, 3, 4, 5, 7, 8, 8, 9, 10]

 Input: [-10, -9, -8, -7, -8, -5, -4, -3, -2, -1, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Output: [-10, -9, -8, -8, -7, -5, -4, -3, -2, -1, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

 
 

 

 

 

Using Collection classes

 

/* NetRexx */
options replace format comments java crossref symbols nobinary
 
import java.util.Queue
 
runSample(arg)
return
 
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
method radixSort(tlist = Rexx[]) public static returns Rexx[]
 
  -- scale the array to start at zero to allow handling of -ve values
  limits = ''
  parse '!MAXN !MINN !MAXL' maxn_ minn_ maxl_ .
  parse getLimits(tlist) maxn minn maxl .
  limits[maxn_] = maxn
  limits[minn_] = minn
  limits[maxl_] = maxl
  tlist = rescale(tlist, limits[minn_])
 
  loop px = limits[maxl_] to 1 by -1
    bukits = Queue[10] -- stacks for digits 0 .. 9
    loop ix = 0 while ix < tlist.length
      cval = tlist[ix].right(limits[maxl_], 0)
      parse cval . =(px) digit +1 . -- extract next digit (fun with parse)
      -- alternatively: digit = (cval % (10 ** (px - 1))) // 10
      if bukits[digit] == null then bukits[digit] = LinkedList()
      bukits[digit].add((cval + 0))
      end ix
 
    intermediates = ArrayList()
    loop bi = 0 to 9
      if bukits[bi] \= null then loop while bukits[bi].size() > 0
        nextd = bukits[bi].poll()
        intermediates.add(nextd)
        end
      end bi
 
    -- reload result array
    loop iw = 0 while iw < intermediates.size()
      tlist[iw] = Rexx intermediates.get(iw)
      end iw
    end px
 
  -- restore the array to original scale
  tlist = rescale(tlist, -limits[minn_])
  return tlist
 
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
method rescale(arry = Rexx[], newbase) private static returns Rexx[]
  loop ix = 0 to arry.length - 1
    arry[ix] = arry[ix] - newbase
    end ix
  return arry
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
method getLimits(arry = Rexx[]) private static returns Rexx
  maxn = 0
  minn = 0
  maxl = 0
  loop i_ = 0 to arry.length - 1
    maxn = maxn.max(arry[i_])
    minn = minn.min(arry[i_])
    end i_
  maxl = (maxn - minn).length()
  return maxn minn maxl
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
method runSample(arg) private static
  lists = [-
    [2, 24, 45, 0, 66, 75, 170, -802, -90, 1066, 666], -
    [170, 45, 75, 90, 2, 24, 802, 66], -
    [10, 9, 8, 7, 8, 5, 4, 3, 2, 1, 0], -
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], -
    [-10, -9, -8, -7, -8, -5, -4, -3, -2, -1, -0], -
    [-0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10], -
    [-10, -19, -18, -17, -18, -15, -14, -13, -12, -11, -100], -
    [10, 9, 8, 7, 8, 5, 4, 3, 2, 1, 0, -0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10], -
    [-10, -9, -8, -7, -8, -5, -4, -3, -2, -1, -0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] -
  ]
 
  loop il = 0 to lists.length - 1
    tlist = lists[il]
    say ' Input:' Arrays.asList(tlist)
    say 'Output:' Arrays.asList(radixSort(tlist))
    say
    end il
  return
 

Perl

 

#!/usr/bin/perl
use warnings;
use strict;
 
sub radix {
    my @tab = ([@_]);
 
    my $max_length = 0;
    length > $max_length and $max_length = length for @_;
    $_ = sprintf "%0${max_length}d", $_ for @{ $tab[0] }; # Add zeros.
 
    for my $pos (reverse -$max_length .. -1) {
        my @newtab;
        for my $bucket (@tab) {
            for my $n (@$bucket) {
                my $char = substr $n, $pos, 1;
                $char = -1 if '-' eq $char;
                $char++;
                push @{ $newtab[$char] }, $n;
            }
        }
        @tab = @newtab;
    }
 
    my @return;
    my $negative = shift @tab;                            # Negative bucket must be reversed.
    push @return, reverse @$negative;
    for my $bucket (@tab) {
        push @return, @{ $bucket // [] };
    }
    $_ = 0 + $_ for @return;                              # Remove zeros.
    return @return;
}

 

 

 

To test, add the following lines:

 

use Test::More tests => 1000;
 
for (1 .. 1000) {
    my @l = map int rand(2000) - 1000, 0 .. 20;
    is_deeply([radix(@l)], [sort { $a <=> $b } @l]);
}

 

 

 

 

Perl 6

 

sub radsort (@ints) {
    my $maxlen = [max] @ints».chars;
    my @list = @ints».fmt("\%0{$maxlen}d");
 
    for reverse ^$maxlen -> $r {
        my @buckets = @list.classify( *.substr($r,1) ).sort: *.key;
        if !$r and @buckets[0].key eq '-' { @buckets[0].value .= reverse }
        @list = map *.value.values, @buckets;
    }
    @list».Int;
}
 
.say for radsort (-2_000 .. 2_000).roll(20);

 

Output:

 

-1585
-1427
-1228
-1067
-945
-657
-643
-232
-179
-28
37
411
488
509
716
724
1504
1801
1864
1939

 
 

 

 

 

PicoLisp

 

(de radixSort (Lst)
   (let Mask 1
      (while
         (let (Pos (list NIL NIL)  Neg (list NIL NIL)  Flg)
            (for N Lst
               (queue
                  (if2 (ge0 N) (bit? Mask N)
                     (cdr Pos) Pos Neg (cdr Neg) )
                  N )
               (and (>= (abs N) Mask) (on Flg)) )
            (setq
               Lst (conc (apply conc Neg) (apply conc Pos))
               Mask (* 2 Mask) )
            Flg ) ) )
   Lst )

 

PureBasic

 

S
tructure bucket
  List i.i()
EndStructure
 
DataSection
  ;sets specify the size (1 based) followed by each integer
  set1:
  Data.i 10 ;size
  Data.i 1, 3, 8, 9, 0, 0, 8, 7, 1, 6 ;data
  set2:
  Data.i 8 
  Data.i 170, 45, 75, 90, 2, 24, 802, 66
  set3:
  Data.i 8
  Data.i 170, 45, 75, 90, 2, 24, -802, -66
EndDataSection
 
Procedure setIntegerArray(Array x(1), *setPtr) 
  Protected i, count
  count = PeekI(*setPtr) - 1 ;convert to zero based count
  *setPtr + SizeOf(Integer) ;move pointer forward to data
  Dim x(count)
  For i = 0 To count
    x(i) = PeekI(*setPtr + i * SizeOf(Integer))
  Next 
EndProcedure
 
Procedure displayArray(Array x(1))
  Protected i, Size = ArraySize(x())
  For i = 0 To Size
    Print(Str(x(i)))
    If i < Size: Print(", "): EndIf
  Next 
  PrintN("")
EndProcedure
 
Procedure radixSort(Array x(1), Base = 10)
  Protected count = ArraySize(x())
  If Base < 1 Or count < 1: ProcedureReturn: EndIf ;exit due to invalid values
 
  Protected i, pv, digit, digitCount, maxAbs, pass, index
  ;find element with largest number of digits
  For i = 0 To count
    If Abs(x(i)) > maxAbs
      maxAbs = Abs(x(i))
    EndIf 
  Next
 
  digitCount = Int(Log(maxAbs)/Log(Base)) + 1
 
  For pass = 1 To digitCount
    Dim sortBuckets.bucket(Base * 2 - 1)
    pv = Pow(Base, pass - 1)
 
    ;place elements in buckets according to the current place-value's digit
    For index = 0 To count
      digit = Int(x(index)/pv) % Base + Base
      AddElement(sortBuckets(digit)\i())
      sortBuckets(digit)\i() = x(index)
    Next
 
    ;transfer contents of buckets back into array
    index = 0
    For digit = 1 To (Base * 2) - 1
      ForEach sortBuckets(digit)\i()
        x(index) = sortBuckets(digit)\i()
        index + 1
      Next 
    Next
  Next
EndProcedure
 
If OpenConsole()
  Dim x(0)
  setIntegerArray(x(), ?set1)
  radixSort(x()): displayArray(x())
 
  setIntegerArray(x(), ?set2)
  radixSort(x()): displayArray(x())
 
  setIntegerArray(x(), ?set3)
  radixSort(x(), 2): displayArray(x())
 
  Print(#CRLF$ + #CRLF$ + "Press ENTER to exit"): Input()
  CloseConsole()
EndIf

 

Python

 

tructure bucket
  List i.i()
EndStructure
 
DataSection
  ;sets specify the size (1 based) followed by each integer
  set1:
  Data.i 10 ;size
  Data.i 1, 3, 8, 9, 0, 0, 8, 7, 1, 6 ;data
  set2:
  Data.i 8 
  Data.i 170, 45, 75, 90, 2, 24, 802, 66
  set3:
  Data.i 8
  Data.i 170, 45, 75, 90, 2, 24, -802, -66
EndDataSection
 
Procedure setIntegerArray(Array x(1), *setPtr) 
  Protected i, count
  count = PeekI(*setPtr) - 1 ;convert to zero based count
  *setPtr + SizeOf(Integer) ;move pointer forward to data
  Dim x(count)
  For i = 0 To count
    x(i) = PeekI(*setPtr + i * SizeOf(Integer))
  Next 
EndProcedure
 
Procedure displayArray(Array x(1))
  Protected i, Size = ArraySize(x())
  For i = 0 To Size
    Print(Str(x(i)))
    If i < Size: Print(", "): EndIf
  Next 
  PrintN("")
EndProcedure
 
Procedure radixSort(Array x(1), Base = 10)
  Protected count = ArraySize(x())
  If Base < 1 Or count < 1: ProcedureReturn: EndIf ;exit due to invalid values
 
  Protected i, pv, digit, digitCount, maxAbs, pass, index
  ;find element with largest number of digits
  For i = 0 To count
    If Abs(x(i)) > maxAbs
      maxAbs = Abs(x(i))
    EndIf 
  Next
 
  digitCount = Int(Log(maxAbs)/Log(Base)) + 1
 
  For pass = 1 To digitCount
    Dim sortBuckets.bucket(Base * 2 - 1)
    pv = Pow(Base, pass - 1)
 
    ;place elements in buckets according to the current place-value's digit
    For index = 0 To count
      digit = Int(x(index)/pv) % Base + Base
      AddElement(sortBuckets(digit)\i())
      sortBuckets(digit)\i() = x(index)
    Next
 
    ;transfer contents of buckets back into array
    index = 0
    For digit = 1 To (Base * 2) - 1
      ForEach sortBuckets(digit)\i()
        x(index) = sortBuckets(digit)\i()
        index + 1
      Next 
    Next
  Next
EndProcedure
 
If OpenConsole()
  Dim x(0)
  setIntegerArray(x(), ?set1)
  radixSort(x()): displayArray(x())
 
  setIntegerArray(x(), ?set2)
  radixSort(x()): displayArray(x())
 
  setIntegerArray(x(), ?set3)
  radixSort(x(), 2): displayArray(x())
 
  Print(#CRLF$ + #CRLF$ + "Press ENTER to exit"): Input()
  CloseConsole()
EndIf

 

 

Racket

#lang racket
 
(require data/queue)
 
(define (radix-sort l r)
  (define queues (for/vector #:length r ([_ r]) (make-queue)))
  (let loop ([l l] [R 1])
    (define all-zero? #t)
    (for ([x (in-list l)])
      (define x/R (quotient x R))
      (enqueue! (vector-ref queues (modulo x/R r)) x)
      (unless (zero? x/R) (set! all-zero? #f)))
    (if all-zero? l
        (loop (let q-loop ([i 0])
                (define q (vector-ref queues i))
                (let dq-loop ()
                  (if (queue-empty? q)
                    (if (< i (sub1 r)) (q-loop (add1 i)) '())
                    (cons (dequeue! q) (dq-loop)))))
              (* R r)))))
 
(for/and ([i 10000]) ; run some tests on random lists with a random radix
  (define (make-random-list)
    (for/list ([i (+ 10 (random 10))]) (random 100000)))
  (define (sorted? l)
    (match l [(list) #t] [(list x) #t]
           [(list x y more ...) (and (<= x y) (sorted? (cons y more)))]))
  (sorted? (radix-sort (make-random-list) (+ 2 (random 98)))))
;; => #t, so all passed

 

 

 

REXX

 

/*REXX program performs a   radix sort   on a  stemmed  integer array.  */
aList='0 2 3 4 5 5 7 6 6 7 11 7 13 9 8 8 17 8 19 9 10 13 23 9 10 15 9 11 29 10 31 10 14',
      '19 12 10 37 21 16 11 41 12 43 15 11 25 47 11 14 12 20 17 53 11 16 13 22 31 59 12',
      '61 33 13 12 18 16 67 21 26 14 71 12 73 39 13 23 18 18 79 13 12 43 83 14 22 45 32',
      '17 89 13 20 27 34 49 24 13 97 16 17 14 101 22 103 19 15 55 107 13 109 18 40 15 113 -42'
         /*excluding  -42,  the abbreviated list (above) is called the integer log function.*/
 
mina=word(aList,1);   maxa=mina;    n=words(aList);    w=length(n)
 
     do n=1  for n; x=word(aList,n); @.n=x  /*list ??? array.*/
     mina =min(x,mina);        maxa=max(x,maxa)
     width=max(length(abs(mina)),length(maxa))
     end   /*n*/
 
call radSort n
 
         do j=1  for n
         say 'item' right(j,w) "after the radix sort:"  right(@.j,width+1)
         end    /*j*/
exit                                   /*stick a fork in it, we're done.*/
/*???????????????????????????????????RADSORT subroutine?????????????????*/
radSort:  procedure expose @. width;  parse arg size;  mote=c2d(' ');  #=1
!.#._b=1;    !.#._i=1
!.#._n=size;     do i=1  for size;    y=@.i;     @.i=right(abs(y),width,0)
                 if y<0  then @.i='-'@.i
                 end   /*i*/
  /*??????????????????????????????????? where the rubber meets the road.?????????*/
  do while #\==0; ctr.=0; L='ffff'x; low=!.#._b; n=!.#._n; radi=!.#._i; H=    /*?*/
  #=#-1                                                                       /*?*/
        do j=low  for n;     parse var @.j =(radi) _ +1;     ctr._=ctr._+1    /*?*/
        if ctr._==1  then if _\==''  then do;      if _<<L  then L=_          /*?*/
                                                   if _>>H  then H=_          /*?*/
                                          end                                 /*?*/
        end   /*j*/                                                           /*?*/
  _=                                                                          /*?*/
  if L>>H  then iterate                                                       /*?*/
  if L==H  then if ctr._==0  then do;  #=#+1;  !.#._b = low                   /*?*/
                                               !.#._n = n                     /*?*/
                                               !.#._i = radi+1;    iterate    /*?*/
                                  end                                         /*?*/
  L=c2d(L);  H=c2d(H);    ?=ctr._+low;      top._=?;    ts=mote;     max=L    /*?*/
               do k=L  to H;    _=d2c(k,1);    cen=ctr._                      /*?*/
               if cen>ts  then  parse value    cen  k    with    ts  max      /*?*/
               ?=?+cen;   top._=?                                             /*?*/
               end   /*k*/                                                    /*?*/
  pivot=low                                                                   /*?*/
     do  while  pivot<low+n;         it=@.pivot                               /*?*/
          do forever                                                          /*?*/
          parse var it =(radi) _ +1; cen=top._-1; if pivot>=cen then leave    /*?*/
          top._=cen;  ?=@.cen;   @.cen=it;   it=?                             /*?*/
          end    /*forever*/                                                  /*?*/
     top._=pivot;     @.pivot=it;            pivot=pivot+ctr._                /*?*/
     end         /*while pivot<low+n*/                                        /*?*/
  i=max                                                                       /*?*/
      do  until i==max;  _=d2c(i,1);   i=i+1;  if i>H  then i=L;   d=ctr._    /*?*/
      if d<=mote then do; if d>1 then call .radSortP top._,d; iterate; end    /*?*/
      #=#+1;     !.#._b = top._                                               /*?*/
                 !.#._n = d                                                   /*?*/
                 !.#._i = radi+1                                              /*?*/
      end   /*until i==max*/                                                  /*?*/
  end       /*while #\==0 */                                                  /*?*/
  /*?????????????????????????????????????????????????????????????????????????????*/
#=0;   do i=size by -1 to 1; if @.i>=0  then iterate; #=#+1; @@.#=@.i; end
       do j=1 for size;      if @.j <0  then iterate; #=#+1; @@.#=@.j; end
       do k=1 for size;  @.k=@@.k+0; end  /*combine neg&pos radix lists*/
return
/*???????????????????????????????????.radSortP subroutine???????????????*/
.radSortP:     parse arg bb,nn
          do k=bb+1  for nn-1;    q=@.k
            do j=k-1  by -1  to bb  while q<<@.j;  jp=j+1;  @.jp=@.j;  end
                                                   jp=j+1;  @.jp=q
          end   /*k*/
return

Tcl

 

package require Tcl 8.5
proc splitByRadix {lst base power} {
    # create a list of empty lists to hold the split by digit
    set out [lrepeat [expr {$base*2}] {}]
    foreach item $lst {
	# pulls the selected digit
	set digit [expr {($item / $base ** $power) % $base + $base * ($item >= 0)}]
	# append the number to the list selected by the digit
	lset out $digit [list {*}[lindex $out $digit] $item]
    }
    return $out
}
 
# largest abs value element of a list
proc tcl::mathfunc::maxabs {lst} {
    set max [abs [lindex $lst 0]]
    for {set i 1} {$i < [llength $lst]} {incr i} {
	set v [abs [lindex $lst $i]]
	if {$max < $v} {set max $v}
    }
    return $max
}
 
proc radixSort {lst {base 10}} {
    # there are as many passes as there are digits in the longest number
    set passes [expr {int(log(maxabs($lst))/log($base) + 1)}]
    # For each pass...
    for {set pass 0} {$pass < $passes} {incr pass} {
	# Split by radix, then merge back into the list
	set lst [concat {*}[splitByRadix $lst $base $pass]]
    }
    return $lst
}

 

zkl

 

fcn radixSort(ns){ // ints only, inplace, ns is mutable
   b:=(0).pump(20,List,List.create.fpM("-"));  // 20 buckets: -10..10
   z:=ns.reduce(fcn(a,b){if(a.abs()>b.abs()) a else b},0); // max # digits
   m:=1;
   while(z){
      ns.apply2('wrap(n){b[(n/m)%10 +10].append(n)});    
      ns.clear(); b.apply2(ns.extend); // flatten ie sorted on mth digit
      b.apply("clear");  // reset buckets
      m *= 10; z /= 10;
   }
   ns
}

 

radixSort(T(170, 45, 75, 90, 802, 2, 24, 66)).println();
radixSort(T(170, 45, 75, -90, -802, 24, 2, 66)).println();

 

Output:

 

L(2,24,45,66,75,90,170,802)
L(-802,-90,2,24,45,66,75,170)

 

При написании статьи были использованы открытые источники сети интернет :

Wikipedia

Rosettacode

Youtube 

 

 

 







Видеотека

Яндекс.Метрика