C - 自定义qsort无法正常工作

时间:2014-11-20 15:23:37

标签: c function pointers qsort

我正在尝试制作具有相同参数的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;
}

3 个答案:

答案 0 :(得分:2)

您有许多与指针运算和元素大小相关的问题。您的排序中也存在逻辑错误(我猜您知道这是一种单向振动器排序)。这是修复这些缺陷的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对条件进行排序,这样可以避免在bound - pace为零时与length关联的未定义行为。

答案 1 :(得分:0)

这里是quicksort(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);
   }
}

答案 2 :(得分:0)

这是一个更好的算法,适合您的目的。 但是,它只处理整数,所以你需要 将比较函数作为第4个参数添加到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]);
    }
}