- 一个租房系统,在系统中增加一个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);
}
}