244 lines
9.1 KiB
C
244 lines
9.1 KiB
C
#include "c_MergeSort.h"
|
|
#include "c_Test.h"
|
|
|
|
// ==========================================
|
|
// 1. 测试用例伴生:通用比对器与稳定性校验结构体
|
|
// ==========================================
|
|
static int sort_compare_ints_with_args(const void* a, const void* b, void* args) {
|
|
(void)args;
|
|
int arg1 = *(const int*)a;
|
|
int arg2 = *(const int*)b;
|
|
if (arg1 < arg2) return -1;
|
|
if (arg1 > arg2) return 1;
|
|
return 0;
|
|
}
|
|
|
|
typedef struct {
|
|
int key; // 核心排序键值
|
|
int origin_order; // 记录元素的原始相对生成次序(用于硬性稳定性验证)
|
|
} StableElement_t;
|
|
|
|
// 仅根据 key 键值进行比对的复合比较器
|
|
static int sort_compare_stable_keys(const void* a, const void* b, void* args) {
|
|
(void)args;
|
|
const StableElement_t* e1 = (const StableElement_t*)a;
|
|
const StableElement_t* e2 = (const StableElement_t*)b;
|
|
if (e1->key < e2->key) return -1;
|
|
if (e1->key > e2->key) return 1;
|
|
return 0;
|
|
}
|
|
|
|
typedef struct {
|
|
int id;
|
|
int weight;
|
|
} Package_t;
|
|
|
|
static int sort_compare_packages(const void* a, const void* b, void* args) {
|
|
(void)args;
|
|
const Package_t* p1 = (const Package_t*)a;
|
|
// 【已修正】:彻底将原先笔误残留下来的 Task_t 符号更正为合法的 Package_t
|
|
const Package_t* p2 = (const Package_t*)b;
|
|
if (p1->weight < p2->weight) return -1;
|
|
if (p1->weight > p2->weight) return 1;
|
|
return 0;
|
|
}
|
|
|
|
// ==========================================
|
|
// 2. 自动化测试用例集
|
|
// ==========================================
|
|
TEST_CASE(test_c_MergeSort_IntArray) {
|
|
int arr[] = { 45, 12, 85, 32, 85, 5, 67, 19, 90, 32 };
|
|
c_size_t num = sizeof(arr) / sizeof(arr[0]);
|
|
|
|
c_MergeSort(arr, num, sizeof(int), sort_compare_ints_with_args, NULL);
|
|
|
|
// 1. 验证全区间是否严格单调不减排列
|
|
for (c_size_t i = 0; i < num - 1; i++) {
|
|
ASSERT_TRUE(arr[i] <= arr[i + 1]);
|
|
}
|
|
ASSERT_INT_EQ(5, arr[0]); // 检查最小值
|
|
ASSERT_INT_EQ(90, arr[num - 1]); // 检查最大值
|
|
}
|
|
|
|
TEST_CASE(test_c_MergeSort_StabilityCheck) {
|
|
// 2. 核心压测:验证归并排序的“稳定性(Stable)”。
|
|
// 构建多组拥有完全相同键值(key = 40)、但原始序号不同的无序序列
|
|
StableElement_t items[] = {
|
|
{ 40, 1 }, // 第一个40
|
|
{ 10, 0 },
|
|
{ 40, 2 }, // 第二个40
|
|
{ 25, 0 },
|
|
{ 40, 3 } // 第三个40
|
|
};
|
|
c_size_t num = sizeof(items) / sizeof(items[0]);
|
|
|
|
c_MergeSort(items, num, sizeof(StableElement_t), sort_compare_stable_keys, NULL);
|
|
|
|
// 验证键值递增
|
|
for (c_size_t i = 0; i < num - 1; i++) {
|
|
ASSERT_TRUE(items[i].key <= items[i + 1].key);
|
|
}
|
|
|
|
// 核心断言:排序后,key同样为 40 的三个元素,其原始顺序必须依然是 1 -> 2 -> 3
|
|
// 修正了上一轮由于漏写数组索引 [idx] 导致的引用错误
|
|
ASSERT_INT_EQ(40, items[2].key); ASSERT_INT_EQ(1, items[2].origin_order);
|
|
ASSERT_INT_EQ(40, items[3].key); ASSERT_INT_EQ(2, items[3].origin_order);
|
|
ASSERT_INT_EQ(40, items[4].key); ASSERT_INT_EQ(3, items[4].origin_order);
|
|
}
|
|
|
|
TEST_CASE(test_c_MergeSort_EdgesAndNull) {
|
|
int ordered_arr[] = { 1, 2, 3, 4 };
|
|
c_size_t num = sizeof(ordered_arr) / sizeof(ordered_arr[0]);
|
|
|
|
// 3. 完全升序数组的无阻碍测试
|
|
c_MergeSort(ordered_arr, num, sizeof(int), sort_compare_ints_with_args, NULL);
|
|
ASSERT_INT_EQ(1, ordered_arr[0]);
|
|
ASSERT_INT_EQ(4, ordered_arr[num - 1]);
|
|
|
|
// 4. 空参数以及单元素数组的拦截压测,彻底杜绝 num-1 引发的无符号下溢崩溃
|
|
int single_arr[] = { 555 };
|
|
c_MergeSort(single_arr, 1, sizeof(int), sort_compare_ints_with_args, NULL);
|
|
c_MergeSort(NULL, 0, sizeof(int), sort_compare_ints_with_args, NULL);
|
|
ASSERT_INT_EQ(555, single_arr[0]);
|
|
}
|
|
|
|
TEST_CASE(test_c_MergeSort_BottomUp_IntArray) {
|
|
// 故意使用一个长度不等于 2 的幂次方的数组 (长度为 11),强迫触发高频边界不规则裁切路径
|
|
int arr[] = { 64, 34, 25, 12, 22, 11, 90, 45, 12, 88, 3 };
|
|
c_size_t num = sizeof(arr) / sizeof(arr[0]);
|
|
|
|
c_MergeSort_BottomUp(arr, num, sizeof(int), sort_compare_ints_with_args, NULL);
|
|
|
|
// 验证区间整体是否呈现绝对严格升序排列
|
|
for (c_size_t i = 0; i < num - 1; i++) {
|
|
ASSERT_TRUE(arr[i] <= arr[i + 1]);
|
|
}
|
|
ASSERT_INT_EQ(3, arr[0]); // 检查最小值
|
|
ASSERT_INT_EQ(90, arr[num - 1]); // 检查最大值
|
|
}
|
|
|
|
TEST_CASE(test_c_MergeSort_BottomUp_StabilityCheck) {
|
|
// 验证非递归自底向上模型的排序“稳定性”。
|
|
StableElement_t items[] = {
|
|
{ 50, 1 }, // 第一个 50
|
|
{ 20, 0 },
|
|
{ 50, 2 }, // 第二个 50
|
|
{ 10, 0 },
|
|
{ 50, 3 } // 第三个 50
|
|
};
|
|
c_size_t num = sizeof(items) / sizeof(items[0]);
|
|
|
|
c_MergeSort_BottomUp(items, num, sizeof(StableElement_t), sort_compare_stable_keys, NULL);
|
|
|
|
// 验证键值递增
|
|
for (c_size_t i = 0; i < num - 1; i++) {
|
|
ASSERT_TRUE(items[i].key <= items[i + 1].key);
|
|
}
|
|
|
|
// 核心断言:排序后,拥有相同键值的项,其内部存储顺序必须依然是 1 -> 2 -> 3
|
|
ASSERT_INT_EQ(50, items[2].key); ASSERT_INT_EQ(1, items[2].origin_order);
|
|
ASSERT_INT_EQ(50, items[3].key); ASSERT_INT_EQ(2, items[3].origin_order);
|
|
ASSERT_INT_EQ(50, items[4].key); ASSERT_INT_EQ(3, items[4].origin_order);
|
|
}
|
|
|
|
TEST_CASE(test_c_MergeSort_BottomUp_EdgesAndNull) {
|
|
int ordered_arr[] = { 10, 20, 30 };
|
|
c_size_t num = sizeof(ordered_arr) / sizeof(ordered_arr[0]);
|
|
|
|
// 完全有序状态测试
|
|
c_MergeSort_BottomUp(ordered_arr, num, sizeof(int), sort_compare_ints_with_args, NULL);
|
|
ASSERT_INT_EQ(10, ordered_arr[0]);
|
|
ASSERT_INT_EQ(30, ordered_arr[num - 1]);
|
|
|
|
// 极端输入安全防御测试,防止无符号整数最大值溢出
|
|
int single_arr[] = { 999 };
|
|
c_MergeSort_BottomUp(single_arr, 1, sizeof(int), sort_compare_ints_with_args, NULL);
|
|
c_MergeSort_BottomUp(NULL, 0, sizeof(int), sort_compare_ints_with_args, NULL);
|
|
ASSERT_INT_EQ(999, single_arr[0]);
|
|
}
|
|
|
|
TEST_CASE(test_c_MergeSort_Optimized_LargeAndCutoff) {
|
|
// 构建一个超越截断阈值(> 15)的长乱序整型数组
|
|
int arr[] = { 89, 45, 68, 90, 23, 12, 57, 46, 35, 78, 24, 11, 5, 99, 41, 102, 33, 1 };
|
|
c_size_t num = sizeof(arr) / sizeof(arr[0]);
|
|
|
|
c_MergeSort_Optimized(arr, num, sizeof(int), sort_compare_ints_with_args, NULL);
|
|
|
|
// 1. 验证大区间在历经自适应截断重组后呈现绝对升序状态
|
|
for (c_size_t i = 0; i < num - 1; i++) {
|
|
ASSERT_TRUE(arr[i] <= arr[i + 1]);
|
|
}
|
|
ASSERT_INT_EQ(1, arr[0]);
|
|
ASSERT_INT_EQ(102, arr[num - 1]);
|
|
}
|
|
|
|
TEST_CASE(test_c_MergeSort_Optimized_PreSortedCheck) {
|
|
// 2. 压测完全有序的输入,强制激活极其高效的有序性前置快速阻断路径
|
|
int ordered_arr[] = { 10, 20, 30, 40, 50, 60, 70, 80, 90 };
|
|
c_size_t num = sizeof(ordered_arr) / sizeof(ordered_arr[0]);
|
|
|
|
c_MergeSort_Optimized(ordered_arr, num, sizeof(int), sort_compare_ints_with_args, NULL);
|
|
|
|
for (c_size_t i = 0; i < num - 1; i++) {
|
|
ASSERT_TRUE(ordered_arr[i] < ordered_arr[i + 1]);
|
|
}
|
|
ASSERT_INT_EQ(10, ordered_arr[0]);
|
|
ASSERT_INT_EQ(90, ordered_arr[num - 1]);
|
|
}
|
|
|
|
TEST_CASE(test_c_MergeSort_Optimized_Stability) {
|
|
// 3. 验证交替角色互换后的稳定排序特性
|
|
Package_t pkgs[] = {
|
|
{ 101, 50 }, // 相同重量 50
|
|
{ 102, 20 },
|
|
{ 103, 50 }, // 相同重量 50
|
|
{ 104, 10 }
|
|
};
|
|
c_size_t num = sizeof(pkgs) / sizeof(pkgs[0]);
|
|
|
|
c_MergeSort_Optimized(pkgs, num, sizeof(Package_t), sort_compare_packages, NULL);
|
|
|
|
// 【已修正】:彻底补上数组定位下标 [idx],解决前一轮缺失索引引起的编译错误
|
|
ASSERT_INT_EQ(10, pkgs[0].weight);
|
|
ASSERT_INT_EQ(20, pkgs[1].weight);
|
|
|
|
// 核心断言:相同键值的项(weight = 50),其原始相对先后生成顺序(id)绝对不能被调换
|
|
ASSERT_INT_EQ(50, pkgs[2].weight); ASSERT_INT_EQ(101, pkgs[2].id);
|
|
ASSERT_INT_EQ(50, pkgs[3].weight); ASSERT_INT_EQ(103, pkgs[3].id);
|
|
}
|
|
|
|
TEST_CASE(test_c_MergeSort_Optimized_Edges) {
|
|
int single_arr[] = { 42 };
|
|
|
|
// 4. 空参数以及单元素安全边界防御
|
|
c_MergeSort_Optimized(single_arr, 1, sizeof(int), sort_compare_ints_with_args, NULL);
|
|
c_MergeSort_Optimized(NULL, 0, sizeof(int), sort_compare_ints_with_args, NULL);
|
|
ASSERT_INT_EQ(42, single_arr[0]);
|
|
}
|
|
|
|
// ==========================================
|
|
// 3. 独立测试运行入口
|
|
// ==========================================
|
|
int main(void) {
|
|
TEST_START(C_TopDownMergeSort_Isolated_TestSuite);
|
|
|
|
// 运行专项排序测试集
|
|
RUN_TEST(test_c_MergeSort_IntArray);
|
|
RUN_TEST(test_c_MergeSort_StabilityCheck);
|
|
RUN_TEST(test_c_MergeSort_EdgesAndNull);
|
|
|
|
RUN_TEST(test_c_MergeSort_BottomUp_IntArray);
|
|
RUN_TEST(test_c_MergeSort_BottomUp_StabilityCheck);
|
|
RUN_TEST(test_c_MergeSort_BottomUp_EdgesAndNull);
|
|
|
|
RUN_TEST(test_c_MergeSort_Optimized_LargeAndCutoff);
|
|
RUN_TEST(test_c_MergeSort_Optimized_PreSortedCheck);
|
|
RUN_TEST(test_c_MergeSort_Optimized_Stability);
|
|
RUN_TEST(test_c_MergeSort_Optimized_Edges);
|
|
|
|
TEST_REPORT();
|
|
|
|
RETURN_TEST_STATUS;
|
|
}
|
|
|