add tk_mergesort

This commit is contained in:
lixianjing 2024-08-11 10:40:30 +08:00
parent ef24f5ced5
commit 7a0dbac018
4 changed files with 128 additions and 3 deletions

View File

@ -1,4 +1,6 @@
# 最新动态
2024/08/11
* 增加函数 tk_mergesort
2024/08/9
* 增加 goto_error_if_fail_ex(感谢兆坤提供补丁)

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}