【问题标题】:C - Custom qsort not workingC - 自定义 qsort 不起作用
【发布时间】:2014-11-20 15:23:37
【问题描述】:

我正在尝试制作具有相同参数的 qsort 类型的函数。我还写了 3 个函数来比较 int、float 和 characters。由于某种原因,它在任何情况下都不起作用。 我不知道这是否是我的 qsortx 函数的问题,但我检查了几次,它应该可以正常工作。我不确定问题是什么,或者我做错了什么。我目前正在学习函数指针,我可能没有得到与它相关的所有内容。提前致谢。

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

void qsortx(void*, int, int, int (*)(const void*, const void*));
int intcmp();
int floatcmp();
int charcmp();

int main()
{
    int i,n;
    char items[]={'c', 'a', 'b'};
    n = 3;
    for (i=0;i<n;++i) {
        printf("%c ", items[i]);
    }
    printf("\n");

    qsortx(items, n, sizeof(char), charcmp);

    for (i=0;i<n;++i) {
        printf("%c ", items[i]);
    }
    printf("\n");
    return 0;
}

void qsortx (void *tp, int length, int pace, int(*fp)(const void* a, const void* b)) {
    int switched,i,j;
    void *p;
    p=(void*)malloc(pace);
    switched = 1;
    while (1) {
        if (switched == 0) {
            return;
        }
        switched = 0;
        for (i=0; i<length-1;++i) {
            for (j=0;j<length-1;++j) {
                printf("%c %c", tp+i, tp+j);
                if (fp(tp+i, tp+j) > 0) {
                    memcpy(p, tp+i, pace);
                    memcpy(tp+i, tp+j, pace);
                    memcpy(tp+j, p, pace);
                    switched++;
                }
            }
        }

    }
}

int intcmp(const void* a, const void* b) {
    return *(int*)a - *(int*)b;
}

int floatcmp(const void* a, const void* b) {
    return *(float*)a - *(float*)b;
}

int charcmp(const void* a, const void* b) {
    return *(char*)a - *(char*)b;
}

【问题讨论】:

  • 您能否添加一个无法按预期工作的示例?
  • 如果你从上面运行代码,它会写出相同的数组,它不会像它应该的那样按升序更改项目:a b c。此外,有时它不会写出第一个字符,如果我在数组中使用 5 个元素在 int 上对其进行测试,那么前两个数字将是大数字或零。
  • 我立即看到的一件事是 main 中的数组 items 是一个 int 数组,但你发送sizeof(char).
  • 除了@Thomas 指出的大小问题之外,在您第一次通过qsortx() 中的循环时,您会在变量switched 初始化之前检查它的值。
  • 另外,tp+i 形式的表达式不正确。当被排序的项目的长度为 1 时,他们可能会偶然地做正确的事情,否则不会。

标签: c function pointers qsort


【解决方案1】:

您有多个与指针算术和元素大小相关的问题。您的排序中也存在逻辑错误(我猜您知道这是单向振动器排序)。以下是修复这些缺陷的 qsortx() 函数版本:

void qsortx (void *tp, int length, int pace, int(*fp)(const void* a, const void* b)) {
    if (length > 1) {
        char *bound = ((char *) tp) + (length * pace);
        char *p = malloc(pace);
        char *item1p;

        for (item1p = tp; item1p < (bound - pace); item1p += pace) {
            char *item2p;

            for (item2p = item1p + pace; item2p < bound; item2p += pace) {
                if (fp(item1p, item2p) > 0) {
                    memcpy(p, item1p, pace);
                    memcpy(item1p, item2p, pace);
                    memcpy(item2p, p, pace);
                }
            }
        }

        free(p);
    }
}

请注意:

  1. 所有指针运算都针对 char * 类型的值执行。
  2. 在单步执行输入数组时必须考虑元素大小 (pace),否则只会打乱数据。
  3. 最内层循环应该从元素之后开始,该元素在下一个外层循环中被考虑。
  4. switched = 1 是比switched ++ 更好的选择,因为它不会溢出,而且您关心的只是零与非零。 (更新:但 switched 不再相关。)
  5. (更新)如果通过item1p 循环导致零交换,则提前退出是不正确的。仅仅因为一个元素已经在其正确的位置并不意味着所有后续元素也在其正确的位置。我更新了上面的代码以消除这种行为。
  6. (更新)正如 chux 所观察到的,为交换元素保留的临时空间没有被释放。我添加了一个合适的free(p)
  7. (更新)我还以数组长度大于 1 为条件进行排序,这样可以避免在 length 为零的情况下与 bound - pace 相关的未定义行为。

【讨论】:

  • 由于某种原因,它进入了一个无限循环,因为它将 item1p 作为整个数组而不仅仅是第一个元素,并且 item2p 作为除了第一个元素之外的整个数组,至少那是什么它显示在调试中。此外,即使在 item1p 到达 abc 之后,它仍然显示为 true 并再次开始排序。
  • 使用您提供的 main()charcmp() 函数,我提供的代码可以正确运行。
  • 哦,对不起,我又检查了一遍,我调用了错误的函数。非常感谢。
  • 很好,@chux。已更新。
  • 请注意,如果pace 小于零且长度大于零,此函数将调用未定义的行为。不过,因为pace 小于 1 是荒谬的,所以我并不在乎。这个问题可以通过给pace 一个无符号类型来避免(size_t 很自然),但我坚持使用问题中指定的函数签名。
【解决方案2】:

这里是快速排序(qsort)算法的伪代码和实现,以及一些附属代码,如http://www.codingbot.net/2013/01/quick-sort-algorithm-and-c-code.html 网页中所定义: 请注意,此算法与 qsort() 略有不同 因为有一个不同的参数列表和某些其他细节。 不过基本算法是一样的。

function quicksort('array')
    if length('array') ≤ 1
        return 'array'  // an array of zero or one elements is already sorted
        select and remove a pivot value 'pivot' from 'array'
        create empty lists 'less' and 'greater'
        for each 'x' in 'array'
            if 'x' ≤ 'pivot' 
                then append 'x' to 'less'
            else 
                append 'x' to 'greater'
            endif
        end for
        return concatenate(quicksort('less'), 'pivot', quicksort('greater') );

notice that qsort is a partition sort, using recursion.

#include<stdio.h>
#include<conio.h>

void quick_sort(int arr[20],int,int);

int main()
{
   int arr[20],n,i;
   clrscr();
   printf("Enter the number of elements in the Array: ");
   if( 1 != scanf(" %d",&n) ) 
   {
       perror( "scanf for count of elements" );
       exit(1);
   }

   printf("\nEnter %d elements:\n\n",n);

   for(i=0 ; i<n ; i++)
   {
        printf(" Array[%d] = ",i);
        if( 1 != scanf(" %d",&arr[i]) )
        {
            perror( "scanf for element values" );
            exit(2);
        }

   }

   quick_sort(arr,0,n-1);
   printf("\nThe Sorted Array is:\n\n");

   for(i=0 ; i<n ; i++)
   {
        printf(" %4d",arr[i]);
   }
   getch();
}

void quick_sort(int arr[20],int low,int high)
{
    int pivot; // used in partitioning the array
    int j; // loop index
    int temp; // for swapping
    int i; // loop index

    if(low<high)
    {
        pivot = low; 
        i = low;
        j = high;

        while(i<j)
        {
            // find next item not in proper sequence
            while((arr[i] <= arr[pivot]) && (i<high))
            {
                i++;
            }

            // find next item not in proper sequence
            while(arr[j] > arr[pivot])
            {
                j--;
            }

            // following is where a callback function would be invoked
            if(i<j)
            { 
                temp=arr[i];
                arr[i]=arr[j];
                arr[j]=temp;
            }
        }

        temp=arr[pivot];
        arr[pivot] = arr[j];
        arr[j]=temp;

        // following is where recursion is used to perform sort on sub partitions
        quick_sort(arr,low,j-1);
        quick_sort(arr,j+1,high);
   }
}

【讨论】:

    【解决方案3】:

    对于您的目的来说,这是一个更好的算法。 但是,它只处理整数,所以你需要 将比较函数作为第四个参数添加到 quicksort() 并修改代码以使用您的比较功能

    #include <stdio.h>
    #include <stdlib.h>
    
    void swap(int *x,int *y);
    int choose_pivot(int i,int j );
    void quicksort(int list[],int m,int n);
    void display(int list[],const int n);
    
    int main()
    {
        const int SIZE = 10;
        int list[SIZE];
    
        int i = 0;
    
        /* generates random numbers and fill the list */
        for(i = 0; i < SIZE; i++ )
        {
            list[i] = rand();
        }
    
        printf("The list before sorting is:\n");
        display(list,SIZE);
    
        /* sort the list using quicksort algorithm */
        quicksort(list,0,SIZE-1);
    
        printf("The list after sorting:\n");
        display(list,SIZE);
    }
    
    
    void swap(int *x,int *y)
    {
        // for integer swaps, 3 exclusive OR operations would be much faster
        // and not require a temp variable
        int temp;
        temp = *x;
        *x = *y;
        *y = temp;
    }
    
    
    int choose_pivot(int i,int j )
    {
        return((i+j) /2);
    }
    
    
    void quicksort(int list[],int m,int n)
    {
        int key,i,j,k;
    
        if( m < n)
        {
            k = choose_pivot(m,n);
            swap(&list[m],&list[k]);
            key = list[m];
            i = m+1;
            j = n;
            while(i <= j)
            {
                while((i <= n) && (list[i] <= key))
                {
                     i++;
                }
    
                while((j >= m) && (list[j] > key))
                {
                    j--;
                }
    
                if( i < j)
                {
                    swap(&list[i],&list[j]);
                }
            }
    
            /* swap two elements */
            swap(&list[m],&list[j]);
    
            /* recursively sort the lesser list */
            quicksort(list,m,j-1);
            quicksort(list,j+1,n);
        }
    }
    
    
    void display(int list[],const int n)
    {
        int i;
    
        for(i=0; i<n; i++)
        {
            printf("%d\t",list[i]);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-10-13
      • 1970-01-01
      • 1970-01-01
      • 2012-05-05
      • 2020-05-21
      • 2019-11-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多