【问题标题】:Sorting any kind of element using void pointers in C在 C 中使用 void 指针对任何类型的元素进行排序
【发布时间】:2012-07-07 12:15:52
【问题描述】:

大家好,我正在编写一个用 C 语言对一般元素进行排序的程序。它可以对任何类型的对象(整数、浮点数、复数、对象)进行排序

我想到的是使用空指针,

void qsort(void *ptr,int sz,int i,int j,int (*fptr) (const void *,const void *) )
{

if(i<j)
{
    int p=(i+j)/2;
    p=partition(ptr,sz,i,j,p,fptr);
    qsort(ptr,size,i,p-1,fptr); 
    qsort(ptr,size,p+1,j,fptr); 
}
} 

比较

通过 sz 的值我们可以知道它是指向 string、int、char、float 等的指针

int compare(const void* a,const void* b,int sz)
{
if(sz==0)             //means pointer to a string
return strcmp( (char*)a, (char*)b );
else if(sz==1)  //means int
return  *(int*)a -  *(int*)b;
else if(sz==2)  //means float
return *(float*)a-  *(float*)b;
else if(sz==3)
return *(char*)a-  *(char*)b;
}

用于交换两个元素

void swap(void *a,void *b,int sz)//for swapping
{
     if(sz==0)
     { 
      void *c;
      c=a;
      a=b;
      b=c;
      }
     else if(sz==1)
      {
      a=(int*)a;
      b=(int*)b;
      int c;
      c= *a;
      *a=*b;
      *b=c;
       }

     else if(sz==2)
     {
       a=(float*)a;
       b=(float*)b;
       float c;
       c= *a;
       *a=*b;
       *b=c;
     }

已编辑

qsort(arr,4,0,9,&compare);

完整的代码正在构建中,请告诉我是否可以在我的方法中进行一些优化,或者针对这个问题提供一些更好的替代方案。 在我看来,它的尺寸真的会很大

提前很多很多

【问题讨论】:

  • 你有理由不使用通常的 qsort 功能吗? linux.die.net/man/3/qsort
  • 我不会担心大小,但枚举会让你的代码更具可读性。顺便说一句,您在 swap() 中的方法不起作用:具体来说,当您先说“a=(int*)a”然后说“a=*b”时,对于第二个语句,a 和 b 不是更长的int.
  • 在风格上,您可以使用 switch 语句,而不是长长的 if 链。
  • 我已经用int 数组的示例更新了我的答案。这个想法是一样的,调用者会传入一个不同的比较函数,一个特定于他们的数组的函数。
  • 是的,这样更好,因为你不知道他们想要排序什么疯狂的数组类型。

标签: c sorting void-pointers


【解决方案1】:

问题在于这不允许对自定义类型(如结构)进行排序。通常的方法是接受你调用的函数指针来进行比较。

【讨论】:

  • 我想你会发现这就是 fptr 参数的用途。
  • 但你是对的,它永远无法进入比较函数,所以发生了一些奇怪的事情。
【解决方案2】:

您应该做的是将比较作为函数指针传递。您正在传递一个函数指针,但您似乎没有使用它来比较值。您不必预先定义所有比较,因为您可以在使用它们时根据您正在使用的值的类型来定义它们。

【讨论】:

  • 那我们将如何比较不同的类型
  • 为什么要比较不同的类型?如果您正在排序,则您的排序类型相同。您不会传入 FILE *char * 并对其进行排序。哪个更大?那是没有意义的。你将传入一堆ints 或一堆doubles 或一堆chars。
  • 通过不同的类型,我的意思是对字符、整数等进行排序
  • 是的,但您(可能)不想同时对chars 和ints 的分类进行排序。如果你这样做了,你应该在传递它们之前将它们转换为另一个,否则你将无法在 qsort 函数中迭代它们。
【解决方案3】:

由于partition 函数可能会使用您的交换例程,它应该适用于任意大小的对象,而不仅仅是您计划传递给代码的对象。

void swap (void *a, void *b, int sz) {
    char buf[512];
    void *p = buf;
    if (sz > sizeof(buf)) p = malloc(sz);
    memcpy(p, a, sz);
    memcpy(a, b, sz);
    memcpy(b, p, sz);
    if (p != buf) free(p);
}

从您编写比较例程的方式来看,您似乎只打算发送某些类型的数组。但是,sz 通常用于说明数组中各个元素的大小,而不是作为类型标识符,因为您似乎正在尝试使用它。

struct x { int key; /*...*/ };

int cmp_x (const void *a, const void *b) {
    const struct x *xa = a;
    const struct x *xb = b;
    return (xa->key > xb->key) - (xa->key < xb->key);
}

struct x array_x[100];
/* populate array */
qsort(array_x, sizeof(struct x), 0, 100, cmp_x);

这就是我想象你的qsort 应该被调用的方式。 (感谢 Ambroz Bizjak 的漂亮comparison implementation。)

对于int的数组:

int cmp_int (const void *a, const void *b) {
    int ia = *(const int *)a;
    int ib = *(const int *)b;
    return (ia > ib) - (ia < ib);
}

int array_i[100];
/* populate array */
qsort(array_i, sizeof(int), 0, 100, cmp_int);

【讨论】:

    猜你喜欢
    • 2021-07-21
    • 1970-01-01
    • 2021-09-02
    • 2011-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-05
    • 2019-05-25
    相关资源
    最近更新 更多