Sorting 负整数的基数排序
我正在尝试实现整数的基数排序,包括负整数。对于非负整数,我计划为数字0-9创建一个由10个队列组成的队列,并实现LSD算法。但我有点被负整数搞糊涂了。我现在想的是,继续为它们创建另一个包含10个队列的队列,并分别对它们进行排序,然后在最后,我将给出两个列表,一个包含已排序的负整数,另一个包含非负整数。最后我会合并它们 你觉得这个怎么样?有没有更有效的方法来处理负整数Sorting 负整数的基数排序,sorting,language-agnostic,radix-sort,radix,Sorting,Language Agnostic,Radix Sort,Radix,我正在尝试实现整数的基数排序,包括负整数。对于非负整数,我计划为数字0-9创建一个由10个队列组成的队列,并实现LSD算法。但我有点被负整数搞糊涂了。我现在想的是,继续为它们创建另一个包含10个队列的队列,并分别对它们进行排序,然后在最后,我将给出两个列表,一个包含已排序的负整数,另一个包含非负整数。最后我会合并它们 你觉得这个怎么样?有没有更有效的方法来处理负整数 谢谢大家! 您可以将符号视为一种特殊的数字。你在单位上排序,然后是十等,最后在标志上排序。这确实会为负片生成一个相反的顺序,然后您
谢谢大家! 您可以将符号视为一种特殊的数字。你在单位上排序,然后是十等,最后在标志上排序。这确实会为负片生成一个相反的顺序,然后您只需反转该桶中的内容即可。这就是旧的机械卡片分拣机的工作方式。还有一种解决方案是从数组中分离出负整数,使其为正,使用基数排序为正值,然后将其反转,并用排序后的非负数组追加 绝对!当然,你必须注意将消极因素从积极因素中分离出来,但幸运的是这很容易。在排序算法开始时,您需要做的就是围绕值0对数组进行分区。之后,基数排序在分区的下方和上方 下面是实际中的算法。我从Kevin Wayne和Bob Sedgewick的MSD基数排序中得出:
private static final int CUTOFF=15;
私有静态最终整数位每整数=32;
私有静态最终整数位每字节=8;
专用静态最终整数R=256;
公共无效排序(int[]a){
int firstPositiveIndex=分区(0,a,0,a.length-1);
int[]aux=新的int[a.length];
如果(第一个正指数>0){
recSort(a,第一个正索引,a.length-1,0,aux);
recSort(a,0,第一正索引-1,0,辅助);
}否则{//全部为正
recSort(a,0,a.length-1,0,aux);
}
}
私有void recSort(int[]a、int-lo、int-hi、int-d、int[]aux){
如果(d>4)返回;
if(hi lobitsToShift)和mask;
计数[c+1]++;
}
//计算指数
用于(int i=0;ibitsToShift)和掩码;
辅助[计数[c]+lo]=a[i];
计数[c]++;
}
//复写
对于(int i=lo;i0)
recSort(a、lo、lo+计数[0]-1、d+1、aux);
对于(int i=1;i0)
recSort(a,lo+计数[i-1],lo+计数[i]-1,d+1,辅助);
}
}
//插入排序a[lo..hi],从dth字符开始
私有void insertionSort(int[]a,int-lo,int-hi){
对于(inti=lo;ilo&a[j]如果((curHi-1)注意到符号位是有符号整数中的最高位,但默认情况下,所有数字都按基数排序处理为无符号整数。因此,您需要告诉算法负数小于正数。对于32位有符号整数,您可以先对三个较低字节进行排序,然后对第四个字节(较高)进行排序符号位反转的字节,所以0将用于负数,而不是1,因此它们将首先出现
我强烈建议按字节而不是按十进制数字对数字进行排序,因为机器提取字节要比提取数字容易得多。处理有符号值的最简单方法可能是偏移累积的起始位置(即,生成位置偏移)对最高有效位进行操作时。转换输入使所有数字都可以被视为无符号也是一个选项,但需要对值数组至少应用两次操作(一次用于准备输入,另一次用于恢复输出)
这使用了第一种技术以及字节大小的数字(字节访问通常更有效):
void lsdradixsort(int*a,size\n)
{
//按索引隔离整数字节。
自动bmask=[](整数x,大小i)
{
返回(静态_cast(x)>>i*8)&0xFF;
};
//分配临时缓冲区。
自动m=标准::使_唯一(n);
int*b=m.get();
//对于整数中的每个字节(假设为4字节整数)。
对于(尺寸i,j=0;j<4;j++){
//将计数器初始化为零;
大小\u t h[256]={},开始;
//直方图。
//计算索引字节值的每次出现次数。
对于(i=0;i0;i--)
b[--h[b任务(a[i-1],j)]]=a[i-1];
标准:交换(a,b);
}
}
注意:代码未经测试。对于任何错误/打字错误,我们深表歉意。如果不使用“位移位”和“按位与”进行基数计算,则基数排序不会比著名的比较排序快
计算机使用2的补码来表示有符号的数字,这里的符号位位于二进制数字的最左端,在内存中表示
例如
436163157(作为32位数字)=000110011111111 01010010 01010101
-436163157(作为32位数字)=1110000000000 10101101
1(作为32位数字)=000000000000000000000000000000000000001
-1(作为32位数字)=111111111111111111111111111111111111
0表示为=000000000000000000000000000
高地
private static final int CUTOFF = 15;
private static final int BITS_PER_INT = 32;
private static final int BITS_PER_BYTE = 8;
private static final int R = 256;
public void sort(int[] a){
int firstPositiveIndex = partition(0, a, 0, a.length-1);
int[] aux =new int[a.length];
if(firstPositiveIndex>0){
recSort(a, firstPositiveIndex, a.length-1, 0,aux);
recSort(a, 0, firstPositiveIndex-1, 0,aux);
}else{//all positive
recSort(a, 0, a.length-1, 0, aux);
}
}
private void recSort(int[] a, int lo, int hi, int d, int[] aux){
if(d>4)return;
if(hi-lo<CUTOFF){
insertionSort(a,lo, hi);
return;
}
int[] count = new int[R+1];
//compute counts
int bitsToShift = BITS_PER_INT-BITS_PER_BYTE*d-BITS_PER_BYTE;
int mask = 0b1111_1111;
for(int i = lo; i<=hi; i++){
int c = (a[i]>>bitsToShift) & mask;
count[c+1]++;
}
//compute indices
for(int i = 0; i<R; i++){
count[i+1]=count[i]+count[i+1];
}
//distribute
for(int i = lo; i<=hi; i++){
int c = (a[i]>>bitsToShift) & mask;
aux[count[c]+lo] = a[i];
count[c]++;
}
//copy back
for(int i = lo; i<=hi; i++){
a[i]=aux[i];
}
if(count[0]>0)
recSort(a, lo, lo+count[0]-1, d+1, aux);
for(int i = 1; i<R; i++){
if(count[i]>0)
recSort(a, lo+count[i-1], lo+count[i]-1, d+1, aux);
}
}
// insertion sort a[lo..hi], starting at dth character
private void insertionSort(int[] a, int lo, int hi) {
for (int i = lo; i <= hi; i++)
for (int j = i; j > lo && a[j] < a[j-1]; j--)
swap(a, j, j-1);
}
//returns the index of the partition or to the right of where it should be if the pivot is not in the array
public int partition(int pivot, int[] a, int lo, int hi){
int curLo = lo;
int curHi = hi;
while(curLo<curHi){
while(a[curLo]<pivot){
if((curLo+1)>hi)return hi+1;
curLo++;
}
while(a[curHi]>pivot){
if((curHi-1)<lo)return lo-1;
curHi--;
}
if(curLo<curHi){
swap(a, curLo, curHi);
if(a[curLo]!=pivot)curLo++;
if(a[curHi]!=pivot)curHi--;
}
}
return curLo;
}
private void swap(int[] a, int i1, int i2){
int t = a[i1];
a[i1]=a[i2];
a[i2]=t;
}
V = ( A[i] >> 24 ) & 255
public class RadixSortsInterviewQuestions {
private static final int MSB = 64;
static Map.Entry<Integer, Integer> twoSum(long[] a, long sum) {
int n = a.length - 1;
sort(a, MSB, 0, n);
for (int i = 0, j = n; i < j; ) {
long t = a[i] + a[j];
if (t == sum) {
return new SimpleImmutableEntry<>(i, j);
} else if (t < sum) {
i++;
} else {
j--;
}
}
return null;
}
// Binary MSD radix sort: https://en.wikipedia.org/wiki/Radix_sort#In-place_MSD_radix_sort_implementations
private static void sort(long[] a, int d, int lo, int hi) {
if (hi < lo || d < 1) return;
int left = lo - 1;
int right = hi + 1;
for (int i = left + 1; i < right; ) {
if (isBitSet(a[i], d)) {
swap(a, i, --right);
} else {
left++;
i++;
}
}
sort(a, d - 1, lo, left);
sort(a, d - 1, right, hi);
}
private static boolean isBitSet(long x, int k) {
boolean set = (x & 1L << (k - 1)) != 0;
// invert signed bit so that all positive integers come after negative ones
return (k == MSB) != set;
}
private static void swap(long[] a, int i, int j) {
long tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
}
Binary | 2s-comp | Flip sign
----------+----------+----------
0000 | 00 | -8
0001 | +1 | -7
0010 | +2 | -6
0011 | +3 | -5
0100 | +4 | -4
0101 | +5 | -3
0110 | +6 | -2
0111 | +7 | -1
1000 | -8 | 00
1001 | -7 | +1
1010 | -6 | +2
1011 | -5 | +3
1100 | -4 | +4
1101 | -3 | +5
1110 | -2 | +6
1111 | -1 | +7
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
static void sortbno(const int32_t* tab, // table of entries
int tabsz, // #entries in tab
int bno, // byte number in T
int* inidx, // current sorted index before this byte
int* outidx) // indices after sorting this byte
{
int count[256];
memset(count, 0, sizeof(count));
// count occurrences of each byte value
for (int i = 0; i < tabsz; i++) {
int32_t x = tab[i];
int v = (x >> (8 * bno)) & 0xff;
count[v]++;
}
// change count[i] so it now reflects the actual
// position of this byte value in outidx
if (bno == sizeof(tab[0]) - 1) {
/* account for signed bit for most-significant-byte */
for (int i = 129; i < 256; i++) {
count[i] += count[i - 1];
}
count[0] += count[255];
for (int i = 1; i < 128; i++) {
count[i] += count[i - 1];
}
} else {
for (int i = 1; i < 256; i++) {
count[i] += count[i - 1];
}
}
// fill outidx[]
for (int i = tabsz - 1; i >= 0; i--) {
int in = inidx[i];
int32_t x = tab[in];
int v = (x >> (8 * bno)) & 0xff;
outidx[--count[v]] = in;
}
}
/**
* Sort tab[].
* Return the indices into tab[] in ascending order.
*/
int* rsort(const int32_t* tab, int tabsz)
{
int* r[2];
r[0] = malloc(tabsz * sizeof(*r[0]));
r[1] = malloc(tabsz * sizeof(*r[1]));
if (! (r[0] && r[1]))
goto bail;
// Artificially assign indices to items
for (int i = 0; i < tabsz; i++) {
r[0][i] = i;
}
// Sort byte by byte. byte #0 is x & 0xff.
int bin = 0;
for (int i = 0; i < (int)sizeof(tab[0]); i++) {
sortbno(tab, tabsz, i, r[bin], r[1-bin]);
bin = !bin;
}
free(r[1-bin]);
return r[bin];
bail:
if (r[0]) free(r[0]);
if (r[1]) free(r[1]);
return 0;
}