您的位置:首页 > 编程语言 > C语言/C++

利用C实现泛型(generics)效果---原地洗牌,快速排序

2013-11-27 23:46 369 查看
用一个函数实现一个算法,能够应用在不同的数据类型(int,double,字符数组)上,这在C++,python等高级语言中是很常见的。

灵活地利用C中的void指针,内存操作,函数指针也可以实现类似的效果。

用void指针指向特定元素的地址,如果传入元素占内存大小(如sizeof(int),sizeof(double)),可以用memcpy实现赋值操作。

如果实现了用于元素间比较或四则运算的函数并将其指针传入(如int (*cmp)(void*,void*)),则能在算法中不考虑数据类型实现更多功能。

比如下面一段函数,实现了原地洗牌,快速排序两种算法:

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

//omit ptr check when malloc and realloc

void swap(void* ap, void* bp, int elem_size) {
void* buffer = malloc(elem_size);
memcpy(buffer, ap, elem_size);
memcpy(ap, bp, elem_size);
memcpy(bp, buffer, elem_size);
free(buffer);
}

void randomize_in_place(void* arr, int n, int elem_size) {
int rand_place;
srand((unsigned int)time(NULL));
for(int i=0; i<n; i++) {
rand_place = rand() % (n-i) + i;
swap((char*)arr+i*elem_size, (char*)arr+rand_place*elem_size, elem_size);
}
}

int int_cmp(const void* ap, const void* bp) {
return *(int*)ap - *(int*)bp;
}

int double_cmp(const void* ap, const void* bp) {
if(*(double*)ap - *(double*)bp < 0)
return -1;
else if(*(double*)ap - *(double*)bp == 0)
return 0;
else
return 1;
}

int charptr_cmp(const void* ap, const void* bp) {
return strcmp(*(char**)ap, *(char**)bp);
}

int randomized_partition(void* arr, int p, int r, int elem_size, int (*compar)(const void*, const void*)) {
srand((unsigned int)time(NULL));
int rand_elem_index = rand() % (r-p+1) + p;
char* rand_elem_ptr = (char*)arr + rand_elem_index * elem_size;
char* pivot_ptr = (char*)arr + r * elem_size;
swap(rand_elem_ptr, pivot_ptr, elem_size);
// start to partition, arr[r]=pivot
// p<=k<=i arr[k]<=pivot, i+1<=k<=j-1 arr[k]>pivot
int i = p - 1;
char* ith_elem_ptr = NULL;
char* jth_elem_ptr = NULL;
for(int j=p; j<r; j++) {
jth_elem_ptr = (char*)arr + j * elem_size;
if(compar(jth_elem_ptr, pivot_ptr) <= 0) {
i = i + 1;
ith_elem_ptr = (char*)arr + i * elem_size;
swap(ith_elem_ptr, jth_elem_ptr, elem_size);
}
}
swap((char*)arr+(i+1)*elem_size, pivot_ptr, elem_size);
return i+1;
}

void recursive_qsort(void* arr, int p, int r, int elem_size, int (*compar)(const void*, const void*)) {
if(p < r) {
int q = randomized_partition(arr, p, r, elem_size, compar);
recursive_qsort(arr, p, q-1, elem_size, compar);
recursive_qsort(arr, q+1, r, elem_size, compar);
}
}

void generic_qsort(void* arr, int n, int elem_size, int (*compar)(const void*, const void*)) {
recursive_qsort(arr, 0, n-1, elem_size, compar);
}


int main(int argc, char** argv) {
int int_array[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
randomize_in_place(int_array, 10, sizeof(int));  //test
generic_qsort(int_array, 10, sizeof(int), int_cmp);  //test
double double_array[6] = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
randomize_in_place(double_array, 6, sizeof(double));  //test
generic_qsort(double_array, 6, sizeof(double), double_cmp);  //test
char* charptr_array[6] = {"generics", "hccc", "spring", "summer", "autumn", "winter"};
randomize_in_place(charptr_array, 6, sizeof(char*));  //test
generic_qsort(charptr_array, 6, sizeof(char*), charptr_cmp);  //test
}

在《C++编程思想》那本书中的,“一个袖珍的C库”那一小节,利用类似的思想实现了一个stash,不过那里使用的是字符拷贝,而且只考虑了元素存取,没有更复杂的操作。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息