不定长二维数组的排序问题分析

  • 一个租房系统,在系统中增加一个roomid,它有几个属性,面积为 area,月租金为 price,卧室数量为 rooms,地址坐标为 address(格式为 [横坐标x, 纵坐标y])。
  • 一个查询功能要求对满足的房源进行排序,每一次查询的排序规则均不同,是动态变化的,称之为不定长二维数组的排序问题

解法1

  • 下面是初始版本,也是不推荐使用的,qsort函数的cmp写的很烂,还使用了递归调用。实际上大可不必这么做。没有兴趣看的可以之间看解法2:
#define MAX_ADDR_NUM 2

typedef struct {
    int roomid;
    int area;
    int price;
    int rooms;
    int address[MAX_ADDR_NUM];
    UT_hash_handle hh;
} MyHashTable;


MyHashTable *g_users = NULL;

MyHashTable *g_newusers = NULL;

RentingSystem *RentingSystemCreate()
{
    g_users = NULL;
    g_newusers = NULL;
    return NULL;
}

bool RentingSystemDeleteRoom(RentingSystem *obj, int id)
{
    MyHashTable *tmp = NULL;
    HASH_FIND_INT(g_users, &id, tmp);
    if (tmp != NULL) {
        HASH_DEL(g_users, tmp);
        return true;
    } else {
        return false;
    }
}

bool RentingSystemAddRoom(RentingSystem *obj, int id, int area, int price, int rooms, int *address, int addressSize)
{
    // 若不存在则为false;
    bool isExit = false;
    isExit = RentingSystemDeleteRoom(obj, id);

    MyHashTable *tmp = NULL;
    tmp = (MyHashTable *)malloc(sizeof(MyHashTable));
    tmp->roomid = id;
    tmp->area = area;
    tmp->price = price;
    tmp->rooms = rooms;
    tmp->address[0] = address[0];
    tmp->address[1] = address[1];
    HASH_ADD_INT(g_users, roomid, tmp);
    return !isExit;
}

int g_orderby[3][2] = {0};
int g_index = 0;
int g_maxindex = 0;
// 房源坐标
int g_x = 0;
int g_y = 0;

int GetLen(MyHashTable *a)
{
    int x = a->address[0] > g_x ? a->address[0] - g_x : g_x - a->address[0];
    int y = a->address[1] > g_y ? a->address[1] - g_y : g_y - a->address[1];
    return x + y;
}

int MyCmp(MyHashTable *a, MyHashTable *b)
{
    if (g_index >= g_maxindex) {
        g_index = 0;
        return a->roomid - b->roomid;
    }
    int parameter = g_orderby[g_index][0];
    int order = g_orderby[g_index][1];

    if (parameter == 1) {
        if (a->area == b->area) {
            g_index++;
            return MyCmp(a, b);
        }
        g_index = 0;
        return order == 1 ? a->area - b->area : b->area - a->area;
    } else if (parameter == 2) {
        if (a->price == b->price) {
            g_index++;
            return MyCmp(a, b);
        }
        g_index = 0;
        return order == 1 ? a->price - b->price : b->price - a->price;
    } else {
        int alen = GetLen(a);
        int blen = GetLen(b);
        if (alen == blen) {
            g_index++;
            return MyCmp(a, b);
        }
        g_index = 0;
        return order == 1 ? alen - blen : blen - alen;
    }
}

/*
 * 输入orderBy是长度为orderBySize的数组指针的数组,其中每个元素也是一个数组,此数组长度固定为2。
 * 注意:返回的数组必须由实现者进行内存分配,由框架代码进行内存释放。
 * 返回的数组长度存在 *retSize 中。
 */
int *RentingSystemQueryRoom(RentingSystem *obj, int area, int price, int rooms, int *address, int addressSize,
                            int **orderBy, int orderBySize, int *retSize)
{
    MyHashTable *el = NULL;
    MyHashTable *tmp = NULL;
    int cnt = 0;
    g_newusers = NULL;
    HASH_ITER(hh, g_users, el, tmp)
    {
        if (el->area >= area && el->price <= price) {
            MyHashTable *newnode = NULL;
            newnode = (MyHashTable *)malloc(sizeof(MyHashTable));
            newnode->roomid = el->roomid;
            newnode->area = el->area;
            newnode->price = el->price;
            newnode->rooms = el->rooms;
            newnode->address[0] = el->address[0];
            newnode->address[1] = el->address[1];
            HASH_ADD_INT(g_newusers, roomid, newnode);
            cnt++;
        }
    }

    (void)memset(g_orderby, 0, sizeof(g_orderby));
    for (int i = 0; i < orderBySize; i++) {
        g_orderby[i][0] = orderBy[i][0];
        g_orderby[i][1] = orderBy[i][1];
    }
    g_maxindex = orderBySize;
    g_index = 0;
    // 房源坐标
    g_x = address[0];
    g_y = address[1];

    HASH_SORT(g_newusers, MyCmp);

    int *res = (int *)malloc(sizeof(int) * cnt);
    cnt = 0;
    HASH_ITER(hh, g_newusers, el, tmp)
    {
        res[cnt] = el->roomid;
        cnt++;
        HASH_DEL(g_newusers, el);
        free(el);
    }
    *retSize = cnt;
    return res;
}

void RentingSystemFree(RentingSystem *obj)
{
    MyHashTable *el = NULL;
    MyHashTable *tmp = NULL;
    HASH_ITER(hh, g_users, el, tmp)
    {
        HASH_DEL(g_users, el);
        free(el);
    }
}

解法2

  • 该解法,使用了标准的qsort中cmp函数的写法,如何将函数的排序条件传递到比较函数cmp中呢
  • c语言一般使用全局变量传递
  • 对于非c语言,通常用lambda表达式传递
#define MAX_ROOMINFO_SIZE 4
#define ADDR_LEN 2

typedef struct {
    int id;
    int roomInfo[MAX_ROOMINFO_SIZE];
    int roomsNum;
    int addr[ADDR_LEN];
    UT_hash_handle hh;
} RentingSystem;


RentingSystem *g_rentingHead = NULL;

RentingSystem *RentingSystemCreate()
{
    g_rentingHead = NULL;
    return g_rentingHead;
}

bool RentingSystemDeleteRoom(RentingSystem *obj, int id)
{
    RentingSystem* tmp = NULL;
    HASH_FIND_INT(g_rentingHead, &id, tmp);
    if (tmp != NULL) {
        HASH_DEL(g_rentingHead, tmp);
        free(tmp);
        return true;
    } else {
        return false;
    }
}

bool RentingSystemAddRoom(RentingSystem *obj, int id, int area, int price, int rooms, int *address, int addressSize)
{
    RentingSystem* tmp = NULL;
    HASH_FIND_INT(g_rentingHead, &id, tmp);
    if (tmp == NULL) {
        tmp = (RentingSystem*)malloc(sizeof(RentingSystem));
        memset(tmp, 0, sizeof(RentingSystem));
        tmp->id = id;
        tmp->roomInfo[0] = area;
        tmp->roomInfo[1] = price;
        tmp->roomsNum = rooms;
        tmp->addr[0] = address[0];
        tmp->addr[1] = address[1];
        HASH_ADD_INT(g_rentingHead, id, tmp);
        return true;
    } else {
        tmp->roomInfo[0] = area;
        tmp->roomInfo[1] = price;
        tmp->roomsNum = rooms;
        tmp->addr[0] = address[0];
        tmp->addr[1] = address[1];
        return false;
    }
}

int **g_orderBy;
int *g_address;
int g_orderBySize;
// 重点比较函数,要理解用法
int RentingCmp(const void *a, const void *b)
{
    RentingSystem* left = (RentingSystem*)a;
    RentingSystem* right = (RentingSystem*)b;
    int left_value;
    int right_value;
    for (int i = 0; i < g_orderBySize; i++) {
        int j = g_orderBy[i][0] - 1;
        int order = g_orderBy[i][1];
        if (j == 2) {
            left_value = abs(left->addr[0] - g_address[0]) + abs(left->addr[1] - g_address[1]);
            right_value = abs(right->addr[0] - g_address[0]) + abs(right->addr[1] - g_address[1]);
        } else {
            left_value = left->roomInfo[j];
            right_value = right->roomInfo[j];
        }

        if (left_value == right_value) {
            continue;
        }
        if (order == 1) {
            return left_value - right_value;
        } else {
            return right_value - left_value;
        }
    }
    return left->id - right->id;

}


/*
 * 输入orderBy是长度为orderBySize的数组指针的数组,其中每个元素也是一个数组,此数组长度固定为2。
 * 注意:返回的数组必须由实现者进行内存分配,由框架代码进行内存释放。
 * 返回的数组长度存在 *retSize 中。
 */
int *RentingSystemQueryRoom(RentingSystem *obj, int area, int price, int rooms, int *address, int addressSize,
                            int **orderBy, int orderBySize, int *retSize)
{
    RentingSystem* curr = NULL;
    RentingSystem* next = NULL;

    RentingSystem* filterHead = NULL;
    int cnt = 0;
    HASH_ITER(hh, g_rentingHead, curr, next) {
        if (curr->roomsNum == rooms && curr->roomInfo[0] >= area && curr->roomInfo[1] <= price) {
            RentingSystem* tmp = (RentingSystem*)malloc(sizeof(RentingSystem));
            memset(tmp, 0, sizeof(RentingSystem));
            tmp->id = curr->id;
            tmp->roomsNum = curr->roomsNum;
            memcpy(tmp->roomInfo, curr->roomInfo, sizeof(tmp->roomInfo));
            memcpy(tmp->addr, curr->addr, sizeof(tmp->addr));
            HASH_ADD_INT(filterHead, id, tmp);
            cnt++;
        }
    }
    g_orderBy = orderBy;
    g_orderBySize = orderBySize;
    g_address = address;
    HASH_SORT(filterHead, RentingCmp);

    int *result = (int *)malloc(sizeof(int) * cnt);
    *retSize = cnt;
    cnt = 0;
    HASH_ITER(hh, filterHead, curr, next) {
        result[cnt++] = curr->id;
    }

    return result;
}

void RentingSystemFree(RentingSystem *obj)
{
    RentingSystem* curr = NULL;
    RentingSystem* next = NULL;
    HASH_ITER(hh, g_rentingHead, curr, next) {
        HASH_DEL(g_rentingHead, curr);
        free(curr);
    }
}

posted @ 2021-10-13 20:10  匠人小魏  阅读(131)  评论(0)    收藏  举报