簡體   English   中英

計算C中Quicksort的掉期交易

[英]Counting swaps in Quicksort in C

我試圖計算我在C中的快速排序中發生的掉期數量。但是,我得到的值不正確並且不確定我哪里出錯了。 我使用結構作為我的數組進行排序。

struct anArray{
int numbers[maxSize];
int swaps;
};

/* Partition function */
int partition(struct anArray *array, int start, int end){
if(start == end){
    return start;
}
int pivot = array->numbers[end];
int low = start - 1;
int high = end;

for(;;){
    do{
        low++;
    } while(array->numbers[low] < pivot);

    do{
        high--;
    } while(array->numbers[high] > pivot);

    /* Detector for when the cells meet */
    if(low >= high){
        swap(array, low, end);
        return low;
    }
  }
/* Swapping the values */
swap(array, low, high);
}

這是我用來“分離”數組的分區函數。

void quickSort(struct anArray *array, int start, int end){
if(end - start <= 0){ return; }
else{
    int pivot = array->numbers[end];
    int partitionPoint = partition(array, start, end);

    quickSort(array, start, partitionPoint - 1);
    quickSort(array, partitionPoint + 1, end);
  }
}

這是我的快速排序功能。 這是一個遞歸函數。 每次調用時,我的交換函數都會將計數器遞增1。

在我的主要內容中,我設置了myArray-> swaps = counter; 但掉期發生的次數不對。 例如,如果我對一個從1到9的數組進行排序,那么交換的數量應該是0,但是我得到9.我嘗試僅在分區函數中遞增計數器,但它給了我相同的結果。

我的分區功能有問題嗎?

非常感謝你

編輯1:

這是我的交換功能。

void swap(struct anArray *array, int first, int second){
int temp = array->numbers[first];
array->numbers[first] = array->numbers[second];
array->numbers[second] = temp;
counter++;
}

我試過用了

void swap(struct anArray *array, int first, int second, int swapCount)

然后在調用交換函數時將swapCount變為array-> swaps,並將其遞增1,但它給出了相同的答案。

這是我主要的一部分。

int main(){
  struct anArray *ascending = (struct anArray*)malloc(10 * sizeof(struct anArray));
  int ascend[maxSize] = {  1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
  initArray(ascending, ascend);

  quickSort(ascending, 0, maxSize - 1);
  ascending->swaps = counter;
  printf("Test: Unique random values\nSorted: [ ");
  for(int i = 0; i < maxSize; i++){
    printf("%i ", ascending->numbers[i]);
}
printf("]\nSwaps: %i\nComps: \n\n", ascending->swaps);

我的主要的其他部分只是要排序的其他數組。 initArray用於設置array-> numbers的值,並將array-> swaps重置為0。

你的快速排序代碼似乎很不錯。 我沒有嚴格檢查,但它通過了一個簡單的測試,所以我沒有進一步調查。 編輯:根據您的反饋,我在第二次更新中創建了第三個版本,顯示排序存在較大數據輸入的問題)。

主要的錯誤是main頂部的malloc 我們希望在結構數組 anArray

struct anArray *ascending = malloc(10 * sizeof(struct anArray));

也就是說,我們希望(例如)10層結構,我們希望有一個單一的結構,並在10個填補int是走成S numbers字段是在單一結構。

initArray函數沒有發布,所以我不得不猜測/推斷它可能是什么。 根據上面的錯誤,我不確定numbers是否會被正確初始化。

從發布的代碼片段中,我能夠將整個程序拼湊起來。 我創建了兩個版本:

一個帶有注釋[但不是固定]的錯誤編譯干凈。

並且,第二個完全清理,工作和推廣任意數組大小[請原諒無償的樣式清理]


這里有[接近]你的原始代碼,附帶注釋的bug:

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

// NOTE/BUG: this was not defined and _fixed_ defines should be all caps
#define maxSize     10

struct anArray {
    int numbers[maxSize];
    int swaps;
};

int counter;

void
initArray(struct anArray *array,const int *src)
{

    for (int idx = 0;  idx < maxSize;  ++idx)
        array->numbers[idx] = src[idx];

    array->swaps = 0;
}

void
swap(struct anArray *array, int first, int second)
{
    int temp = array->numbers[first];

    array->numbers[first] = array->numbers[second];
    array->numbers[second] = temp;
    counter++;
}

/* Partition function */
int
partition(struct anArray *array, int start, int end)
{
    if (start == end) {
        return start;
    }
    int pivot = array->numbers[end];
    int low = start - 1;
    int high = end;

    for (;;) {
        do {
            low++;
        } while (array->numbers[low] < pivot);

        do {
            high--;
        } while (array->numbers[high] > pivot);

        /* Detector for when the cells meet */
        if (low >= high) {
            swap(array, low, end);
            return low;
        }
    }
/* Swapping the values */
    swap(array, low, high);
}

void
quickSort(struct anArray *array, int start, int end)
{
    if (end - start <= 0) {
        return;
    }
    else {
        // NOTE/BUG: pivot is _not_ used
        int pivot = array->numbers[end];
        int partitionPoint = partition(array, start, end);

        quickSort(array, start, partitionPoint - 1);
        quickSort(array, partitionPoint + 1, end);
    }
}

int
main(void)
{
    // NOTE/BUG: we do _not_ want an array of the struct, but an array of int
    // that is allocated for "number" _inside_ the struct
    struct anArray *ascending = malloc(10 * sizeof(struct anArray));

    int ascend[maxSize] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

    // NOTE/BUG: this was not defined
    initArray(ascending, ascend);

    quickSort(ascending, 0, maxSize - 1);
    ascending->swaps = counter;

    printf("Test: Unique random values\nSorted: [ ");
    for (int i = 0; i < maxSize; i++) {
        printf("%i ", ascending->numbers[i]);
    }
    printf("]\nSwaps: %i\nComps: \n\n", ascending->swaps);

    return 0;
}

這是一個清理和工作版本。 我把它推廣了所以它可以采用任意長的數組。 我還做了一些樣式和代碼清理:

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

typedef struct {
    int *numbers;
    int size;
    int swaps;
} Array;

Array *
initArray(const int *src,int size)
{
    Array *array = malloc(sizeof(Array));

    array->numbers = malloc(size * sizeof(int));
    array->size = size;

    // store in reverse order so the sort will actually do something
    for (int idx = 0;  idx < size;  ++idx)
        array->numbers[size - 1 - idx] = src[idx];

    array->swaps = 0;

    return array;
}

void
freeArray(Array *array)
{

    free(array->numbers);
    free(array);
}

void
swap(Array *array, int first, int second)
{
    int temp = array->numbers[first];

    array->numbers[first] = array->numbers[second];
    array->numbers[second] = temp;

    array->swaps += 1;
}

/* Partition function */
int
partition(Array *array, int start, int end)
{

    if (start == end)
        return start;

    int pivot = array->numbers[end];
    int low = start - 1;
    int high = end;

    for (;;) {
        do {
            low++;
        } while (array->numbers[low] < pivot);

        do {
            high--;
        } while (array->numbers[high] > pivot);

        /* Detector for when the cells meet */
        if (low >= high) {
            swap(array, low, end);
            return low;
        }
    }

    /* Swapping the values */
    swap(array, low, high);
}

void
quickSort(Array *array, int start, int end)
{
    if (end - start <= 0)
        return;

    //int pivot = array->numbers[end];
    int partitionPoint = partition(array, start, end);

    quickSort(array, start, partitionPoint - 1);
    quickSort(array, partitionPoint + 1, end);
}

int
main(void)
{
    // NOTE/BUG: we do _not_ want an array of the struct, but an array of int
    // that is allocated for "number" _inside_ the struct

    int original[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    int size = sizeof(original) / sizeof(original[0]);

    Array *ascending = initArray(original, size);

    quickSort(ascending, 0, ascending->size - 1);

    printf("Test: Unique random values\nSorted: [ ");
    for (int i = 0; i < ascending->size; i++) {
        int expected = original[i];
        int actual = ascending->numbers[i];
        printf("%d%s ", actual, (actual == expected) ? "" : "???");
    }
    printf("]\nSwaps: %i\nComps: \n\n", ascending->swaps);

    freeArray(ascending);

    return 0;
}

更新:

line int size = sizeof(original) / sizeof(original[0]); 做到了嗎?

它是否給我一個大小的整數,我設置為我可以在數組中保存多少個數字的大小?

是的,這是常見/慣用的手段來得到一個固定尺寸數組的元素的數量的計數

int array[] = { 1, 2, 3 };
size_t count = sizeof(array) / sizeof(array[0]);

這里, sizeof(array)是各個元素[以int為單位]的大小[以字節為單位]的3倍,因此我們有3 * 4或12。

sizeof(array[0])sizeof(array[0])的單個第一個元素的大小,它[又]是一個int ,所以這是4。

所以,當我們將兩者分開時,我們有12 / 4或3,這是元素的數量。

如果是這樣,如果sizeof(原始[0])恰好非常大,那么我能保持的數字量是不是很小?

不,因為分裂。 它不關心元素大小[以字節為單位]的大小,因為該比率總是產生元素的數量。

當我們這樣做時, sizeof(arr) / sizeof(arr[0])技巧對於獲取計數很有用: int arr[] = { ... };

如果我們這樣做:

#define ARRCOUNT 3
int arr[ARRCOUNT] = { 1, 2, 3 };

我們已經知道了計數(即它是ARRCOUNT )。

sizeof/sizeof技巧的[輕微]優勢在於,如果我們錯誤地將ARRCOUNT定義為4,它仍然會編譯,鏈接和運行,但會產生不正確的結果[因為只有3個元素]。

這是一個很常見的技巧,我們可以定義一個通用宏[我們可以通過將它放在.h文件中重用 ]:

#define ARRAY_COUNT(arr_) (sizeof(arr_) / sizeof(arr_))

更新#2:

我已經嘗試過你的代碼(甚至嘗試過復制和粘貼它),但我的交換仍然顯示9,盡管我要排序的數組只是從{1到10}。 不知道為什么會一直這樣。

我相信[現在]你在排序中有一個錯誤。

我已經制作了另一個版本,它具有更廣泛的測試數據生成和比較。

至少,由於測試的結構方式,排序數組的第一個元素應始終具有值1。

失敗的測試是在發送它進行排序之前對原始數組進行隨機混洗的測試。

您可以根據需要添加其他測試。 陣列不需要那么大來顯示問題。 例如,以下單個測試足以產生錯誤:

bigtest(100,237,1);

無論如何,這是增強的診斷代碼:

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

#define MAXLEN      60

typedef struct {
    int *numbers;
    int size;
    int swaps;
} Array;

Array *
initArray(const int *src,int size,int randshuf)
{
    int idx;
    Array *array = malloc(sizeof(Array));

    array->numbers = malloc(size * sizeof(int));
    array->size = size;
    array->swaps = 0;

    // store in reverse order so the sort will actually do something
    switch (randshuf) {
    case 0:  // reverse the numbers
        for (idx = 0;  idx < size;  ++idx)
            array->numbers[size - 1 - idx] = src[idx];
        break;

    default:  // do _crude_ random shuffle
        for (idx = 0;  idx < size;  ++idx)
            array->numbers[idx] = 0;

        for (idx = 0;  idx < size;  ++idx) {
            while (1) {
                int ridx = rand() % size;
                if (array->numbers[ridx] == 0) {
                    array->numbers[ridx] = src[idx];
                    break;
                }
            }
        }
        break;
    }

    return array;
}

void
freeArray(Array *array)
{

    free(array->numbers);
    free(array);
}

void
swap(Array *array, int first, int second)
{
    int temp = array->numbers[first];

    array->numbers[first] = array->numbers[second];
    array->numbers[second] = temp;

    array->swaps += 1;
}

/* Partition function */
int
partition(Array *array, int start, int end)
{

    if (start == end)
        return start;

    int pivot = array->numbers[end];
    int low = start - 1;
    int high = end;

    for (;;) {
        do {
            low++;
        } while (array->numbers[low] < pivot);

        do {
            high--;
        } while (array->numbers[high] > pivot);

        /* Detector for when the cells meet */
        if (low >= high) {
            swap(array, low, end);
            return low;
        }
    }

    /* Swapping the values */
    swap(array, low, high);
}

void
quickSort(Array *array, int start, int end)
{
    if (end - start <= 0)
        return;

    //int pivot = array->numbers[end];
    int partitionPoint = partition(array, start, end);

    quickSort(array, start, partitionPoint - 1);
    quickSort(array, partitionPoint + 1, end);
}

void
print_orig(const int *orig,int count)
{
    int len = 0;

    printf("Test: Original numbers (%d):\n",count);

    for (int idx = 0;  idx < count;  ++idx) {
        len += printf(" %10d ", orig[idx]);
        if (len >= MAXLEN) {
            printf("\n");
            len = 0;
        }
    }

    if (len > 0)
        printf("\n");
}

int
print_array(Array *array,const int *orig,const char *reason)
{
    int len = 0;
    int cmp;
    int err = -1;

    printf("Test: Array Values (%s):\n",reason);

    for (int idx = 0; idx < array->size; ++idx) {
        int actual = array->numbers[idx];

        if (orig != NULL) {
            int expected = orig[idx];
            cmp = (actual == expected);
        }
        else
            cmp = 1;

        len += printf(" %10d%c", actual, cmp ? ' ' : '?');

        if (len >= MAXLEN) {
            printf("\n");
            len = 0;
        }

        if (cmp)
            continue;
        if (err < 0)
            err = idx;
    }

    if (orig != NULL)
        printf("\nSwaps: %i\nComps: \n\n", array->swaps);
    else {
        if (len > 0)
            printf("\n");
    }

    return err;
}

void
bigtest(int count,int randgap,int randshuf)
// count -- number of elements (negative means random)
// randgap -- gap between element values (negative means random)
// randshuf -- 0=simple reverse, 1=random shuffle
{
    int *orig;
    Array *array;

    printf("\n");
    for (int idx = 1;  idx <= 80;  ++idx)
        printf("-");
    printf("\n");

    printf("COUNT: %d, RANDGAP: %d, RANDSHUF: %d\n",count,randgap,randshuf);

    // get number of elements
    if (count < 0)
        count = (rand() % count) + 1;

    // get element gap (e.g. 1 --> {1, 2, 3}, 2 --> { 1, 3, 5 }
    if (randgap < 0)
        randgap = (rand() % randgap) + 1;

    printf("COUNT: %d, RANDGAP: %d, RANDSHUF: %d\n",count,randgap,randshuf);

    // get original array
    orig = malloc(sizeof(int) * count);

    // fill in original array
    do {
        int val = 1;

        // simple gap
        if (randgap >= 0) {
            if (randgap == 0)
                randgap = 1;
            for (int idx = 0;  idx < count;  ++idx, val += randgap)
                orig[idx] = val;
            break;
        }

        // random gap
        int gap;
        for (int idx = 0;  idx < count;  ++idx, val += gap) {
            orig[idx] = val;
            gap = (rand() % randgap) + 1;
        }
    } while (0);

    print_orig(orig,count);

    array = initArray(orig,count,randshuf);
    print_array(array,NULL,"Shuffled");

    quickSort(array, 0, array->size - 1);

    print_array(array,orig,"Sorted");

    freeArray(array);
    free(orig);
}

int
main(void)
{

    bigtest(10,0,0);
    bigtest(-100,23,0);
    bigtest(-1000,-2337,0);
    bigtest(-1000,-2337,1);

    return 0;
}

暫無
暫無

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

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