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

来源:互联网 发布:网店数据同步系统 编辑:程序博客网 时间:2024/06/05 18:29

用一个函数实现一个算法,能够应用在不同的数据类型(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;elsereturn 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));  //testgeneric_qsort(int_array, 10, sizeof(int), int_cmp);  //testdouble double_array[6] = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};randomize_in_place(double_array, 6, sizeof(double));  //testgeneric_qsort(double_array, 6, sizeof(double), double_cmp);  //testchar* charptr_array[6] = {"generics", "hccc", "spring", "summer", "autumn", "winter"};randomize_in_place(charptr_array, 6, sizeof(char*));  //testgeneric_qsort(charptr_array, 6, sizeof(char*), charptr_cmp);  //test}

在《C++编程思想》那本书中的,“一个袖珍的C库”那一小节,利用类似的思想实现了一个stash,不过那里使用的是字符拷贝,而且只考虑了元素存取,没有更复杂的操作。

原创粉丝点击