C 通用快速排序适用于int*,但不适用于void*
我有一个通用的快速排序功能:C 通用快速排序适用于int*,但不适用于void*,c,pointers,function-pointers,C,Pointers,Function Pointers,我有一个通用的快速排序功能: void qsort(void* sup,int n, int(*cmp) (void *x,void *y), void (*swap) (void *a,void *b)) { int pv=n/2,l=0,h=n-1; if(n<2) return; while(h-1>=l) { if(l==pv) { swap(sup+pv,sup+pv+1); pv++; } if(h==pv) {
void qsort(void* sup,int n,
int(*cmp) (void *x,void *y),
void (*swap) (void *a,void *b))
{
int pv=n/2,l=0,h=n-1;
if(n<2)
return;
while(h-1>=l)
{
if(l==pv)
{
swap(sup+pv,sup+pv+1);
pv++;
}
if(h==pv)
{
swap(sup+pv,sup+(pv-1));
pv--;
}
if(cmp(sup+h, sup+pv))
{
h--;
continue;
}
if(cmp(sup+pv, sup+l))
{
l++;
continue;
}
swap(sup+l,sup+h);
l++,h--;
}
qsort(sup, l, cmp, swap);
qsort(sup+l,n-l, cmp, swap);
}
主要功能如下:
int main()
{
int arr[4] = {3,4,1,2};
print(arr, 4);
printf("\n\n");
qsort(arr, 4, &cmp, &swap);
print(arr, 4);
return 0;
}
其中打印为:
void print(int* arr, int size) {
int i = 0;
for(; i < size; ++i) {
printf("%d \t", arr[i]);
}
}
它工作得很好
但是当我将sup
参数更改为void*
时:
void qsort(void* sup,int n,
int(*cmp) (void *x,void *y),
void (*swap) (void *a,void *b))
它不起作用。有人知道为什么吗
我正在使用Windows下的Code::Blocks和MinGW。您必须能够取消对参数的引用<代码>无效*无法取消引用,因为编译器无法确定要传递的类型。如果通过
void*
,则必须使用显式强制转换
这个
当然可以,但是在这里
void qsort(void* sup,int n,
int(*cmp) (void *x,void *y),
void (*swap) (void *a,void *b))
您正在传递一个
void*
(sup),无法取消对该文件的引用。因此,您的第一个解决方案很好,但您必须要么在(*cmp)
中进行类型转换,要么为每个类型定义一个qsort。以下是修复排序的方法:
#include <stdio.h>
void Qsort(
void* sup,
int n,
int size,
int(*cmp) (const void *x, const void *y),
void (*swap) (void *a,void *b))
{
int pv = n / 2, l = 0, h = n - 1;
if (n < 2)
return;
while (h - 1 >= l)
{
if (l == pv)
{
swap((char*)sup + pv * size, (char*)sup + (pv + 1) * size);
pv++;
}
if(h == pv)
{
swap((char*)sup + pv * size, (char*)sup + (pv - 1) * size);
pv--;
}
if (cmp((char*)sup + h * size, (char*)sup + pv * size) > 0)
{
h--;
continue;
}
if (cmp((char*)sup + pv * size, (char*)sup + l * size) > 0)
{
l++;
continue;
}
swap((char*)sup + l * size, (char*)sup + h * size);
l++, h--;
}
Qsort(sup, l, size, cmp, swap);
Qsort((char*)sup + l * size, n - l, size, cmp, swap);
}
int cmp(const void *c1, const void *c2)
{
int a = *(const int*)c1;
int b = *(const int*)c2;
if (a > b) return 1;
if (a < b) return -1;
return 0;
}
void swap(void *c1, void *c2)
{
int c = *(int*)c1;
*(int*)c1 = *(int*)c2;
*(int*)c2 = c;
}
void print(int* arr, int size)
{
int i = 0;
for(; i < size; ++i)
{
printf("%d \t", arr[i]);
}
}
int main(void)
{
int arr[4] = {3,4,1,2};
print(arr, 4);
printf("\n\n");
Qsort(arr, 4, sizeof(arr[0]), &cmp, &swap);
print(arr, 4);
return 0;
}
请注意,以与标准库函数相同的方式命名函数是一件不好的事情。您的程序可能无法编译或运行。因此,我将
qsort
更改为qsort
我们可以改进一种通用的快速排序,以省略交换功能
#ifdef _WIN32
#define alloca _alloca
#else
#include <alloca.h>
#endif
// the generic swap function
void arrswap(void * const a, void * const b, int const sz) {
int64_t tmp;
void * p;
bool needfree = false;
if (sz > sizeof(int64_t)) {
p = alloca(sz);
if (p == NULL) {
p = malloc(sz);
//assert(p != NULL, "not enough memory");
needfree = true;
}
}
else {
p = &tmp;
}
memcpy(p, b, sz);
memcpy(b, a, sz);
memcpy(a, p, sz);
if (needfree) {
free(p);
}
}
// O(n^2) sort
void arrsort(void * const p, int const sz, int const n,
int(*compare)(void const * const pa, void const *const pb)) {
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if (compare((char*)p + i*sz, (char*)p + j*sz) == 1) {
arrswap((char*)p + i*sz, (char*)p + j*sz, sz);
}
}
}
}
// guess the index of the pivot value from three value in the array.
static int guessmidval(void * const p, int const sz, int const n,
int(*compare)(void const * const pa, void const *const pb)) {
int a = 0;
int b = n / 2;
int c = n - 1;
int ab = compare((char*)p + a*sz, (char*)p + b*sz);
int bc = compare((char*)p + b*sz, (char*)p + c*sz);
int cb = compare((char*)p + c*sz, (char*)p + b*sz);
int ba = compare((char*)p + b*sz, (char*)p + a*sz);
if (ab <= 0 && bc <= 0 || cb <= 0 && ba <= 0) {
return b;
}
int ac = compare((char*)p + a*sz, (char*)p + c*sz);
int ca = compare((char*)p + c*sz, (char*)p + a*sz);
if (ba <= 0 && ac <= 0 || ca <= 0 && ab <= 0) {
return a;
}
return c;
}
// quick sort
void arrqsort(void * const p, int sz, int const n,
int(*compare)(void const * const pa, void const *const pb)) {
if (n <= 2) {
arrsort(p, sz, n, compare);
return;
}
int midval_index = guessmidval(p, sz, n, compare);
arrswap(p, (char*)p + midval_index*sz, sz);
int i, j;
for (i = 1, j = n - 1; ; i++, j--) {
for (; compare((char*)p + i*sz, p) <= -1 && i <= j; i++);
for (; compare((char*)p + j*sz, p) >= +1 && i <= j; j--);
if (i >= j)break;
arrswap((char*)p + i*sz, (char*)p + j*sz, sz);
}
arrqsort(p, sz, i, compare);
arrqsort((char*)p + i*sz, sz, n - i, compare);
}
指针算法对无效指针无效。“无效”是什么意思?它实际上做什么?@djechlin它实际上不排序数组
qsort
是标准库函数的名称。请选择其他名称,除非您正在实现标准库。cmp
和swap
函数与qsort
函数的参数类型不兼容。你的编译器应该对此抱怨;如果没有,请启用更多警告。如果您发布一个而不是多个代码片段,那么诊断您的问题会更容易。样本输入和输出也会有帮助;很难说“按随机顺序修改”是什么意思。你认为void qsort的标准库实现(const void*ptr,size\u t count,size\u t size,int(*comp)(const void*,const void*))代码>仅为踢而传递该尺寸参数?请考虑为什么需要它。那么,您建议如何解决这个问题,仍然使用Q排序作为泛型?您可以使用函数指针,但不能将<代码>空白> /COD>作为待排序的参数。这是关于itSo的,没有理由根据swap和cmp函数对所有类型进行qsort吗?@Billie首先编写一个完全通用的swap,然后您将看到如何做到这一点。用谷歌搜索这个或提示:您需要将sizeof
类型作为参数。注意:我不认为swap
确实有必要成为qsort
的一个参数,它可以使用所有类型的通用参数。
void qsort(void* sup,int n,
int(*cmp) (void *x,void *y),
void (*swap) (void *a,void *b))
#include <stdio.h>
void Qsort(
void* sup,
int n,
int size,
int(*cmp) (const void *x, const void *y),
void (*swap) (void *a,void *b))
{
int pv = n / 2, l = 0, h = n - 1;
if (n < 2)
return;
while (h - 1 >= l)
{
if (l == pv)
{
swap((char*)sup + pv * size, (char*)sup + (pv + 1) * size);
pv++;
}
if(h == pv)
{
swap((char*)sup + pv * size, (char*)sup + (pv - 1) * size);
pv--;
}
if (cmp((char*)sup + h * size, (char*)sup + pv * size) > 0)
{
h--;
continue;
}
if (cmp((char*)sup + pv * size, (char*)sup + l * size) > 0)
{
l++;
continue;
}
swap((char*)sup + l * size, (char*)sup + h * size);
l++, h--;
}
Qsort(sup, l, size, cmp, swap);
Qsort((char*)sup + l * size, n - l, size, cmp, swap);
}
int cmp(const void *c1, const void *c2)
{
int a = *(const int*)c1;
int b = *(const int*)c2;
if (a > b) return 1;
if (a < b) return -1;
return 0;
}
void swap(void *c1, void *c2)
{
int c = *(int*)c1;
*(int*)c1 = *(int*)c2;
*(int*)c2 = c;
}
void print(int* arr, int size)
{
int i = 0;
for(; i < size; ++i)
{
printf("%d \t", arr[i]);
}
}
int main(void)
{
int arr[4] = {3,4,1,2};
print(arr, 4);
printf("\n\n");
Qsort(arr, 4, sizeof(arr[0]), &cmp, &swap);
print(arr, 4);
return 0;
}
3 4 1 2
1 2 3 4
#ifdef _WIN32
#define alloca _alloca
#else
#include <alloca.h>
#endif
// the generic swap function
void arrswap(void * const a, void * const b, int const sz) {
int64_t tmp;
void * p;
bool needfree = false;
if (sz > sizeof(int64_t)) {
p = alloca(sz);
if (p == NULL) {
p = malloc(sz);
//assert(p != NULL, "not enough memory");
needfree = true;
}
}
else {
p = &tmp;
}
memcpy(p, b, sz);
memcpy(b, a, sz);
memcpy(a, p, sz);
if (needfree) {
free(p);
}
}
// O(n^2) sort
void arrsort(void * const p, int const sz, int const n,
int(*compare)(void const * const pa, void const *const pb)) {
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if (compare((char*)p + i*sz, (char*)p + j*sz) == 1) {
arrswap((char*)p + i*sz, (char*)p + j*sz, sz);
}
}
}
}
// guess the index of the pivot value from three value in the array.
static int guessmidval(void * const p, int const sz, int const n,
int(*compare)(void const * const pa, void const *const pb)) {
int a = 0;
int b = n / 2;
int c = n - 1;
int ab = compare((char*)p + a*sz, (char*)p + b*sz);
int bc = compare((char*)p + b*sz, (char*)p + c*sz);
int cb = compare((char*)p + c*sz, (char*)p + b*sz);
int ba = compare((char*)p + b*sz, (char*)p + a*sz);
if (ab <= 0 && bc <= 0 || cb <= 0 && ba <= 0) {
return b;
}
int ac = compare((char*)p + a*sz, (char*)p + c*sz);
int ca = compare((char*)p + c*sz, (char*)p + a*sz);
if (ba <= 0 && ac <= 0 || ca <= 0 && ab <= 0) {
return a;
}
return c;
}
// quick sort
void arrqsort(void * const p, int sz, int const n,
int(*compare)(void const * const pa, void const *const pb)) {
if (n <= 2) {
arrsort(p, sz, n, compare);
return;
}
int midval_index = guessmidval(p, sz, n, compare);
arrswap(p, (char*)p + midval_index*sz, sz);
int i, j;
for (i = 1, j = n - 1; ; i++, j--) {
for (; compare((char*)p + i*sz, p) <= -1 && i <= j; i++);
for (; compare((char*)p + j*sz, p) >= +1 && i <= j; j--);
if (i >= j)break;
arrswap((char*)p + i*sz, (char*)p + j*sz, sz);
}
arrqsort(p, sz, i, compare);
arrqsort((char*)p + i*sz, sz, n - i, compare);
}
int compare_int64(void const * const pa, void const *const pb) {
int64_t a = *(int64_t*)pa;
int64_t b = *(int64_t*)pb;
if (a > b)return 1;
else if (a < b)return -1;
return 0;
}
int64_t a[] = { 3,1,65,4,-1 };
int n = sizeof(a) / sizeof(*a);
arrqsort(a, sizeof(*a), n, compare_int64);
for (int j = 0; j < n; j++) {//-1,1,3,4,65,
printf("%d,", a[j]);
}