无法使基数排序算法在C ++中工作

时间:2015-02-25 18:34:15

标签: c++ algorithm sorting recursion radix

给定n 32位整数(假设它们是正数),您希望通过首先查看总位中最重要的shift并递归排序由它创建的每个桶来对它们进行排序。这些位上的整数排序。

因此,如果shift为2,那么您将首先查看每个32位整数中的两个最高有效位,然后应用计数排序。最后,从您将获得的组中,您对每个组进行递归,并通过查看第三个和第四个最重要的位开始对每个组的编号进行排序。你递归地做这件事。

我的代码如下:

void radix_sortMSD(int start, int end, 
          int shift, int currentDigit, int input[])
{

    if(end <= start+1 || currentDigit>=32) return;

    /*
     find total amount of buckets
     which is basically 2^(shift)
    */
    long long int numberOfBuckets = (1UL<<shift);

    /*
     initialize a temporary array 
     that will hold the sorted input array
     after finding the values of each bucket.   
    */

    int tmp[end];

   /*
     Allocate memory for the buckets.
   */
   int *buckets = new int[numberOfBuckets + 1];

   /*
       initialize the buckets,
        we don't care about what's 
     happening in position numberOfBuckets+1
   */
   for(int p=0;p<numberOfBuckets + 1;p++)
         buckets[p] = 0;

   //update the buckets
   for (int p = start; p < end; p++)
      buckets[((input[p] >> (32 - currentDigit - shift)) 
                &   (numberOfBuckets-1)) + 1]++;

   //find the accumulative sum
   for(int p = 1; p < numberOfBuckets + 1; p++)
       buckets[p] += buckets[p-1];

   //sort the input array input and store it in array tmp   
   for (int p = start; p < end; p++){ 
    tmp[buckets[((input[p] >> (32 - currentDigit- shift)) 
            & (numberOfBuckets-1))]++] = input[p];
    }

   //copy all the elements in array tmp to array input
   for(int p = start; p < end; p++)
          input[p] = tmp[p];

   //recurse on all the groups that have been created
   for(int p=0;p<numberOfBuckets;p++){
       radix_sortMSD(start+buckets[p], 
       start+buckets[p+1], shift, currentDigit+shift, input);
    }

    //free the memory of the buckets
    delete[] buckets;
}

  int main()
  {

        int a[] = {1, 3, 2, 1, 4, 8, 4, 3};
        int n = sizeof(a)/sizeof(int);
        radix_sortMSD(0,n, 2,0,a);
        return 0;
   }

我可以想象这段代码中只有两个问题。

第一个问题是我是否在每次迭代中实际获得了整数的正确位。我假设如果我处于currentDigit位置,如果currentDigit = 0意味着我在我的整数的32位,那么得到下一个shift位,我在32 - currentDigit - shift个位置右移,然后我应用AND运算来获得shift最不重要的位,这正是我想要的位。

第二个问题是递归。我不认为我会对正确的群体进行宣传,但由于我不知道第一个问题是否真的得到了正确解决,我现在还不能说更多相关内容。

对此的任何反馈都将不胜感激。

提前谢谢。

EDIT:添加了main函数来显示我的radix函数是如何被调用的。

1 个答案:

答案 0 :(得分:1)

另一个更新,转换为数组类型的模板。 Tmp数组现在作为参数传递。删除了复制步骤并添加了一个辅助函数来返回已排序数据最终的缓冲区。使用400万个64位无符号整数进行测试,它可以工作但速度很慢。使用numberOfBits = 4实现的最快时间.numberOfBits不再需要精确划分每个元素的位数。

为了解释为什么MSD首先很慢,我将使用卡片分类器类比。想象一下,你有1000张卡片,每张卡片有3位数,000到999,按随机顺序排列。通常你用第三个数字穿过分拣机,每个箱子里有100个卡,bin 0用“0”保持卡片,... bin 9用“9”保持卡片。然后,您将卡从bin 0连接到bin 9,然后使用第二个数字再次通过分拣机运行它们,再次使用第一个数字,生成一组已排序的卡片。这是每次运行1000张卡的3次运行,因此共有3000张卡通过分拣机。

现在再次从随机订购的卡开始,按第1位排序。您无法连接这些集,因为具有较高的第1位但较低的第2位的卡最终会出现故障。所以现在你必须做10次运行,每次100卡。这样就产生了100组10张卡片,您可以通过分拣机再次运行,每张卡片分别生成1000套1张卡片,现在可以对卡片进行分类。因此,通过分拣机运行的卡数量仍为3,000,与上述相同,但您必须进行111次运行(1次1000卡套,10套100套卡,100套10套卡)。

template <typename T>
void RadixSortMSD(size_t start, size_t end, 
          size_t numberOfBits, size_t currentBit, T input[], T tmp[])
{
    if((end - start) < 1)
        return;

    // adjust numberOfBits if currentBit close to end element
    if((currentBit + numberOfBits) > (8*sizeof(T)))
        numberOfBits = (8*sizeof(T)) - currentBit;

    // set numberOfBuckets
    size_t numberOfBuckets = 1 << numberOfBits;
    size_t bitMask = numberOfBuckets - 1;
    size_t shift = (8*sizeof(T)) - currentBit - numberOfBits;

    // create bucket info
    size_t *buckets = new size_t[numberOfBuckets+1];
    for(size_t p = 0; p < numberOfBuckets+1; p++)
        buckets[p] = 0;
    for(size_t p = start; p < end; p++)
        buckets[(input[p] >> shift) & bitMask]++;
    size_t m = start;
    for(size_t p = 0; p < numberOfBuckets+1; p++){
        size_t n = buckets[p];
        buckets[p] = m;
        m += n;
    }

    //sort the input array input and store it in array tmp   
    for (size_t p = start; p < end; p++){ 
        tmp[buckets[(input[p] >> shift) & bitMask]++] = input[p];
    }

    // restore bucket info
    for(size_t p = numberOfBuckets; p > 0; p--)
        buckets[p] = buckets[p-1];
    buckets[0] = start;

    // advance current bit
    currentBit += numberOfBits;
    if(currentBit < (8*sizeof(T))){
        //recurse on all the groups that have been created
        for(size_t p=0; p < numberOfBuckets; p++){
            RadixSortMSD(buckets[p], buckets[p+1],
                numberOfBits, currentBit, tmp, input);
        }
    }

    //free buckets
    delete[] buckets;
    return;
}

template <typename T>
T * RadixSort(T *pData, T *pTmp, size_t n)
{
size_t numberOfBits = 4;
    RadixSortMSD(0, n, numberOfBits, 0, pData, pTmp);
    // return the pointer to the sorted data
    if((((8*sizeof(T))+numberOfBits-1)/numberOfBits)&1)
        return pTmp;
    else
        return pData;
}