qsort似乎改变了价值观

时间:2012-10-19 18:48:49

标签: c qsort

我遇到了以下问题:

int sort_compare(const void *x, const void *y) {
    const int *xi = *(const int **) x;
    const int *yi = *(const int **) y;

    for (int i = 0; i < block_size; i++) {
        comp_x[i] = block[(*xi + i) % block_size];
        comp_y[i] = block[(*yi + i) % block_size];
    }

    return memcmp(comp_x, comp_y, block_size);
}

void sort() {
    for (int i = 0; i < block_size; i++) {
        printf("%d,", to_sort[i]);
    }
    puts("");
    qsort(to_sort, block_size, sizeof (int), sort_compare);
    for (int i = 0; i < block_size; i++) {
        printf("%d,", to_sort[i]);
    }
    puts("");
}

values:
    block_size = 5;
    block = "jkldj";
    comp_x, compy_y and to_sort are well allocated

output:
    0,1,2,3,4,
    3,0,1785357420,1,1684826986,

to_sort包含来自(圆形)字符串的第一个字母,例如

qwer
werq
erqw
rqwe

,表示为(0,1,2,3)需要排序为

erqw
rqwe
qwer
werq

,表示为(2,3,0,1)。我似乎得到了非常大的数字,为什么会这样?

提前致谢!

3 个答案:

答案 0 :(得分:2)

传递到比较器的xy是指向数组元素的指针。您的数组元素为int s,因此要获取int值,您需要将void指针转换为int指针并取消引用。你的代码中有一个额外的间接层,它应该看起来像这样:

int xi = *(const int *) x;
int yi = *(const int *) y;

然后在进行数据比较时,直接使用xiyi代替*xi*yi

作为优化,不需要将数据复制到单独的数组中,然后memcmp - 你可以在循环中自己比较它们:

for (int i = 0; i < block_size; i++) {
    char data_x = block[(xi + i) % block_size];
    char data_y = block[(yi + i) % block_size];
    if (data_x != data_y)
        return data_x - data_y;
}

return 0;

作为进一步优化,如果您将block数组中的数据加倍(例如,使其具有"qwerqwer"而不是"qwer"),则可以在单次调用memcmp,因为您不再需要处理环绕声。 memcmp经过了大量优化,因此如果您拥有大量数据,那么使用memcmp然后手写的for循环可以快得多。

答案 1 :(得分:1)

初始化时

const int *xi = *(const int **) x;
const int *yi = *(const int **) y;

to_sort元素的地址被解释为const int**,然后取消引用以提供xiyi的值。这可以解释to_sort中的值(如果int* s大于int s,则可能超出此值)作为指针。

你应该投出void* s:

const int *xi = (const int *) x;
const int *yi = (const int *) y;

答案 2 :(得分:1)

qsort()通过给它一个N项的线性列表来唱歌,其中任何给定的项(n)地址可以使用基于每个'项'的地址+大小来计算。所以从简单的东西开始,简单来说就是一个指针列表。

首先,可以通过简单地将副本拼接到原始文件上来模拟缓冲区的循环(理想情况下,不是一个字符,但我不打算对一个字节进行狡辩)。即

"qwer" ==> "qwerqwer"

这可以通过以下方式完成:

char *buff = malloc(2 * blocksize);
memcpy(buff, to_sort, blocksize);
memcpy(buff+blocksize, to_sort, blocksize);

现在你有偏移0 ..(blocksize-1),每个都是chars的块大小,可以在没有任何特殊指针数学的情况下相互比较。

接下来,构建实际排序的指针列表,在本例中为

char** ptrs = malloc(sizeof(char*) * blocksize); 
for (i=0;i<blocksize;i++)
    ptrs[i] = buff+i;

接下来,比较两个“项目”的功能。我们通过地址传递给我们的项目是指向字符串的指针。再次,地址过去的左右都是内存位置,我们会找到两个char *。地址本身不是 char *:

int block_compare(const void *left, const void *right)
{
    // memcmp would work for most platforms, but not all, so...
    return strncmp(*(char **)left, *(char **)right, blocksize);
}

最后,将其发送到qsort():

qsort(ptrs, blocksize, sizeof(char*), block_compare);

最终输出将是一个块大小的指向进入循环缓冲区的指针列表,每个指针都引用一个块大小的块。上述所有内容的全文如下:

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>

size_t blocksize = 0;

int block_compare(const void *left, const void *right)
{
    // memcmp would work for most platforms, but not all, so...
    return strncmp(*(char **)left, *(char **)right, blocksize);
}


int main(int argc, char* argv[])
{
    char to_sort[] = "qwer";
    size_t i = 0;

    // set blockize
    blocksize = strlen(to_sort);

    char *buff = malloc(2 * blocksize);
    memcpy(buff, to_sort, blocksize);
    memcpy(buff+blocksize, to_sort, blocksize);

    char ** ptrs = malloc(blocksize * sizeof(char*));
    for (i=0;i<blocksize;++i)
        ptrs[i] = buff+i;

    // now send the pointer list to qsort()
    qsort(ptrs, blocksize, sizeof(*ptrs), block_compare);

    // ptrs is sorted. do with it what you will.
    for (i=0;i<blocksize;i++)
    {
        fwrite(ptrs[i], sizeof(char), blocksize, stdout);
        fwrite("\n", sizeof(char), 1, stdout);
    }
    fflush(stdout);

    free(ptrs);
    free(buff);

    return EXIT_SUCCESS;
}

使用“qwer”产生:

erqw
qwer
rqwe
werq

另一个样本,使用“asubstantiallylongerstringtest”

allylongerstringtestasubstanti
antiallylongerstringtestasubst
asubstantiallylongerstringtest
bstantiallylongerstringtestasu
erstringtestasubstantiallylong
estasubstantiallylongerstringt
gerstringtestasubstantiallylon
gtestasubstantiallylongerstrin
iallylongerstringtestasubstant
ingtestasubstantiallylongerstr
llylongerstringtestasubstantia
longerstringtestasubstantially
lylongerstringtestasubstantial
ngerstringtestasubstantiallylo
ngtestasubstantiallylongerstri
ntiallylongerstringtestasubsta
ongerstringtestasubstantiallyl
ringtestasubstantiallylongerst
rstringtestasubstantiallylonge
stantiallylongerstringtestasub
stasubstantiallylongerstringte
stringtestasubstantiallylonger
substantiallylongerstringtesta
tantiallylongerstringtestasubs
tasubstantiallylongerstringtes
testasubstantiallylongerstring
tiallylongerstringtestasubstan
tringtestasubstantiallylongers
ubstantiallylongerstringtestas
ylongerstringtestasubstantiall

男人,我希望这就是你要找的东西。 (噢)。