浮点数的基数排序

Posted

技术标签:

【中文标题】浮点数的基数排序【英文标题】:Radix Sort for Floats 【发布时间】:2020-11-09 01:10:48 【问题描述】:

我想用基数对 C 中的浮点数进行排序。下面是我的代码。但是,我的输出不正确。例如,如果我使用 3.1、-5 和 1 运行代码,我的排序值将打印为 3.000000、-5.000000 和 1.000000。

我知道正确地将浮点数转换为 int 再转换回浮点数,我需要应用以下逻辑,但我不确定如何将其集成到 rfloat() 中,因为我尝试过并且遇到了很多错误。

我怎样才能正确地将按位基数排序应用于浮点数?

float x = 3.1, *y; 
    int *a; 
    
    a = (int *)&x; 
    y = (float *)a; 

    printf("%f",*y); 
#include <stdio.h>
#include <stdlib.h>

void rs(unsigned int *a, int c) 
    int i;
    int m = a[0];
    int bt = 0;
    unsigned int *b = malloc(0 * sizeof(int));

    for (i = 0; i < c; i++) 
        if (a[i] > m)
            m = a[i]; 
    

    while((m>>bt) > 0) 
        int buck[2] =  0 ;

        for (i = 0; i < c; i++)  
            buck[(a[i]>>bt)&1]++;
        

        for (i = 1; i < 2; i++)  
            buck[i] += buck[i-1];
        

        for (i = c-1; i >= 0; i--)  
            b[--buck[(a[i]>>bt)&1]] = a[i]; 
        

        for (i = 0; i < c; i++) 
            a[i] = b[i]; 
        
        bt++;
    
    free(b); 


void rfloat(float *arr, int c) 
    int d[c]; 
    int i; 
    
    for(i = 0; i < c; i++)
        d[i] = (int)arr[i];
    
    
    rs(d, c);
    
    for(i = 0; i < c; i++)
        arr[i] = (float)d[i]; 
    
    


int main() 
    int size;  
    int i; 
    float* arr = malloc(0* sizeof(float)); 
    
    printf("Size: "); 
    scanf("%d", &size); 
    
    for (int i = 0; i < size; i++)
        printf("Values: ");
        scanf("%f", &arr[i]); 
    
    
    rfloat(arr, size); 
    
    printf("Sorted: ");
    for (i = 0; i < size; i++)
        printf("%f ", arr[i]);
    
    free(arr); 

【问题讨论】:

你认为这是做什么的:malloc(0 * sizeof(int));?返回值将是 0 或无法取消引用的指针。 OT:编译时,始终启用警告,然后修复这些警告。 (对于gcc,至少使用:-Wall -Wextra -Wconversion -pedantic -std=gnu11)注意:其他编译器使用不同的选项来实现相同的结果。 【参考方案1】:

Positive 浮点数的排序顺序与您将它们的位模式排序为无符号整数时的顺序相同。负浮点数不会,它们按 reverse 顺序排序,而不是按位模式排序。此外,如果您要按位模式排序,负浮点数会在正数浮点数之后排序,因为它们的最高位已设置。

那么我们该怎么办?我们进行改造。如果设置了最高位(使负数在它们之间正确排序),我们翻转所有其他位,并且我们总是翻转最高位(使负数和正数正确排序)。然后在排序后我们反转转换。

无需四舍五入!

void rfloat(float* arr, size_t size) 
    assert(sizeof(unsigned) == sizeof(float) && sizeof(float) == 4);
    unsigned* d = malloc(size * sizeof(unsigned));
    
    for (size_t i = 0; i < size; i++) 
        // Interpret float as 32-bit unsigned.
        d[i] = *(unsigned*) &(arr[i]);

        // Flip all except top if top bit is set.
        d[i] ^= (((unsigned) (((int) d[i]) >> 31)) >> 1);

        // Flip top bit.
        d[i] ^= (1u << 31);
    
    
    rs(d, size);
    
    // Inverse transform.
    for (size_t i = 0; i < size; i++) 
        d[i] ^= (1u << 31);
        d[i] ^= (((unsigned) (((int) d[i]) >> 31)) >> 1);
        arr[i] = *(float*) &(d[i]);
    
    
    free(d);


请注意,您的代码在此之后仍然无法正常工作。您的基数排序例程有问题。但那是另一个问题,如果你自己想不通的话。

【讨论】:

我有办法保留小数位吗?例如,如果我输入 -123456.1234567 作为要排序的值之一,我希望它保持为 -123456.1234567。目前,它打印为 -123456.125000。我试过 printf(".7%f ", arr[i]);但我认为在转换值时会在 rfloat() 中发生损失。 @mathisfun1234 不,这是float 的基本限制。您需要使用double(也可以使用上述技巧,但您需要使用 64 位整数并更改一些常量)。

以上是关于浮点数的基数排序的主要内容,如果未能解决你的问题,请参考以下文章

用于浮点数的快速、基于等级的基数排序?

浮点数在c中的基数排序

如何使用分布排序(基数排序等)对字符串进行排序?

10基数排序

排序算法 (11.基数排序)

排序算法之基数排序