mirror of
https://github.com/zlgopen/awtk.git
synced 2025-05-08 11:33:48 +08:00
add tk_mergesort
This commit is contained in:
parent
ef24f5ced5
commit
7a0dbac018
@ -1,4 +1,6 @@
|
||||
# 最新动态
|
||||
2024/08/11
|
||||
* 增加函数 tk_mergesort
|
||||
|
||||
2024/08/9
|
||||
* 增加 goto_error_if_fail_ex(感谢兆坤提供补丁)
|
||||
|
@ -1590,8 +1590,7 @@ uint32_t tk_strnlen(const char* str, uint32_t maxlen) {
|
||||
const char* s;
|
||||
return_value_if_fail(str != NULL, 0);
|
||||
|
||||
for (s = str; maxlen-- && *s != '\0'; ++s)
|
||||
;
|
||||
for (s = str; maxlen-- && *s != '\0'; ++s);
|
||||
return s - str;
|
||||
}
|
||||
|
||||
@ -2473,7 +2472,7 @@ ret_t tk_buffer_get_value(uint8_t* buffer, uint32_t size, value_type_t type, int
|
||||
break;
|
||||
}
|
||||
case VALUE_TYPE_BINARY: {
|
||||
uint32_t bsize = size - (data - buffer);
|
||||
uint32_t bsize = size - (data - buffer);
|
||||
value_set_binary_data(value, data, bsize);
|
||||
break;
|
||||
}
|
||||
@ -2585,3 +2584,77 @@ const char* tk_skip_to_chars(const char* str, const char* chars) {
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
static void merge(void* base, size_t size, tk_compare_t cmp, void* left,
|
||||
size_t leftSize, void* right, size_t rightSize) {
|
||||
// 创建临时数组
|
||||
void* temp = TKMEM_ALLOC((leftSize + rightSize) * size);
|
||||
if (temp == NULL) {
|
||||
fprintf(stderr, "Memory allocation failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
size_t i = 0, j = 0, k = 0;
|
||||
|
||||
// 归并两个子数组
|
||||
while (i < leftSize && j < rightSize) {
|
||||
if (cmp((char*)left + i * size, (char*)right + j * size) <= 0) {
|
||||
memcpy((char*)temp + k * size, (char*)left + i * size, size);
|
||||
i++;
|
||||
} else {
|
||||
memcpy((char*)temp + k * size, (char*)right + j * size, size);
|
||||
j++;
|
||||
}
|
||||
k++;
|
||||
}
|
||||
|
||||
// 复制剩余的左边部分
|
||||
while (i < leftSize) {
|
||||
memcpy((char*)temp + k * size, (char*)left + i * size, size);
|
||||
i++;
|
||||
k++;
|
||||
}
|
||||
|
||||
// 复制剩余的右边部分
|
||||
while (j < rightSize) {
|
||||
memcpy((char*)temp + k * size, (char*)right + j * size, size);
|
||||
j++;
|
||||
k++;
|
||||
}
|
||||
|
||||
// 将排序后的内容复制回原数组
|
||||
memcpy(base, temp, (leftSize + rightSize) * size);
|
||||
TKMEM_FREE(temp);
|
||||
}
|
||||
|
||||
static void tk_mergesort_impl(void* base, size_t nmemb, size_t size,
|
||||
tk_compare_t cmp) {
|
||||
if (nmemb < 2) return; // 如果只有一个元素,不需要排序
|
||||
|
||||
size_t mid = nmemb / 2;
|
||||
|
||||
// 递归排序左半部分
|
||||
tk_mergesort_impl(base, mid, size, cmp);
|
||||
// 递归排序右半部分
|
||||
tk_mergesort_impl((char*)base + mid * size, nmemb - mid, size, cmp);
|
||||
|
||||
// 归并排序的结果
|
||||
void* left = base;
|
||||
void* right = (char*)base + mid * size;
|
||||
|
||||
// 计算左右部分的大小
|
||||
size_t leftSize = mid;
|
||||
size_t rightSize = nmemb - mid;
|
||||
|
||||
// 合并两个已排序的部分
|
||||
merge(base, size, cmp, left, leftSize, right, rightSize);
|
||||
}
|
||||
|
||||
ret_t tk_mergesort(void* base, size_t nmemb, size_t size, tk_compare_t cmp) {
|
||||
return_value_if_fail(cmp != NULL, RET_BAD_PARAMS);
|
||||
return_value_if_fail(base != NULL&& nmemb != 0 && size != 0, RET_BAD_PARAMS);
|
||||
|
||||
tk_mergesort_impl(base, nmemb, size, cmp);
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
@ -1318,6 +1318,17 @@ const char* tk_skip_chars(const char* str, const char* chars);
|
||||
*/
|
||||
const char* tk_skip_to_chars(const char* str, const char* chars);
|
||||
|
||||
/**
|
||||
* @method tk_mergesort
|
||||
* 归并排序(如果需要稳定的排序,可以选择归并排序,而不是快速排序)。
|
||||
* @param {void*} base 数据。
|
||||
* @param {size_t} nmemb 元素个数。
|
||||
* @param {size_t} size 元素大小。
|
||||
* @param {tk_compare_t} cmp 比较函数。
|
||||
* @return {ret_t} 返回RET_OK表示成功,否则表示失败。
|
||||
*/
|
||||
ret_t tk_mergesort(void* base, size_t nmemb, size_t size, tk_compare_t cmp);
|
||||
|
||||
#define TK_STRDUP(str) ((str) != NULL) ? tk_strdup(str) : NULL
|
||||
#define TK_STRNDUP(str, len) ((str) != NULL) ? tk_strndup(str, len) : NULL
|
||||
|
||||
|
@ -1872,3 +1872,42 @@ TEST(Utils, skip_to_chars) {
|
||||
ASSERT_STREQ(tk_skip_to_chars("abc123", "A"), "");
|
||||
ASSERT_STREQ(tk_skip_to_chars("abc123", "a"), "abc123");
|
||||
}
|
||||
|
||||
static int tk_compare_int32(const void* a, const void* b) {
|
||||
return *(int*)a - *(int*)b;
|
||||
}
|
||||
|
||||
typedef struct _person_t {
|
||||
int age;
|
||||
char name[32];
|
||||
} person_t;
|
||||
|
||||
static int person_cmp_age(const void* a, const void* b) {
|
||||
return ((person_t*)a)->age - ((person_t*)b)->age;
|
||||
}
|
||||
|
||||
TEST(Utils, mergesort1) {
|
||||
int32_t arr[] = {38, 27, 43, 3, 9, 82, 10};
|
||||
tk_mergesort(arr, ARRAY_SIZE(arr), sizeof(arr[0]), tk_compare_int32);
|
||||
|
||||
ASSERT_EQ(arr[0], 3);
|
||||
ASSERT_EQ(arr[1], 9);
|
||||
ASSERT_EQ(arr[2], 10);
|
||||
ASSERT_EQ(arr[3], 27);
|
||||
ASSERT_EQ(arr[4], 38);
|
||||
ASSERT_EQ(arr[5], 43);
|
||||
ASSERT_EQ(arr[6], 82);
|
||||
}
|
||||
|
||||
TEST(Utils, mergesort2) {
|
||||
person_t arr[] = {{38, "a"}, {27, "b"}, {43, "c"}, {3, "d"}, {9, "e"}, {82, "f"}, {10, "g"}};
|
||||
tk_mergesort(arr, ARRAY_SIZE(arr), sizeof(arr[0]), person_cmp_age);
|
||||
|
||||
ASSERT_EQ(arr[0].age, 3);
|
||||
ASSERT_EQ(arr[1].age, 9);
|
||||
ASSERT_EQ(arr[2].age, 10);
|
||||
ASSERT_EQ(arr[3].age, 27);
|
||||
ASSERT_EQ(arr[4].age, 38);
|
||||
ASSERT_EQ(arr[5].age, 43);
|
||||
ASSERT_EQ(arr[6].age, 82);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user