简体   繁体   English

计算C中Quicksort的掉期交易

[英]Counting swaps in Quicksort in C

I am trying to count the number of swaps that occur in my quicksort in C. However, I am getting values that are incorrect and not sure where I went wrong. 我试图计算我在C中的快速排序中发生的掉期数量。但是,我得到的值不正确并且不确定我哪里出错了。 I am using a structures as my arrays to be sorted. 我使用结构作为我的数组进行排序。

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);
}

This is my partition function used to "separate" the arrays. 这是我用来“分离”数组的分区函数。

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);
  }
}

This is my quicksorting function. 这是我的快速排序功能。 It's a recursive function. 这是一个递归函数。 My swap function increments counter by 1 every time it's called. 每次调用时,我的交换函数都会将计数器递增1。

In my main, I set myArray->swaps = counter; 在我的主要内容中,我设置了myArray-> swaps = counter; But the number of times the swaps occurs isn't right. 但掉期发生的次数不对。 For example, if I sort an array that goes from 1 to 9, the number of swaps should be 0 but I get 9. I've tried incrementing counter when it's in the partition function only but it gives me the same result. 例如,如果我对一个从1到9的数组进行排序,那么交换的数量应该是0,但是我得到9.我尝试仅在分区函数中递增计数器,但它给了我相同的结果。

Is there something wrong with my partition function? 我的分区功能有问题吗?

Thank you very much 非常感谢你

Edit 1: 编辑1:

Here's my swap function. 这是我的交换功能。

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++;
}

I've tried using 我试过用了

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

and then have swapCount be array->swaps when calling the swap function, and incrementing it by 1 but it gives me the same answer. 然后在调用交换函数时将swapCount变为array-> swaps,并将其递增1,但它给出了相同的答案。

Here's a part of my main. 这是我主要的一部分。

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);

The other parts of my main are just other arrays to be sorted. 我的主要的其他部分只是要排序的其他数组。 The initArray is used to set the values of array->numbers and also reset array->swaps to 0. initArray用于设置array-> numbers的值,并将array-> swaps重置为0。

Your quicksort code seems pretty good. 你的快速排序代码似乎很不错。 I didn't examine it rigorously, but it passed a simple test, so I didn't investigate further. 我没有严格检查,但它通过了一个简单的测试,所以我没有进一步调查。 ( Edit: Based on your feedback, I created a third version in my second update that shows that the sort has an issue for larger data inputs). 编辑:根据您的反馈,我在第二次更新中创建了第三个版本,显示排序存在较大数据输入的问题)。

The main bug was the malloc at the top of main . 主要的错误是main顶部的malloc We do not want an array of the struct anArray : 我们希望在结构数组 anArray

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

That is, we do not want (eg) 10 structs, we want a single struct and to fill in 10 int s that go into the numbers field that is in that single struct. 也就是说,我们希望(例如)10层结构,我们希望有一个单一的结构,并在10个填补int是走成S numbers字段是在单一结构。

The initArray function was not posted, so I had to guess/deduce what it might be. initArray函数没有发布,所以我不得不猜测/推断它可能是什么。 Based on the above bug, I'm not sure that numbers would have been initialized correctly. 根据上面的错误,我不确定numbers是否会被正确初始化。

From the code fragments posted, I was able to piece together a whole program. 从发布的代码片段中,我能够将整个程序拼凑起来。 I've created two versions: 我创建了两个版本:

One with the bugs annotated [but not fixed] that compiles cleanly. 一个带有注释[但不是固定]的错误编译干净。

And, a second that is fully cleaned up, working, and generalized for arbitrary array sizes [please pardon the gratuitous style cleanup] 并且,第二个完全清理,工作和推广任意数组大小[请原谅无偿的样式清理]


Here is [something close to] your original code with the bugs annotated: 这里有[接近]你的原始代码,附带注释的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;
}

Here is a cleaned up and working version. 这是一个清理和工作版本。 I've generalized it so it can take an arbitrarily long array. 我把它推广了所以它可以采用任意长的数组。 I've also done a bit of style and code cleanup: 我还做了一些样式和代码清理:

#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;
}

UPDATE: 更新:

What does the line int size = sizeof(original) / sizeof(original[0]); line int size = sizeof(original) / sizeof(original[0]); do exactly? 做到了吗?

Does it give me an integer for size which I set to be the size of how many numbers I can hold in an array? 它是否给我一个大小的整数,我设置为我可以在数组中保存多少个数字的大小?

Yes, that is common/idiomatic trick to get the count of the number of elements of a fixed size array: 是的,这是常见/惯用的手段来得到一个固定尺寸数组的元素的数量的计数

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

Here, sizeof(array) is 3 times the size [in bytes] of the individual elements [which are int , which is 4 bytes], so we have 3 * 4 or 12. 这里, sizeof(array)是各个元素[以int为单位]的大小[以字节为单位]的3倍,因此我们有3 * 4或12。

sizeof(array[0]) is the size of the single, first element of the array, which is [again] an int , so this is 4. sizeof(array[0])sizeof(array[0])的单个第一个元素的大小,它[又]是一个int ,所以这是4。

So, when we divide the two, we have 12 / 4 or 3, which is the number of elements. 所以,当我们将两者分开时,我们有12 / 4或3,这是元素的数量。

If so, wouldn't the amount of numbers I can hold be really small if sizeof(original[0]) happens to be very large? 如果是这样,如果sizeof(原始[0])恰好非常大,那么我能保持的数字量是不是很小?

No, because of the division. 不,因为分裂。 It doesn't care how large the element size [in bytes] is, because the ratio always produces the number of elements. 它不关心元素大小[以字节为单位]的大小,因为该比率总是产生元素的数量。

The sizeof(arr) / sizeof(arr[0]) trick is useful to get the count when we do: int arr[] = { ... }; 当我们这样做时, sizeof(arr) / sizeof(arr[0])技巧对于获取计数很有用: int arr[] = { ... };

If we do: 如果我们这样做:

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

We already know the count (ie it is ARRCOUNT ). 我们已经知道了计数(即它是ARRCOUNT )。

The [slight] advantage to the sizeof/sizeof trick is that if we had incorrectly defined ARRCOUNT as 4 by mistake, it would still compile, link, and run, but would produce incorrect results [because there were only 3 elements]. sizeof/sizeof技巧的[轻微]优势在于,如果我们错误地将ARRCOUNT定义为4,它仍然会编译,链接和运行,但会产生不正确的结果[因为只有3个元素]。

This is a common enough trick that we can define a generic macro [that we can reuse by putting it a .h file]: 这是一个很常见的技巧,我们可以定义一个通用宏[我们可以通过将它放在.h文件中重用 ]:

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

UPDATE #2: 更新#2:

I've tried your code (even tried copying and pasting it) but my swaps is still showing 9 despite my array to be sorted is just going from { 1 to 10}. 我已经尝试过你的代码(甚至尝试过复制和粘贴它),但我的交换仍然显示9,尽管我要排序的数组只是从{1到10}。 Not sure why this keeps occurring. 不知道为什么会一直这样。

I believe [now] you have a bug in the sort itself. 我相信[现在]你在排序中有一个错误。

I've produced another version that has much more extensive test data generation and comparison. 我已经制作了另一个版本,它具有更广泛的测试数据生成和比较。

At a minimum, because of the way the tests are structured, the first element of the sorted array should always have a value of 1. 至少,由于测试的结构方式,排序数组的第一个元素应始终具有值1。

The test that fails is the one that does a random shuffle of the original array before sending it in to be sorted. 失败的测试是在发送它进行排序之前对原始数组进行随机混洗的测试。

You can add other tests as needed. 您可以根据需要添加其他测试。 The array needn't be so large to show the problem. 阵列不需要那么大来显示问题。 For example, the following single test is enough to produce the error: 例如,以下单个测试足以产生错误:

bigtest(100,237,1);

Anyway, here is the enhanced diagnostic code: 无论如何,这是增强的诊断代码:

#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