需求
linux、标准c、32位系统。主要是做数据处理,涉及到大量的数据集合操作。
实现原理
标准c的算法函数主要有两个:快速排序qsort、二分查找bsearch。
qsort、bsearch用到的比较函数是同一个就可以正常运行,不管比较的是对象结构体内容、或者仅仅比较对象指针。
在struct中嵌套定义union,union中嵌套struct,使得编译器支持通用的变量名访问对象数据。
代码
通用比较用关键字定义如下:
//sizeof(get_keyn) == 4 * n
typedef long get_key ;
typedef struct{get_key k[1];} get_key1;
typedef struct{get_key k[2];} get_key2;
typedef struct{get_key k[3];} get_key3;
typedef struct{get_key k[4];} get_key4;
typedef struct{get_key k[5];} get_key5;
typedef struct{get_key k[6];} get_key6;
typedef struct{get_key k[7];} get_key7;
typedef struct{get_key k[8];} get_key8;
需要做集合操作的结构体示例:
typedef struct{
union{
get_key key ;//仅用于比较的数据对象
struct{ //用户实际要用的数据对象
short x ;
short y ;
};
};
}get_mesh;
多两个示例:
typedef struct{
union{
get_key8 key8 ;//仅用于比较的数据对象
char op_str[MAX_OP_LENGTH] ;
};
bool flag ;
char op_note[MAX_NOTE_LENGTH] ;
}get_option;
typedef struct{
union{
get_key2 key2 ;
struct{
long zone_cd ;
long adr_recno ;
};
};
long city_cnt ;
struct mem_city **rpcity ;
}mem_adr;
结构对象的void*比较函数(一重指针)
int cmp_key_n(const void *l, const void *r, const int key_count)
{
long *pl = (long*)l;
long *pr = (long*)r;
int loop_key = 0;
//
for(loop_key = 0; loop_key < key_count; ++loop_key) {
if(pl[loop_key] != pr[loop_key]) {
return pl[loop_key] - pr[loop_key];
}
}
return 0;
}
int cmp_key_1(const void *l, const void *r)
{
return *((long*)l) - *((long*)r);
}
int cmp_key_2(const void *l, const void *r)
{
if(*((long*)l) != *((long*)r)) {
return *((long*)l) - *((long*)r);
}
else {
return ((long*)l)[1] - ((long*)r)[1];
}
}
int cmp_key_3(const void *l, const void *r) {return cmp_key_n(l, r, 3) ;}
int cmp_key_4(const void *l, const void *r) {return cmp_key_n(l, r, 4) ;}
int cmp_key_5(const void *l, const void *r) {return cmp_key_n(l, r, 5) ;}
int cmp_key_6(const void *l, const void *r) {return cmp_key_n(l, r, 6) ;}
int cmp_key_7(const void *l, const void *r) {return cmp_key_n(l, r, 7) ;}
int cmp_key_8(const void *l, const void *r) {return cmp_key_n(l, r, 8) ;}
结构对象的void**比较函数(两重指针)
int cmp_pkey_n(const void *l, const void *r, const int key_count)
{
long *pl = *(long**)l;
long *pr = *(long**)r;
int loop_key = 0;
//
for(loop_key = 0; loop_key < key_count; ++loop_key) {
if(pl[loop_key] != pr[loop_key]) {
return pl[loop_key] - pr[loop_key];
}
}
return 0;
}
int cmp_pkey_1(const void *l, const void *r)
{
return **((long**)l) - **((long**)r);
}
int cmp_pkey_2(const void *l, const void *r)
{
if(**((long**)l) != **((long**)r)) {
return **((long**)l) - **((long**)r);
}
else {
return (*(long**)l)[1] - (*(long**)r)[1];
}
}
int cmp_pkey_3(const void *l, const void *r) {return cmp_pkey_n(l, r, 3) ;}
int cmp_pkey_4(const void *l, const void *r) {return cmp_pkey_n(l, r, 4) ;}
int cmp_pkey_5(const void *l, const void *r) {return cmp_pkey_n(l, r, 5) ;}
int cmp_pkey_6(const void *l, const void *r) {return cmp_pkey_n(l, r, 6) ;}
int cmp_pkey_7(const void *l, const void *r) {return cmp_pkey_n(l, r, 7) ;}
int cmp_pkey_8(const void *l, const void *r) {return cmp_pkey_n(l, r, 8) ;}
比较函数指针
typedef int(*COMPAR)(const void*, const void*);
p[i]访问宏
#define VEC(p, i, type_size) ((void*)(((char*)(p))+(type_size)*(i)))
杂项定义
#define MAX_OP_LENGTH (32)
#define MAX_NOTE_LENGTH (256)
#define OP_CNT (16)
typedef enum{
false = 0,
true = 1
}bool;
void free_data(void **p)
{
if(NULL != *p) {
free(*p);
*p = NULL;
}
return;
}
集合操作函数
long set_count_diff(void *set, long cnt, size_t type_size, COMPAR f)
{
long item_cnt = 0;
long i = 0;
//
if(cnt <= 1) {
return cnt;
}
item_cnt = 1;
for(i = 1; i < cnt; ++i) {
if(0 != f(VEC(set, i-1, type_size), VEC(set, i, type_size))) {
++item_cnt;
}
}
return item_cnt;
}
int set_copy_diff(void *from, long from_cnt, size_t type_size, COMPAR f,
void *to, long to_cnt)
{
long item_cnt = 0;
long i = 0;
//
if(from_cnt == 0) {
return RET_OK;
}
if(from_cnt == 1) {
memcpy(to, from, type_size);
return RET_OK;
}
memcpy(to, from, type_size);
for(i = 1; i < from_cnt; ++i) {
if(0 != f(VEC(from, i-1, type_size), VEC(from, i, type_size))) {
++item_cnt;
if(item_cnt >= to_cnt) {
outError(LOG_POS, LOG_LV_ERROR, "OVERFLOW ERROR.");
return RET_NG;
}
else {
memcpy(VEC(to, item_cnt, type_size), VEC(from, i, type_size), type_size);
}
}
}
return RET_OK;
}
SET_T set_type_check(void *set, long cnt, size_t type_size, COMPAR f)
{
long diff_cnt = 0;
//
diff_cnt = set_count_diff(set, cnt, type_size, f);
if(cnt == diff_cnt) {
return NO_SAME;
}
else {
return HAVE_SAME;
}
}
bool set_is_sorted(void *set, long cnt, size_t type_size, COMPAR f)
{
long i = 0;
//
if(cnt <= 1) {
return true;
}
for(i = 1; i < cnt; ++i) {
if(f(VEC(set, i-1, type_size), VEC(set, i, type_size)) > 0) {
return false;
}
}
return true;
}
int set_build(void **set, long *cnt, size_t type_size, COMPAR f, SET_T flag)
{
long item_cnt = 0;
char *p = NULL;
//
qsort(*set, *cnt, type_size, f);
//
if(HAVE_SAME == flag) {
return RET_OK;
}
else {
item_cnt = set_count_diff(*set, *cnt, type_size, f);
if(item_cnt > *cnt) {
outError(LOG_POS, LOG_LV_ERROR, "set_count_diff ERROR.");
return RET_NG;
}
if(item_cnt == *cnt) {
return RET_OK;
}
p = REALLOC(NULL, type_size * item_cnt);
if(NULL == p) {
outError(LOG_POS, LOG_LV_ERROR, "REALLOC ERROR.");
return RET_NG;
}
memset(p, 0x00, type_size * item_cnt);
if(RET_OK != set_copy_diff(*set, *cnt, type_size, f, (void*)p, item_cnt)) {
outError(LOG_POS, LOG_LV_ERROR, "set_copy_diff ERROR.");
return RET_NG;
}
FreeFileAll(set, (long*)cnt);
*set = p;
*cnt = item_cnt;
return RET_OK;
}
}
void *set_find(void *set, long cnt, size_t type_size, COMPAR f,
void *key, long *item_cnt)
{
long i = 0;
long cnt_temp = 0;
void *p = NULL;
//
#if SET_TEST_FLAG
if(false == set_is_sorted(set, cnt, type_size, f)) {
outError(LOG_POS, LOG_LV_ERROR, "set must sort before set_find.");
return NULL;
}
#endif
//
p = bsearch(key, set, cnt, type_size, f);
if(NULL == p) {
if(NULL != item_cnt) {
*item_cnt = 0;
}
return p;
}
else {
if(NULL == item_cnt) {
return p;
}
i = ((size_t)p - (size_t)set) / type_size;
for(; i > 0; --i) {
if(0 == f(VEC(set, i-1, type_size), VEC(set, i, type_size))) {
continue;
}
else {
break;
}
}
p = VEC(set, i, type_size);
cnt_temp = 1;
for(++i; i < cnt; ++i) {
if(0 == f(VEC(set, i-1, type_size), VEC(set, i, type_size))) {
++cnt_temp;
}
else {
break;
}
}
*item_cnt = cnt_temp;
}
return p;
}
int set_minus(void *a, long a_cnt, size_t type_size, COMPAR f,
void *b, long b_cnt,
void **c, long *c_cnt)
{
long item_cnt = 0;
int i = 0;
void *p = NULL;
//
if(NULL != *c) {
FreeFileAll(c, (long*)c_cnt);
}
#if SET_TEST_FLAG
if(false == set_is_sorted(b, b_cnt, type_size, f)) {
outError(LOG_POS, LOG_LV_ERROR, "set must sort before set_minus.");
return RET_NG;
}
#endif
for(i = 0, item_cnt = 0; i < a_cnt; ++i) {
p = set_find(b, b_cnt, type_size, f, VEC(a, i, type_size), NULL);
if(NULL == p) {
++item_cnt;
}
}
if(item_cnt > 0) {
*c = REALLOC(NULL, type_size * item_cnt);
if(NULL == *c) {
outError(LOG_POS, LOG_LV_ERROR, "REALLOC ERROR.");
return RET_NG;
}
*c_cnt = item_cnt;
for(i = 0, item_cnt = 0; i < a_cnt; ++i) {
p = set_find(b, b_cnt, type_size, f, VEC(a, i, type_size), NULL);
if(NULL == p) {
memcpy(VEC(*c, item_cnt, type_size), VEC(a, i, type_size), type_size);
++item_cnt;
}
}
}
else {
*c = NULL;
*c_cnt = 0;
}
return RET_OK;
}
int set_intersection(void *a, long a_cnt, size_t type_size, COMPAR f,
void *b, long b_cnt,
void **c, long *c_cnt)
{
long item_cnt = 0;
int i = 0;
void *p = NULL;
//
if(NULL != *c) {
FreeFileAll(c, (long*)c_cnt);
}
#if SET_TEST_FLAG
if(false == set_is_sorted(b, b_cnt, type_size, f)) {
outError(LOG_POS, LOG_LV_ERROR, "set b must sort before set_intersection.");
return RET_NG;
}
#endif
for(i = 0, item_cnt = 0; i < a_cnt; ++i) {
p = set_find(b, b_cnt, type_size, f, VEC(a, i, type_size), NULL);
if(NULL != p) {
++item_cnt;
}
}
if(item_cnt > 0) {
*c = REALLOC(NULL, type_size * item_cnt);
if(NULL == *c) {
outError(LOG_POS, LOG_LV_ERROR, "REALLOC ERROR.");
return RET_NG;
}
*c_cnt = item_cnt;
for(i = 0, item_cnt = 0; i < a_cnt; ++i) {
p = set_find(b, b_cnt, type_size, f, VEC(a, i, type_size), NULL);
if(NULL != p) {
memcpy(VEC(*c, item_cnt, type_size), VEC(a, i, type_size), type_size);
++item_cnt;
}
}
}
else {
*c = NULL;
*c_cnt = 0;
}
return RET_OK;
}
以上代码中的COMPAR f一般为cmp_key_n之类的比较函数。
使用示例
HAVE_SAME == set_type_check(mem_data_set->pmesh, mem_data_set->mesh_cnt,
sizeof(mem_mesh), cmp_key_1)
if(HAVE_SAME == set_type_check(pgdf2city, city_index_cnt,
sizeof(mem_city_index*), cmp_pkey_5))
if(RET_OK != set_copy_diff(*set, *cnt, type_size, f, (void*)p, item_cnt)) {
outError(LOG_POS, LOG_LV_ERROR, "set_copy_diff ERROR.");
return RET_NG;
}
if(RET_OK != set_build((void**)&(p->rpop), &(p->op_cnt),
sizeof(get_option*), cmp_pkey_8, NO_SAME))
p = set_find(b, b_cnt, type_size, f, VEC(a, i, type_size), NULL);
if(RET_OK != set_minus(pcity[loop_city].rpmesh_plus, pcity[loop_city].mesh_plus_cnt,
sizeof(mem_mesh*), cmp_pkey_1,
pcity[loop_city].rpmesh, pcity[loop_city].mesh_cnt,
(void**)&pget, &get_cnt))
if(RET_OK != set_intersection(pmesh_plus, loop_mesh_plus,
sizeof(mem_mesh*), cmp_pkey_1,
pmesh_zone2, mesh_zone_cnt2,
(void **)&c, &c_cnt))