std c中实现通用的集合操作函数

需求

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))
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值