需要帮助找出C中快速排序实现中的错误原因

时间:2014-07-21 20:34:10

标签: c

我在Xcode中遇到一些奇怪的错误 - 线程1:EXC_BAD_ACCESS在下面的代码中

while(*w1 != '\0' && *w2 != '\0')

这是quicksort实现和比较方法:

void quicksort(char ***words, int start, int end){ //start is pivot
    if(start >= end){
        return;
    }
    int left = start;
    int right = end;

    int comp;
    while( left <= right ){
        do{
            char* w1 = (*words)[++left];
            char* w2 = (*words)[start];
            comp = compare(w1, w2);
        }while(comp < start); //while current left less than pivot

        do{
            char* w1= (*words)[--right];
            char* w2= (*words)[start];
            comp = compare(w1, w2);
        }while(comp >= start); //while current right is more or equal to pivot

        if(left < right){
            swap(words, left, right);
        }
    }
    swap(words, start, --left);
    quicksort(words, 0, left-1);
    quicksort(words, left+1, end);
}

int compare(char *w1, char *w2){
    while(*w1 != '\0' && *w2 != '\0'){
        if( *w1 < *w2 ){
            return -1;
        }else if( *w1 > *w2 ){
            return 1;
        }else{
            w1++;
            w2++;
        }
    }

    if(*w1 == *w2)
        return 0;
    else if(*w1 == '\0')
        return -1;
    else return 1;
}

以下是完整代码http://ideone.com/MZFaFO

我认为问题的原因可能在do-while之间。我用指针做得很糟糕......我将非常感谢你的帮助。我刚开始学习C,它完全杀了我。 :(

1 个答案:

答案 0 :(得分:3)

有很多错误(稍后会有更多错误),但我必须打开这个:

不要为快速排序实现传递右/左索引标记。你不需要它们,它们引入通用算法的复杂程度是不值得的。这是C.随着你得到指针算术免费。用它; 陶醉其中。有了这个,你的算法就会减少到一个的地方,在那里完成了offset-magic。其余的变得微不足道。

但首先是一些普通的家务管理,从比较器开始。如果这更简单,你就是法官:

int compare(char const *w1, char const *w2)
{
    while(*w1 && *w2)
    {
        if (*w1 < *w2)
            return -1;

        if (*w2++ < *w1++)
            return 1;
    }
    return *w2 ? -1 : (*w1 != 0);
}

唯一值得讨论的是最后一个条款,其中说:“如果我们完成w2仍然指向某个内容,则它必须长于w1,因此{{1} }是“less”,我们返回-1。否则,w1必须在string-end,所以如果w2不是(因此是“更大”)则返回1,否则返回0(它们'都在字符串结尾处。)

关于w1 - 元素。您只需交换驻留在指针数组中的指针值(地址)。因此...

swap

问题的问题(有多个)。首先,您正在尝试使用 this 完成什么:

void swap_ptrs(char **lhs, char **rhs)
{
    char *tmp = *lhs;
    *lhs = *rhs;
    *rhs = tmp;
}

do{ char* w1 = (*words)[++left]; char* w2 = (*words)[start]; comp = compare(w1, w2); }while(comp < start) 是指针数组的索引,start是比较的结果。它不返回索引,它返回comp-10。他们确实彼此没有没有。同样的问题发生在你的第二个while循环中。此外,您正在递增1(并在另一个循环中递减left过早。简而言之,根本不可能right

利用前面提到的指针数学以及提供的比较器和交换例程,这是快速分配相关分区的一种方法。注意,我们只需要两个参数:数组的基址,以及我们想要排序的序列的长度。递归时使用指针算法在需要时提供正确的起始点和长度。

quicksort

为了测试这个,一个简单的随机字符串生成实现:

void quicksort(char **words, size_t len)
{
    if (len < 2)
        return;

    char const *pvt = words[len/2];
    size_t lhs = 0, rhs=len-1;

    while( lhs < rhs )
    {
        while (compare(words[lhs], pvt) < 0)
            ++lhs;

        while (compare(words[rhs], pvt) > 0)
            --rhs;

        if (lhs <= rhs)
            swap_ptrs(words+lhs++, words+rhs--);
    }

    quicksort(words, rhs+1);
    quicksort(words+lhs, len-lhs);
}

输出(明显不同)

int main()
{
    srand((unsigned int)time(NULL));

    // allocate a string bed of 100 pointers
    static const size_t len = 100;
    char **arr = malloc(sizeof(*arr) * len);

    // populate with random strings ranging from 5 to 8 chars.
    for (size_t i=0; i<len; ++i)
    {
        int siz = 5 + rand() % 4;
        arr[i] = malloc(siz+1);
        for (size_t j=0; j<siz; ++j)
            arr[i][j] = 'A' + rand() % 26;
        arr[i][siz] = 0;
    }
    quicksort(arr, len);

    for (size_t i=0; i<len; ++i)
    {
        printf("%s\n", arr[i]);
        free(arr[i]);
    }
    free(arr);
}