簡體   English   中英

為什么此 Shaker Sort 代碼在 C 中不起作用

[英]Why this Shaker Sort code doesn't work in C

我正在用 C 實現一個通用的 Shaker Sort 算法,並且各種網站以一種不斷給我分段錯誤和其他錯誤的方式呈現代碼,但在使用其他語言時它工作得很好。 例如,如果我將其保留在 C# 中,則此代碼沒有問題,但在將其調整為 C 后它停止工作。

這是我忠實地改編上述代碼的完整示例

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

// definition of a comparator interface needed by the sort function 
// to compare the values in the array passed as 'void *'
typedef int (*comparator)(void *, void *);

// implementation of the comparator interface for the int type
int int_comparator(void *a, void *b)
{
    int *aa = a;
    int *bb = b;
    return (*aa > *bb) - (*aa < *bb);
}

// generic swap, lacking error checking for the malloc call to keep things brief
void swap(void *a, void *b, size_t size)
{
    unsigned char *aa = a;
    unsigned char *bb = b;
    unsigned char *tmp = malloc(size);

    memcpy(tmp, aa, size);
    memcpy(aa, bb, size);
    memcpy(bb, tmp, size);
    free(tmp);
}

// takes the array, its length, the size of the type it contains, and a pointer 
// to a comparator function according to the type contained in the array
void shaker_sort(void *array, size_t length, size_t size, comparator cmp)
{
    // can't dereference a 'void *', so the array is 
    // now considered as a sequence of raw bytes
    unsigned char *arr = array;
    size_t start = 0;
    size_t end = length - 1;
    int swapped = 1;

    while (swapped) {
        swapped = 0;

        for (size_t i = start; i < end; i++) {
            // since we have a sequence of bytes, access to the original 
            // array elements happens by reading chunks of data of the
            // size of the type contained in the array
            if (cmp(&arr[i * size], &arr[i * size + size]) > 0) {
                swap(&arr[i * size], &arr[i * size + size], size);
                swapped = 1;
            }
        }

        if (!swapped) break;

        swapped = 0;
        end--;

        for (size_t i = end; i >= start; i--) {
            if (cmp(&arr[i * size], &arr[i * size + size]) > 0) {
                swap(&arr[i * size], &arr[i * size + size], size);
                swapped = 1;
            }
        }

        start++;
    }
}

int main(void)
{
    int arr[] = {3, 0, -4, 6, 1};
    size_t length = sizeof(arr) / sizeof(int);

    shaker_sort(arr, length, sizeof(int), int_comparator);

    for (size_t i = 0; i < length; i++) {
        printf("%d ", arr[i]);
    }

    puts("");
}

使用gcc -Wall -Wextra -pedantic -std=c11 test.c -o test編譯很好,但隨后會進入分段錯誤。 快速運行valgrind --tool=memcheck --leak-check=full ./test表明顯然我正在使用未初始化的值、執行無效讀取和其他便利。 為簡潔起見,我不包括輸出,但您可以復制整個代碼並重現我的確切結果。

現在,奇怪的是,如果我像這樣編寫 Shaker Sort 的第二個 for 循環,代碼可以與干凈的 valgrind 輸出完美配合:

for (size_t i = end; i > start; i--) {
    if (cmp(&arr[i * size], &arr[i * size - size]) < 0) {
        swap(&arr[i * size], &arr[i * size - size], size);
        swapped = 1;
    }
}

基本上循環現在在位置start + 1的元素處停止,而不是像以前一樣將當前元素與其后繼元素進行比較,而是將當前元素與其前驅元素進行比較 就是這樣,我完全不知道為什么原始形式的代碼在 C# 中可能還可以在 Java 和其他語言中使用,但在 C 中它需要這個小的調整。 有人可以對此事有所了解嗎?

starti沒有簽名,

    for (size_t i = end; i >= start; i--)

第一次這里start是 0

我倒數到 0,然后從 0 中減去 1 得到一些其他值,即無符號大於或等於零,循環繼續

這樣做:

    for (size_t i = end; i > start; i--) {
        if (cmp(&arr[i * size - size], &arr[i * size]) > 0) {
            swap(&arr[i * size - size ], &arr[i * size], size);
            swapped = 1;
        }

    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM