昆仑山:眼中无形心中有穴之穴人合一

夫君子之行,静以修身,俭以养德;非澹泊无以明志,非宁静无以致远。夫学须静也,才须学也;非学无以广才,非志无以成学。怠慢则不能励精,险躁则不能冶性。年与时驰,意与岁去,遂成枯落,多不接世。悲守穷庐,将复何及!

 

算法分析之排序

C语言版本

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <stdbool.h>

// 定义常量
#define MAX_SIZE 10000      // 最大数组大小
#define TEST_SIZE 10       // 测试数组大小
#define DISPLAY_SIZE 20     // 显示数组元素的最大数量

/**
 * 算法性能指标结构体
 * 用于存储每个排序算法的性能数据
 */
typedef struct {
    char name[50];          // 算法名称
    long long comparisons;  // 比较次数
    long long swaps;        // 交换次数
    double time_taken;      // 执行时间(毫秒)
} AlgorithmMetrics;

// 全局计数器,用于统计比较和交换次数
long long comparison_count = 0;  // 比较计数器
long long swap_count = 0;        // 交换计数器

/**
 * 交换两个整数的值
 * @param a 指向第一个整数的指针
 * @param b 指向第二个整数的指针
 */
void swap(int *a, int *b) {
    int temp = *a;    // 临时存储第一个值
    *a = *b;          // 将第二个值赋给第一个位置
    *b = temp;        // 将临时值赋给第二个位置
    swap_count++;     // 增加交换计数
}

/**
 * 比较两个整数的大小
 * @param a 第一个整数
 * @param b 第二个整数
 * @return 如果a > b返回true,否则返回false
 */
bool compare(int a, int b) {
    comparison_count++;  // 增加比较计数
    return a > b;        // 返回比较结果
}

/**
 * 打印数组内容
 * @param arr 要打印的数组
 * @param size 数组大小
 * @param message 打印前的提示信息
 */
void printArray(int arr[], int size, const char *message) {
    printf("%s", message);  // 打印提示信息
    // 确定要显示的元素数量,不超过DISPLAY_SIZE
    int display_count = (size < DISPLAY_SIZE) ? size : DISPLAY_SIZE;

    // 打印数组前display_count个元素
    for (int i = 0; i < display_count; i++) {
        printf("%d ", arr[i]);
    }

    // 如果数组元素超过DISPLAY_SIZE,显示省略信息
    if (size > DISPLAY_SIZE) {
        printf("... (%d more elements)", size - DISPLAY_SIZE);
    }
    printf("\n");
}

/**
 * 复制数组内容
 * @param source 源数组
 * @param dest 目标数组
 * @param size 数组大小
 */
void copyArray(int source[], int dest[], int size) {
    // 逐个复制元素
    for (int i = 0; i < size; i++) {
        dest[i] = source[i];
    }
}

/**
 * 生成指定范围内的随机数组
 * @param arr 目标数组
 * @param size 数组大小
 * @param min 最小值
 * @param max 最大值
 */
void generateRandomArray(int arr[], int size, int min, int max) {
    // 为每个数组元素生成随机数
    for (int i = 0; i < size; i++) {
        // 生成[min, max]范围内的随机数
        arr[i] = min + rand() % (max - min + 1);
    }
}

/**
 * 重置计数器
 * 将比较和交换计数器清零
 */
void resetCounters() {
    comparison_count = 0;  // 重置比较计数器
    swap_count = 0;        // 重置交换计数器
}

// 1. 冒泡排序实现
/**
 * 冒泡排序算法
 * 通过重复遍历数组,比较相邻元素并交换位置来排序
 * @param arr 待排序数组
 * @param n 数组大小
 */
void bubbleSort(int arr[], int n) {
    // 外层循环控制排序轮数
    for (int i = 0; i < n - 1; i++) {
        bool swapped = false;  // 优化标志,检测是否发生交换

        // 内层循环进行相邻元素比较
        for (int j = 0; j < n - i - 1; j++) {
            // 如果前一个元素大于后一个元素,则交换
            if (compare(arr[j], arr[j + 1])) {
                swap(&arr[j], &arr[j + 1]);
                swapped = true;  // 标记发生了交换
            }
        }

        // 如果本轮没有发生交换,说明数组已经有序,可以提前结束
        if (!swapped) break;
    }
}

// 2. 选择排序实现
/**
 * 选择排序算法
 * 每次从未排序部分选择最小元素放到已排序部分的末尾
 * @param arr 待排序数组
 * @param n 数组大小
 */
void selectionSort(int arr[], int n) {
    // 外层循环确定已排序部分的边界
    for (int i = 0; i < n - 1; i++) {
        int min_idx = i;  // 假设当前位置为最小值位置

        // 内层循环在未排序部分寻找真正的最小值
        for (int j = i + 1; j < n; j++) {
            // 如果找到更小的元素,更新最小值索引
            if (compare(arr[min_idx], arr[j])) {
                min_idx = j;
            }
        }

        // 如果最小值不在当前位置,则交换
        if (min_idx != i) {
            swap(&arr[i], &arr[min_idx]);
        }
    }
}

// 3. 插入排序实现
/**
 * 插入排序算法
 * 将数组分为已排序和未排序两部分,逐个将未排序元素插入到已排序部分的正确位置
 * @param arr 待排序数组
 * @param n 数组大小
 */
void insertionSort(int arr[], int n) {
    // 从第二个元素开始处理(第一个元素默认已排序)
    for (int i = 1; i < n; i++) {
        int key = arr[i];  // 当前要插入的元素
        int j = i - 1;     // 已排序部分的最后一个元素索引

        // 在已排序部分中找到合适的插入位置
        while (j >= 0 && compare(arr[j], key)) {
            arr[j + 1] = arr[j];  // 向后移动元素
            j--;                  // 继续向前查找
            swap_count++;         // 记录移动操作
        }
        arr[j + 1] = key;  // 将元素插入到正确位置
    }
}

// 4. 归并排序实现
/**
 * 合并两个已排序的子数组
 * @param arr 原数组
 * @param left 左子数组起始索引
 * @param mid 左子数组结束索引
 * @param right 右子数组结束索引
 */
void merge(int arr[], int left, int mid, int right) {
    int n1 = mid - left + 1;  // 左子数组大小
    int n2 = right - mid;     // 右子数组大小

    // 创建临时数组存储左右子数组
    int *leftArr = (int *) malloc(n1 * sizeof(int));
    int *rightArr = (int *) malloc(n2 * sizeof(int));

    // 复制数据到临时数组
    for (int i = 0; i < n1; i++)
        leftArr[i] = arr[left + i];
    for (int j = 0; j < n2; j++)
        rightArr[j] = arr[mid + 1 + j];

    // 合并两个临时数组到原数组
    int i = 0, j = 0, k = left;

    // 比较两个子数组的元素,将较小的元素放入原数组
    while (i < n1 && j < n2) {
        comparison_count++;  // 增加比较计数
        if (leftArr[i] <= rightArr[j]) {
            arr[k++] = leftArr[i++];  // 选择左子数组元素
        } else {
            arr[k++] = rightArr[j++]; // 选择右子数组元素
        }
        swap_count++;  // 记录元素移动
    }

    // 复制左子数组剩余元素
    while (i < n1) {
        arr[k++] = leftArr[i++];
        swap_count++;
    }

    // 复制右子数组剩余元素
    while (j < n2) {
        arr[k++] = rightArr[j++];
        swap_count++;
    }

    // 释放临时数组内存
    free(leftArr);
    free(rightArr);
}

/**
 * 归并排序递归实现
 * @param arr 待排序数组
 * @param left 起始索引
 * @param right 结束索引
 */
void mergeSortRecursive(int arr[], int left, int right) {
    // 递归终止条件:当子数组只有一个元素或为空时
    if (left < right) {
        int mid = left + (right - left) / 2;  // 计算中点,避免溢出

        // 递归排序左半部分
        mergeSortRecursive(arr, left, mid);
        // 递归排序右半部分
        mergeSortRecursive(arr, mid + 1, right);
        // 合并两个已排序的部分
        merge(arr, left, mid, right);
    }
}

/**
 * 归并排序入口函数
 * @param arr 待排序数组
 * @param n 数组大小
 */
void mergeSort(int arr[], int n) {
    mergeSortRecursive(arr, 0, n - 1);  // 调用递归实现
}

// 5. 快速排序实现
/**
 * 分区函数,将数组分为两部分
 * @param arr 数组
 * @param low 起始索引
 * @param high 结束索引
 * @return 分区点索引
 */
int partition(int arr[], int low, int high) {
    int pivot = arr[high];  // 选择最后一个元素作为基准
    int i = low - 1;        // 较小元素的索引

    // 遍历数组,将小于基准的元素移到左侧
    for (int j = low; j < high; j++) {
        // 如果当前元素小于或等于基准
        if (!compare(arr[j], pivot)) {  // 注意这里使用了逻辑非
            i++;
            swap(&arr[i], &arr[j]);  // 交换元素
        }
    }
    // 将基准元素放到正确位置
    swap(&arr[i + 1], &arr[high]);
    return i + 1;  // 返回分区点索引
}

/**
 * 快速排序递归实现
 * @param arr 数组
 * @param low 起始索引
 * @param high 结束索引
 */
void quickSortRecursive(int arr[], int low, int high) {
    // 递归终止条件
    if (low < high) {
        // 获取分区点
        int pi = partition(arr, low, high);

        // 递归排序分区点左侧部分
        quickSortRecursive(arr, low, pi - 1);
        // 递归排序分区点右侧部分
        quickSortRecursive(arr, pi + 1, high);
    }
}

/**
 * 快速排序入口函数
 * @param arr 待排序数组
 * @param n 数组大小
 */
void quickSort(int arr[], int n) {
    quickSortRecursive(arr, 0, n - 1);  // 调用递归实现
}

// 6. 堆排序实现
/**
 * 调整堆结构,使其满足最大堆性质
 * @param arr 数组
 * @param n 堆大小
 * @param i 当前节点索引
 */
void heapify(int arr[], int n, int i) {
    int largest = i;        // 假设当前节点为最大值
    int left = 2 * i + 1;   // 左子节点索引
    int right = 2 * i + 2;  // 右子节点索引

    // 如果左子节点存在且大于当前最大值
    if (left < n && compare(arr[left], arr[largest])) {
        largest = left;
    }

    // 如果右子节点存在且大于当前最大值
    if (right < n && compare(arr[right], arr[largest])) {
        largest = right;
    }

    // 如果最大值不是当前节点,则交换并继续调整
    if (largest != i) {
        swap(&arr[i], &arr[largest]);
        heapify(arr, n, largest);  // 递归调整受影响的子树
    }
}

/**
 * 堆排序算法
 * @param arr 待排序数组
 * @param n 数组大小
 */
void heapSort(int arr[], int n) {
    // 构建最大堆(从最后一个非叶子节点开始)
    for (int i = n / 2 - 1; i >= 0; i--) {
        heapify(arr, n, i);
    }

    // 逐个提取堆顶元素
    for (int i = n - 1; i > 0; i--) {
        swap(&arr[0], &arr[i]);  // 将堆顶元素移到数组末尾
        heapify(arr, i, 0);      // 重新调整堆
    }
}

// 7. 希尔排序实现
/**
 * 希尔排序算法(缩小增量排序)
 * 是插入排序的一种改进版本,通过设定间隔进行排序
 * @param arr 待排序数组
 * @param n 数组大小
 */
void shellSort(int arr[], int n) {
    // 初始间隔为数组长度的一半,逐步减半
    for (int gap = n / 2; gap > 0; gap /= 2) {
        // 对每个间隔进行插入排序
        for (int i = gap; i < n; i++) {
            int temp = arr[i];  // 当前要插入的元素
            int j;

            // 在间隔为gap的子序列中进行插入排序
            for (j = i; j >= gap && compare(arr[j - gap], temp); j -= gap) {
                arr[j] = arr[j - gap];  // 向后移动元素
                swap_count++;           // 记录移动操作
            }
            arr[j] = temp;  // 插入元素到正确位置
        }
    }
}

// 8. 计数排序实现(仅适用于非负整数)
/**
 * 计数排序算法
 * 通过统计每个元素出现次数来排序,适用于范围较小的整数
 * @param arr 待排序数组
 * @param n 数组大小
 */
void countingSort(int arr[], int n) {
    if (n <= 0) return;  // 空数组直接返回

    // 找到数组中的最大元素
    int max = arr[0];
    for (int i = 1; i < n; i++) {
        comparison_count++;  // 增加比较计数
        if (arr[i] > max) {
            max = arr[i];
        }
    }

    // 创建计数数组和输出数组
    int *count = (int *) calloc(max + 1, sizeof(int));  // 初始化为0
    int *output = (int *) malloc(n * sizeof(int));

    // 统计每个元素出现的次数
    for (int i = 0; i < n; i++) {
        count[arr[i]]++;
    }

    // 计算累积计数(确定每个元素在输出数组中的位置)
    for (int i = 1; i <= max; i++) {
        count[i] += count[i - 1];
    }

    // 构建输出数组(从后向前遍历保证稳定性)
    for (int i = n - 1; i >= 0; i--) {
        output[count[arr[i]] - 1] = arr[i];  // 将元素放到正确位置
        count[arr[i]]--;                     // 减少计数
        swap_count++;                        // 记录移动操作
    }

    // 将排序结果复制回原数组
    for (int i = 0; i < n; i++) {
        arr[i] = output[i];
    }

    // 释放动态分配的内存
    free(count);
    free(output);
}

// 9. 基数排序实现
/**
 * 找到数组中的最大元素
 * @param arr 数组
 * @param n 数组大小
 * @return 最大元素值
 */
int getMax(int arr[], int n) {
    int max = arr[0];  // 假设第一个元素为最大值

    // 遍历数组找到真正的最大值
    for (int i = 1; i < n; i++) {
        comparison_count++;  // 增加比较计数
        if (arr[i] > max) {
            max = arr[i];
        }
    }
    return max;
}

/**
 * 按指定位数进行计数排序
 * @param arr 数组
 * @param n 数组大小
 * @param exp 当前处理的位数(1表示个位,10表示十位,以此类推)
 */
void countingSortForRadix(int arr[], int n, int exp) {
    int *output = (int *) malloc(n * sizeof(int));  // 输出数组
    int count[10] = {0};  // 计数数组,存储0-9每个数字的出现次数

    // 统计当前位上每个数字的出现次数
    for (int i = 0; i < n; i++) {
        count[(arr[i] / exp) % 10]++;
    }

    // 计算累积计数
    for (int i = 1; i < 10; i++) {
        count[i] += count[i - 1];
    }

    // 构建输出数组(从后向前遍历保证稳定性)
    for (int i = n - 1; i >= 0; i--) {
        output[count[(arr[i] / exp) % 10] - 1] = arr[i];  // 放到正确位置
        count[(arr[i] / exp) % 10]--;                    // 减少计数
        swap_count++;                                    // 记录移动操作
    }

    // 将排序结果复制回原数组
    for (int i = 0; i < n; i++) {
        arr[i] = output[i];
    }

    // 释放动态分配的内存
    free(output);
}

/**
 * 基数排序算法
 * 按照低位先排序,然后收集;再按高位排序,然后再收集;依次类推
 * @param arr 待排序数组
 * @param n 数组大小
 */
void radixSort(int arr[], int n) {
    int max = getMax(arr, n);  // 找到最大元素

    // 从个位开始,对每一位进行计数排序
    for (int exp = 1; max / exp > 0; exp *= 10) {
        countingSortForRadix(arr, n, exp);
    }
}

// 10. 鸡尾酒排序实现(双向冒泡排序)
/**
 * 鸡尾酒排序算法
 * 是冒泡排序的改进版本,双向进行冒泡排序
 * @param arr 待排序数组
 * @param n 数组大小
 */
void cocktailSort(int arr[], int n) {
    bool swapped = true;  // 交换标志
    int start = 0;        // 起始索引
    int end = n - 1;      // 结束索引

    // 当发生过交换时继续排序
    while (swapped) {
        swapped = false;

        // 正向遍历(类似冒泡排序)
        for (int i = start; i < end; i++) {
            if (compare(arr[i], arr[i + 1])) {
                swap(&arr[i], &arr[i + 1]);
                swapped = true;
            }
        }

        // 如果没有发生交换,排序完成
        if (!swapped) break;

        end--;       // 缩小排序范围
        swapped = false;

        // 反向遍历
        for (int i = end; i > start; i--) {
            if (compare(arr[i - 1], arr[i])) {
                swap(&arr[i - 1], &arr[i]);
                swapped = true;
            }
        }

        start++;  // 缩小排序范围
    }
}

// 11. 梳排序实现
/**
 * 梳排序算法
 * 是冒泡排序的改进版本,通过逐渐减小比较间隔来提高效率
 * @param arr 待排序数组
 * @param n 数组大小
 */
void combSort(int arr[], int n) {
    int gap = n;           // 初始间隔
    bool swapped = true;   // 交换标志

    // 当间隔大于1或发生过交换时继续排序
    while (gap != 1 || swapped) {
        // 计算新的间隔(缩小因子约为1.3)
        gap = (gap * 10) / 13;
        if (gap < 1) gap = 1;  // 间隔最小为1

        swapped = false;

        // 使用当前间隔进行比较和交换
        for (int i = 0; i < n - gap; i++) {
            if (compare(arr[i], arr[i + gap])) {
                swap(&arr[i], &arr[i + gap]);
                swapped = true;
            }
        }
    }
}

// 12. 地精排序实现
/**
 * 地精排序算法
 * 类似于插入排序,但移动元素的方式不同
 * @param arr 待排序数组
 * @param n 数组大小
 */
void gnomeSort(int arr[], int n) {
    int index = 0;  // 当前处理的索引

    // 遍历整个数组
    while (index < n) {
        // 如果在数组开始位置,直接前进
        if (index == 0) {
            index++;
        }
            // 如果当前元素不小于前一个元素,前进
        else if (!compare(arr[index - 1], arr[index])) {
            index++;
        }
            // 如果当前元素小于前一个元素,交换并后退
        else {
            swap(&arr[index], &arr[index - 1]);
            index--;
        }
    }
}

/**
 * 测试排序算法性能
 * @param sortFunc 排序函数指针
 * @param arr 原始数组
 * @param n 数组大小
 * @param name 算法名称
 * @return 包含性能指标的结构体
 */
AlgorithmMetrics testAlgorithm(void (*sortFunc)(int[], int), int arr[], int n, const char *name) {
    AlgorithmMetrics metrics;        // 性能指标结构体
    strcpy(metrics.name, name);      // 复制算法名称

    // 创建临时数组用于测试
    int *tempArr = (int *) malloc(n * sizeof(int));
    copyArray(arr, tempArr, n);      // 复制原始数组

    resetCounters();                 // 重置计数器

    clock_t start = clock();         // 记录开始时间
    sortFunc(tempArr, n);            // 执行排序
    clock_t end = clock();           // 记录结束时间

    // 记录性能指标
    metrics.comparisons = comparison_count;
    metrics.swaps = swap_count;
    // 计算执行时间(转换为毫秒)
    metrics.time_taken = ((double) (end - start)) / CLOCKS_PER_SEC * 1000;

    free(tempArr);  // 释放临时数组内存

    return metrics;
}

/**
 * 验证数组是否已正确排序
 * @param arr 数组
 * @param n 数组大小
 * @return 如果已排序返回true,否则返回false
 */
bool isSorted(int arr[], int n) {
    // 检查相邻元素是否按升序排列
    for (int i = 0; i < n - 1; i++) {
        if (arr[i] > arr[i + 1]) {
            return false;  // 发现逆序,返回false
        }
    }
    return true;  // 所有元素都已正确排序
}

/**
 * 主函数
 * 程序入口点,执行所有排序算法的测试和比较
 */
int main() {
    srand(time(NULL));  // 初始化随机数种子

    // 打印程序标题
    printf("========================================\n");
    printf("    SORTING ALGORITHMS COMPARISON\n");
    printf("========================================\n\n");

    // 动态分配数组内存
    int *originalArray = (int *) malloc(TEST_SIZE * sizeof(int));
    int *workingArray = (int *) malloc(TEST_SIZE * sizeof(int));

    // 生成随机测试数据
    generateRandomArray(originalArray, TEST_SIZE, 1, 1000);

    // 打印测试信息
    printf("Test Dataset Size: %d elements\n", TEST_SIZE);
    printf("Range: 1 to 1000\n\n");

    // 打印原始数组(前DISPLAY_SIZE个元素)
    printArray(originalArray, TEST_SIZE, "Original Array (first 20 elements): ");
    printf("\n");

    // 定义排序算法结构体
    typedef struct {
        void (*func)(int[], int);  // 排序函数指针
        char name[50];             // 算法名称
    } SortingAlgorithm;

    // 排序算法数组
    SortingAlgorithm algorithms[] = {
            {bubbleSort,    "Bubble Sort"},
            {selectionSort, "Selection Sort"},
            {insertionSort, "Insertion Sort"},
            {mergeSort,     "Merge Sort"},
            {quickSort,     "Quick Sort"},
            {heapSort,      "Heap Sort"},
            {shellSort,     "Shell Sort"},
            {countingSort,  "Counting Sort"},
            {radixSort,     "Radix Sort"},
            {cocktailSort,  "Cocktail Sort"},
            {combSort,      "Comb Sort"},
            {gnomeSort,     "Gnome Sort"}
    };

    // 计算算法数量
    int numAlgorithms = sizeof(algorithms) / sizeof(algorithms[0]);
    // 动态分配结果数组内存
    AlgorithmMetrics *results = (AlgorithmMetrics *) malloc(numAlgorithms * sizeof(AlgorithmMetrics));

    // 打印测试开始信息
    printf("Testing all sorting algorithms...\n");
    printf("----------------------------------------\n\n");

    // 测试每个排序算法
    for (int i = 0; i < numAlgorithms; i++) {
        // 测试算法性能
        results[i] = testAlgorithm(algorithms[i].func, originalArray, TEST_SIZE, algorithms[i].name);

        // 验证排序正确性
        copyArray(originalArray, workingArray, TEST_SIZE);
        resetCounters();
        algorithms[i].func(workingArray, TEST_SIZE);

        // 打印验证结果
        printf("%-20s: ", algorithms[i].name);
        if (isSorted(workingArray, TEST_SIZE)) {
            printf("✓ Sorted correctly\n");
        } else {
            printf("✗ Failed to sort\n");
        }
    }

    // 显示性能比较结果
    printf("\n========================================\n");
    printf("         PERFORMANCE METRICS\n");
    printf("========================================\n\n");

    // 打印表头
    printf("%-20s | %12s | %12s | %12s\n", "Algorithm", "Comparisons", "Swaps", "Time (ms)");
    printf("---------------------|--------------|--------------|-------------\n");

    // 打印每个算法的性能数据
    for (int i = 0; i < numAlgorithms; i++) {
        printf("%-20s | %12lld | %12lld | %12.3f\n",
               results[i].name,
               results[i].comparisons,
               results[i].swaps,
               results[i].time_taken);
    }

    // 时间复杂度分析
    printf("\n========================================\n");
    printf("      TIME COMPLEXITY ANALYSIS\n");
    printf("========================================\n\n");

    // 打印时间复杂度表头
    printf("%-20s | %-15s | %-15s | %-15s | %-10s\n",
           "Algorithm", "Best Case", "Average Case", "Worst Case", "Stable");
    printf("---------------------|-----------------|-----------------|-----------------|------------\n");

    // 打印每种算法的时间复杂度信息
    printf("%-20s | %-15s | %-15s | %-15s | %-10s\n", "Bubble Sort", "O(n)", "O(n²)", "O(n²)", "Yes");
    printf("%-20s | %-15s | %-15s | %-15s | %-10s\n", "Selection Sort", "O(n²)", "O(n²)", "O(n²)", "No");
    printf("%-20s | %-15s | %-15s | %-15s | %-10s\n", "Insertion Sort", "O(n)", "O(n²)", "O(n²)", "Yes");
    printf("%-20s | %-15s | %-15s | %-15s | %-10s\n", "Merge Sort", "O(n log n)", "O(n log n)", "O(n log n)", "Yes");
    printf("%-20s | %-15s | %-15s | %-15s | %-10s\n", "Quick Sort", "O(n log n)", "O(n log n)", "O(n²)", "No");
    printf("%-20s | %-15s | %-15s | %-15s | %-10s\n", "Heap Sort", "O(n log n)", "O(n log n)", "O(n log n)", "No");
    printf("%-20s | %-15s | %-15s | %-15s | %-10s\n", "Shell Sort", "O(n log n)", "O(n^1.3)", "O(n²)", "No");
    printf("%-20s | %-15s | %-15s | %-15s | %-10s\n", "Counting Sort", "O(n + k)", "O(n + k)", "O(n + k)", "Yes");
    printf("%-20s | %-15s | %-15s | %-15s | %-10s\n", "Radix Sort", "O(nk)", "O(nk)", "O(nk)", "Yes");
    printf("%-20s | %-15s | %-15s | %-15s | %-10s\n", "Cocktail Sort", "O(n)", "O(n²)", "O(n²)", "Yes");
    printf("%-20s | %-15s | %-15s | %-15s | %-10s\n", "Comb Sort", "O(n log n)", "O(n²/2^p)", "O(n²)", "No");
    printf("%-20s | %-15s | %-15s | %-15s | %-10s\n", "Gnome Sort", "O(n)", "O(n²)", "O(n²)", "Yes");

    // 打印注释说明
    printf("\nNote: k = range of input for Counting/Radix Sort\n");
    printf("      p = number of increments for Comb Sort\n");

    // 显示排序后的数组示例
    printf("\n========================================\n");
    copyArray(originalArray, workingArray, TEST_SIZE);
    quickSort(workingArray, TEST_SIZE);
    printArray(workingArray, TEST_SIZE, "Sorted Array (first 20 elements): ");

    // 查找最佳性能算法
    printf("\n========================================\n");
    printf("           SUMMARY\n");
    printf("========================================\n\n");

    // 初始化最佳算法索引
    int minCompIdx = 0, minSwapIdx = 0, minTimeIdx = 0;

    // 查找各项指标的最佳算法
    for (int i = 1; i < numAlgorithms; i++) {
        if (results[i].comparisons < results[minCompIdx].comparisons) minCompIdx = i;
        if (results[i].swaps < results[minSwapIdx].swaps) minSwapIdx = i;
        if (results[i].time_taken < results[minTimeIdx].time_taken) minTimeIdx = i;
    }

    // 打印最佳性能算法
    printf("Best Performers:\n");
    printf("  Fewest Comparisons: %s (%lld)\n", results[minCompIdx].name, results[minCompIdx].comparisons);
    printf("  Fewest Swaps:      %s (%lld)\n", results[minSwapIdx].name, results[minSwapIdx].swaps);
    printf("  Fastest Time:      %s (%.3f ms)\n", results[minTimeIdx].name, results[minTimeIdx].time_taken);

    // 打印算法使用建议
    printf("\nRecommendations:\n");
    printf("  • Small datasets (<50): Insertion Sort\n");
    printf("  • Medium datasets: Quick Sort or Merge Sort\n");
    printf("  • Large datasets: Quick Sort (average case) or Heap Sort (guaranteed O(n log n))\n");
    printf("  • Nearly sorted data: Insertion Sort or Bubble Sort with early termination\n");
    printf("  • Stable sort needed: Merge Sort or Counting Sort (for integers)\n");
    printf("  • Limited memory: Heap Sort or Quick Sort (in-place)\n");

    // 释放动态分配的内存
    free(originalArray);
    free(workingArray);
    free(results);

    return 0;
}



C++版本

#include <iostream>
#include <vector>
#include <algorithm>
#include <random>
#include <chrono>
#include <iomanip>
#include <cmath>
#include <functional>

// 使用标准命名空间,避免重复书写std::
using namespace std;
// 使用chrono命名空间,方便时间相关操作
using namespace chrono;

/**
 * 打印数组内容的工具函数
 * @param arr 要打印的数组
 * @param size 要打印的元素个数,默认10个
 */
void printArray(const vector<int> &arr, int size = 10) {
    // 确定实际打印的元素数量,取size和数组大小的较小值
    int limit = min(size, (int) arr.size());
    
    // 打印前limit个元素
    for (int i = 0; i < limit; i++) {
        cout << arr[i] << " ";
    }
    
    // 如果数组元素超过要打印的数量,添加省略号
    if (arr.size() > size) cout << "...";
    cout << endl;
}

/**
 * 生成指定大小的随机数组
 * @param size 数组大小
 * @param minVal 随机数最小值,默认0
 * @param maxVal 随机数最大值,默认1000
 * @return 生成的随机数组
 */
vector<int> generateRandomArray(int size, int minVal = 0, int maxVal = 1000) {
    // 创建随机数设备,用于生成种子
    random_device rd;
    // 创建梅森旋转算法随机数生成器
    mt19937 gen(rd());
    // 创建均匀整数分布,范围[minVal, maxVal]
    uniform_int_distribution<> dis(minVal, maxVal);

    // 创建指定大小的数组
    vector<int> arr(size);
    
    // 填充随机数
    for (int i = 0; i < size; i++) {
        arr[i] = dis(gen);
    }
    
    return arr;
}

// 1. 冒泡排序 - 时间复杂度O(n²)
/**
 * 冒泡排序算法实现
 * 通过重复遍历数组,比较相邻元素并交换位置来排序
 * @param arr 待排序数组的引用
 */
void bubbleSort(vector<int> &arr) {
    int n = arr.size();  // 获取数组大小
    
    // 外层循环控制排序轮数,需要n-1轮
    for (int i = 0; i < n - 1; i++) {
        bool swapped = false;  // 优化标志,检测本轮是否发生交换
        
        // 内层循环进行相邻元素比较,每轮减少一个比较次数
        for (int j = 0; j < n - i - 1; j++) {
            // 如果前一个元素大于后一个元素,则交换
            if (arr[j] > arr[j + 1]) {
                swap(arr[j], arr[j + 1]);
                swapped = true;  // 标记发生了交换
            }
        }
        
        // 如果本轮没有发生交换,说明数组已经有序,可以提前结束
        if (!swapped) break;
    }
}

// 2. 选择排序 - 时间复杂度O(n²)
/**
 * 选择排序算法实现
 * 每次从未排序部分选择最小元素放到已排序部分的末尾
 * @param arr 待排序数组的引用
 */
void selectionSort(vector<int> &arr) {
    int n = arr.size();  // 获取数组大小
    
    // 外层循环确定已排序部分的边界
    for (int i = 0; i < n - 1; i++) {
        int minIdx = i;  // 假设当前位置为最小值位置
        
        // 内层循环在未排序部分寻找真正的最小值
        for (int j = i + 1; j < n; j++) {
            // 如果找到更小的元素,更新最小值索引
            if (arr[j] < arr[minIdx]) {
                minIdx = j;
            }
        }
        
        // 如果最小值不在当前位置,则交换
        if (minIdx != i) {
            swap(arr[i], arr[minIdx]);
        }
    }
}

// 3. 插入排序 - 时间复杂度O(n²)
/**
 * 插入排序算法实现
 * 将数组分为已排序和未排序两部分,逐个将未排序元素插入到已排序部分的正确位置
 * @param arr 待排序数组的引用
 */
void insertionSort(vector<int> &arr) {
    int n = arr.size();  // 获取数组大小
    
    // 从第二个元素开始处理(第一个元素默认已排序)
    for (int i = 1; i < n; i++) {
        int key = arr[i];  // 当前要插入的元素
        int j = i - 1;     // 已排序部分的最后一个元素索引

        // 在已排序部分中找到合适的插入位置
        // 将大于key的元素向后移动
        while (j >= 0 && arr[j] > key) {
            arr[j + 1] = arr[j];  // 向后移动元素
            j--;                  // 继续向前查找
        }
        
        arr[j + 1] = key;  // 将元素插入到正确位置
    }
}

// 4. 归并排序 - 时间复杂度O(n log n)
/**
 * 合并两个已排序的子数组
 * @param arr 原数组的引用
 * @param left 左子数组起始索引
 * @param mid 左子数组结束索引
 * @param right 右子数组结束索引
 */
void merge(vector<int> &arr, int left, int mid, int right) {
    int n1 = mid - left + 1;  // 左子数组大小
    int n2 = right - mid;     // 右子数组大小

    // 创建临时数组存储左右子数组
    vector<int> L(n1), R(n2);

    // 复制数据到临时数组
    for (int i = 0; i < n1; i++)
        L[i] = arr[left + i];
    for (int j = 0; j < n2; j++)
        R[j] = arr[mid + 1 + j];

    // 合并两个临时数组到原数组
    int i = 0, j = 0, k = left;

    // 比较两个子数组的元素,将较小的元素放入原数组
    while (i < n1 && j < n2) {
        if (L[i] <= R[j]) {
            arr[k++] = L[i++];  // 选择左子数组元素
        } else {
            arr[k++] = R[j++];  // 选择右子数组元素
        }
    }

    // 复制左子数组剩余元素
    while (i < n1) {
        arr[k++] = L[i++];
    }

    // 复制右子数组剩余元素
    while (j < n2) {
        arr[k++] = R[j++];
    }
}

/**
 * 归并排序递归辅助函数
 * @param arr 待排序数组的引用
 * @param left 起始索引
 * @param right 结束索引
 */
void mergeSortHelper(vector<int> &arr, int left, int right) {
    // 递归终止条件:当子数组只有一个元素或为空时
    if (left < right) {
        int mid = left + (right - left) / 2;  // 计算中点,避免溢出
        
        // 递归排序左半部分
        mergeSortHelper(arr, left, mid);
        // 递归排序右半部分
        mergeSortHelper(arr, mid + 1, right);
        // 合并两个已排序的部分
        merge(arr, left, mid, right);
    }
}

/**
 * 归并排序入口函数
 * @param arr 待排序数组的引用
 */
void mergeSort(vector<int> &arr) {
    // 只有当数组大小大于1时才需要排序
    if (arr.size() > 1) {
        mergeSortHelper(arr, 0, arr.size() - 1);  // 调用递归实现
    }
}

// 5. 快速排序 - 平均时间复杂度O(n log n),最坏O(n²)
/**
 * 分区函数,将数组分为两部分
 * @param arr 数组的引用
 * @param low 起始索引
 * @param high 结束索引
 * @return 分区点索引
 */
int partition(vector<int> &arr, int low, int high) {
    int pivot = arr[high];  // 选择最后一个元素作为基准
    int i = low - 1;        // 较小元素的索引

    // 遍历数组,将小于基准的元素移到左侧
    for (int j = low; j < high; j++) {
        // 如果当前元素小于基准
        if (arr[j] < pivot) {
            i++;
            swap(arr[i], arr[j]);  // 交换元素
        }
    }
    
    // 将基准元素放到正确位置
    swap(arr[i + 1], arr[high]);
    return i + 1;  // 返回分区点索引
}

/**
 * 快速排序递归辅助函数
 * @param arr 数组的引用
 * @param low 起始索引
 * @param high 结束索引
 */
void quickSortHelper(vector<int> &arr, int low, int high) {
    // 递归终止条件
    if (low < high) {
        // 获取分区点
        int pi = partition(arr, low, high);
        
        // 递归排序分区点左侧部分
        quickSortHelper(arr, low, pi - 1);
        // 递归排序分区点右侧部分
        quickSortHelper(arr, pi + 1, high);
    }
}

/**
 * 快速排序入口函数
 * @param arr 待排序数组的引用
 */
void quickSort(vector<int> &arr) {
    // 只有当数组大小大于1时才需要排序
    if (arr.size() > 1) {
        quickSortHelper(arr, 0, arr.size() - 1);  // 调用递归实现
    }
}

// 6. 堆排序 - 时间复杂度O(n log n)
/**
 * 调整堆结构,使其满足最大堆性质
 * @param arr 数组的引用
 * @param n 堆大小
 * @param i 当前节点索引
 */
void heapify(vector<int> &arr, int n, int i) {
    int largest = i;        // 假设当前节点为最大值
    int left = 2 * i + 1;   // 左子节点索引
    int right = 2 * i + 2;  // 右子节点索引

    // 如果左子节点存在且大于当前最大值
    if (left < n && arr[left] > arr[largest])
        largest = left;

    // 如果右子节点存在且大于当前最大值
    if (right < n && arr[right] > arr[largest])
        largest = right;

    // 如果最大值不是当前节点,则交换并继续调整
    if (largest != i) {
        swap(arr[i], arr[largest]);
        heapify(arr, n, largest);  // 递归调整受影响的子树
    }
}

/**
 * 堆排序算法
 * @param arr 待排序数组的引用
 */
void heapSort(vector<int> &arr) {
    int n = arr.size();

    // 构建最大堆(从最后一个非叶子节点开始)
    for (int i = n / 2 - 1; i >= 0; i--)
        heapify(arr, n, i);

    // 逐个提取堆顶元素
    for (int i = n - 1; i > 0; i--) {
        swap(arr[0], arr[i]);  // 将堆顶元素移到数组末尾
        heapify(arr, i, 0);    // 重新调整堆
    }
}

// 7. 计数排序 - 时间复杂度O(n + k),k为数值范围
/**
 * 计数排序算法
 * 通过统计每个元素出现次数来排序,适用于范围较小的整数
 * @param arr 待排序数组的引用
 */
void countingSort(vector<int> &arr) {
    if (arr.empty()) return;  // 空数组直接返回

    // 找到数组中的最大值和最小值
    int maxVal = *max_element(arr.begin(), arr.end());
    int minVal = *min_element(arr.begin(), arr.end());
    int range = maxVal - minVal + 1;  // 计算数值范围

    // 创建计数数组和输出数组
    vector<int> count(range, 0);  // 初始化为0
    vector<int> output(arr.size());

    // 统计每个元素出现的次数
    for (int i = 0; i < arr.size(); i++)
        count[arr[i] - minVal]++;

    // 计算累积计数(确定每个元素在输出数组中的位置)
    for (int i = 1; i < range; i++)
        count[i] += count[i - 1];

    // 构建输出数组(从后向前遍历保证稳定性)
    for (int i = arr.size() - 1; i >= 0; i--) {
        output[count[arr[i] - minVal] - 1] = arr[i];  // 将元素放到正确位置
        count[arr[i] - minVal]--;                     // 减少计数
    }

    arr = output;  // 将排序结果复制回原数组
}

// 8. 基数排序 - 时间复杂度O(d * (n + k)),d为位数,k为基数
/**
 * 按指定位数进行计数排序
 * @param arr 数组的引用
 * @param exp 当前处理的位数(1表示个位,10表示十位,以此类推)
 */
void countingSortForRadix(vector<int> &arr, int exp) {
    int n = arr.size();
    vector<int> output(n);
    vector<int> count(10, 0);  // 计数数组,存储0-9每个数字的出现次数

    // 统计当前位上每个数字的出现次数
    for (int i = 0; i < n; i++)
        count[(arr[i] / exp) % 10]++;

    // 计算累积计数
    for (int i = 1; i < 10; i++)
        count[i] += count[i - 1];

    // 构建输出数组(从后向前遍历保证稳定性)
    for (int i = n - 1; i >= 0; i--) {
        output[count[(arr[i] / exp) % 10] - 1] = arr[i];  // 放到正确位置
        count[(arr[i] / exp) % 10]--;                    // 减少计数
    }

    arr = output;  // 将排序结果复制回原数组
}

/**
 * 基数排序算法
 * 按照低位先排序,然后收集;再按高位排序,然后再收集;依次类推
 * @param arr 待排序数组的引用
 */
void radixSort(vector<int> &arr) {
    if (arr.empty()) return;  // 空数组直接返回

    int maxVal = *max_element(arr.begin(), arr.end());  // 找到最大元素

    // 从个位开始,对每一位进行计数排序
    for (int exp = 1; maxVal / exp > 0; exp *= 10) {
        countingSortForRadix(arr, exp);
    }
}

// 9. 希尔排序 - 时间复杂度O(n log n)到O(n²)取决于间隔序列
/**
 * 希尔排序算法(缩小增量排序)
 * 是插入排序的一种改进版本,通过设定间隔进行排序
 * @param arr 待排序数组的引用
 */
void shellSort(vector<int> &arr) {
    int n = arr.size();

    // 初始间隔为数组长度的一半,逐步减半
    for (int gap = n / 2; gap > 0; gap /= 2) {
        // 对每个间隔进行插入排序
        for (int i = gap; i < n; i++) {
            int temp = arr[i];  // 当前要插入的元素
            int j;
            
            // 在间隔为gap的子序列中进行插入排序
            for (j = i; j >= gap && arr[j - gap] > temp; j -= gap) {
                arr[j] = arr[j - gap];  // 向后移动元素
            }
            arr[j] = temp;  // 插入元素到正确位置
        }
    }
}

// 10. 桶排序 - 平均时间复杂度O(n + k)
/**
 * 桶排序算法
 * 将数组分到有限数量的桶里,每个桶再分别排序
 * @param arr 待排序数组的引用
 */
void bucketSort(vector<int> &arr) {
    if (arr.empty()) return;  // 空数组直接返回

    // 找到数组中的最大值和最小值
    int maxVal = *max_element(arr.begin(), arr.end());
    int minVal = *min_element(arr.begin(), arr.end());
    int range = maxVal - minVal + 1;  // 计算数值范围
    
    // 确定桶的数量,取数组大小和范围的较小值
    int bucketCount = min((int) arr.size(), range);

    // 创建桶数组
    vector<vector<int>> buckets(bucketCount);

    // 将元素分配到各个桶中
    for (int i = 0; i < arr.size(); i++) {
        // 计算元素应该放入的桶索引
        int idx = (arr[i] - minVal) * bucketCount / (range + 1);
        buckets[idx].push_back(arr[i]);
    }

    // 对每个桶内的元素进行排序
    for (auto &bucket: buckets) {
        sort(bucket.begin(), bucket.end());
    }

    // 按顺序从桶中取出元素,重新填充原数组
    int index = 0;
    for (auto &bucket: buckets) {
        for (int val: bucket) {
            arr[index++] = val;
        }
    }
}

// 11. 梳排序 - 改进的冒泡排序,使用递减间隔
/**
 * 梳排序算法
 * 是冒泡排序的改进版本,通过逐渐减小比较间隔来提高效率
 * @param arr 待排序数组的引用
 */
void combSort(vector<int> &arr) {
    int n = arr.size();
    int gap = n;           // 初始间隔
    bool swapped = true;   // 交换标志

    // 当间隔大于1或发生过交换时继续排序
    while (gap != 1 || swapped) {
        // 计算新的间隔(收缩因子约为1.3)
        gap = (gap * 10) / 13;
        if (gap < 1) gap = 1;  // 间隔最小为1

        swapped = false;

        // 使用当前间隔进行比较和交换
        for (int i = 0; i < n - gap; i++) {
            if (arr[i] > arr[i + gap]) {
                swap(arr[i], arr[i + gap]);
                swapped = true;
            }
        }
    }
}

// 12. 鸡尾酒排序 - 双向冒泡排序
/**
 * 鸡尾酒排序算法
 * 是冒泡排序的改进版本,双向进行冒泡排序
 * @param arr 待排序数组的引用
 */
void cocktailSort(vector<int> &arr) {
    bool swapped = true;  // 交换标志
    int start = 0;        // 起始索引
    int end = arr.size() - 1;  // 结束索引

    // 当发生过交换时继续排序
    while (swapped) {
        swapped = false;

        // 正向遍历(类似冒泡排序)
        for (int i = start; i < end; i++) {
            if (arr[i] > arr[i + 1]) {
                swap(arr[i], arr[i + 1]);
                swapped = true;
            }
        }

        // 如果没有发生交换,排序完成
        if (!swapped) break;

        end--;       // 缩小排序范围
        swapped = false;

        // 反向遍历
        for (int i = end; i > start; i--) {
            if (arr[i] < arr[i - 1]) {
                swap(arr[i], arr[i - 1]);
                swapped = true;
            }
        }

        start++;  // 缩小排序范围
    }
}

// 13. 地精排序 - 类似插入排序的简化版本
/**
 * 地精排序算法
 * 类似于插入排序,但移动元素的方式不同
 * @param arr 待排序数组的引用
 */
void gnomeSort(vector<int> &arr) {
    int index = 0;  // 当前处理的索引

    // 遍历整个数组
    while (index < arr.size()) {
        // 如果在数组开始位置,直接前进
        if (index == 0 || arr[index] >= arr[index - 1]) {
            index++;
        }
        // 如果当前元素不小于前一个元素,前进
        else {
            swap(arr[index], arr[index - 1]);
            index--;
        }
    }
}

// 14. 奇偶排序 - 并行排序算法
/**
 * 奇偶排序算法
 * 交替进行奇数阶段和偶数阶段的比较排序,适合并行处理
 * @param arr 待排序数组的引用
 */
void oddEvenSort(vector<int> &arr) {
    int n = arr.size();
    bool sorted = false;

    // 当数组未排序完成时继续
    while (!sorted) {
        sorted = true;

        // 奇数阶段:比较奇数索引对 (1,2), (3,4), (5,6)...
        for (int i = 1; i < n - 1; i += 2) {
            if (arr[i] > arr[i + 1]) {
                swap(arr[i], arr[i + 1]);
                sorted = false;
            }
        }

        // 偶数阶段:比较偶数索引对 (0,1), (2,3), (4,5)...
        for (int i = 0; i < n - 1; i += 2) {
            if (arr[i] > arr[i + 1]) {
                swap(arr[i], arr[i + 1]);
                sorted = false;
            }
        }
    }
}

// 15. Tim Sort的核心思想 - 结合归并排序和插入排序
/**
 * 对指定范围使用插入排序
 * @param arr 数组的引用
 * @param left 起始索引
 * @param right 结束索引
 */
void insertionSortRange(vector<int> &arr, int left, int right) {
    // 对指定范围内的元素使用插入排序
    for (int i = left + 1; i <= right; i++) {
        int key = arr[i];
        int j = i - 1;
        
        // 在已排序部分中找到合适的插入位置
        while (j >= left && arr[j] > key) {
            arr[j + 1] = arr[j];
            j--;
        }
        arr[j + 1] = key;
    }
}

/**
 * Tim排序算法
 * 结合了归并排序和插入排序的优点,是Python和Java中的默认排序算法
 * @param arr 待排序数组的引用
 */
void timSort(vector<int> &arr) {
    const int RUN = 32;  // 插入排序的子数组大小
    int n = arr.size();

    // 对各个子数组使用插入排序
    for (int i = 0; i < n; i += RUN) {
        insertionSortRange(arr, i, min((i + RUN - 1), (n - 1)));
    }

    // 逐步合并子数组,大小从RUN开始,每次翻倍
    for (int size = RUN; size < n; size = 2 * size) {
        // 每次合并两个大小为size的子数组
        for (int left = 0; left < n; left += 2 * size) {
            int mid = left + size - 1;
            int right = min((left + 2 * size - 1), (n - 1));

            // 如果mid < right,说明有两个子数组需要合并
            if (mid < right) {
                merge(arr, left, mid, right);
            }
        }
    }
}

// 16. BST Sort - 使用二叉搜索树进行排序
/**
 * 二叉树节点结构
 */
struct TreeNode {
    int val;          // 节点值
    TreeNode *left;   // 左子节点指针
    TreeNode *right;  // 右子节点指针

    // 构造函数
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

/**
 * 二叉搜索树类
 */
class BST {
private:
    TreeNode *root;  // 根节点指针

    /**
     * 插入节点的递归辅助函数
     * @param node 当前节点
     * @param val 要插入的值
     * @return 插入后的节点
     */
    TreeNode *insert(TreeNode *node, int val) {
        if (!node) return new TreeNode(val);  // 如果节点为空,创建新节点

        // 根据BST性质插入到左子树或右子树
        if (val <= node->val)
            node->left = insert(node->left, val);
        else
            node->right = insert(node->right, val);

        return node;
    }

    /**
     * 中序遍历,将结果存储到数组中
     * @param node 当前节点
     * @param result 结果数组的引用
     */
    void inorderTraversal(TreeNode *node, vector<int> &result) {
        if (node) {
            inorderTraversal(node->left, result);   // 遍历左子树
            result.push_back(node->val);            // 访问当前节点
            inorderTraversal(node->right, result);  // 遍历右子树
        }
    }

    /**
     * 删除整个树
     * @param node 当前节点
     */
    void deleteTree(TreeNode *node) {
        if (node) {
            deleteTree(node->left);   // 删除左子树
            deleteTree(node->right);  // 删除右子树
            delete node;              // 删除当前节点
        }
    }

public:
    // 构造函数,初始化根节点为空
    BST() : root(nullptr) {}

    // 析构函数,清理内存
    ~BST() {
        deleteTree(root);
    }

    /**
     * 插入值到BST中
     * @param val 要插入的值
     */
    void insert(int val) {
        root = insert(root, val);
    }

    /**
     * 获取排序后的数组
     * @return 排序后的数组
     */
    vector<int> getSortedArray() {
        vector<int> result;
        inorderTraversal(root, result);
        return result;
    }
};

/**
 * BST排序算法
 * 通过构建二叉搜索树并中序遍历来实现排序
 * @param arr 待排序数组的引用
 */
void bstSort(vector<int> &arr) {
    BST bst;
    
    // 将所有元素插入到BST中
    for (int val: arr) {
        bst.insert(val);
    }
    
    // 获取排序后的数组
    arr = bst.getSortedArray();
}

// 计时函数模板,用于测量执行时间
/**
 * 测量函数执行时间的模板函数
 * @tparam Func 函数类型
 * @param sortFunc 排序函数
 * @param arr 待排序数组的引用
 * @return 执行时间(毫秒)
 */
template<typename Func>
double measureTime(Func sortFunc, vector<int> &arr) {
    auto start = high_resolution_clock::now();  // 记录开始时间
    sortFunc(arr);                              // 执行排序函数
    auto end = high_resolution_clock::now();    // 记录结束时间
    
    // 计算时间差并转换为毫秒
    duration<double, milli> diff = end - start;
    return diff.count();
}

// 验证数组是否已排序
/**
 * 验证数组是否已正确排序
 * @param arr 数组的常量引用
 * @return 如果已排序返回true,否则返回false
 */
bool isSorted(const vector<int> &arr) {
    // 检查相邻元素是否按升序排列
    for (int i = 1; i < arr.size(); i++) {
        if (arr[i] < arr[i - 1]) {
            return false;  // 发现逆序,返回false
        }
    }
    return true;  // 所有元素都已正确排序
}

/**
 * 主函数
 * 程序入口点,执行所有排序算法的测试和比较
 */
int main() {
    // 测试参数:不同的数组大小
    vector<int> sizes = { 100, 1000, 5000, 10000 };

    // 打印程序标题
    cout << "=== SORTING ALGORITHMS PERFORMANCE ANALYSIS ===" << endl;
    cout << "Testing with random integer arrays (values 0-1000)" << endl << endl;

    // 对每个数组大小进行测试
    for (int size : sizes) {
        cout << "Array Size: " << size << " elements" << endl;
        cout << string(60, '-') << endl;

        // 生成原始随机数组
        vector<int> original = generateRandomArray(size);

        // 打印样本数据
        cout << "Sample data (first 10 elements): ";
        printArray(original);
        cout << endl;

        // 定义算法结构体,用于存储算法信息
        struct Algorithm {
            string name;                           // 算法名称
            function<void(vector<int>&)> func;     // 排序函数
            bool skipLarge;                        // 是否在大数组时跳过
        };

        // 算法数组,包含所有要测试的排序算法
        vector<Algorithm> algorithms = {
                {"Bubble Sort", bubbleSort, true},
                {"Selection Sort", selectionSort, true},
                {"Insertion Sort", insertionSort, true},
                {"Merge Sort", mergeSort, false},
                {"Quick Sort", quickSort, false},
                {"Heap Sort", heapSort, false},
                {"Shell Sort", shellSort, false},
                {"Counting Sort", countingSort, false},
                {"Radix Sort", radixSort, false},
                {"Bucket Sort", bucketSort, false},
                // 新增的排序算法
                {"Comb Sort", combSort, true},
                {"Cocktail Sort", cocktailSort, true},
                {"Gnome Sort", gnomeSort, true},
                {"Odd-Even Sort", oddEvenSort, true},
                {"Tim Sort", timSort, false},
                {"BST Sort", bstSort, false}
        };

        // 打印表头
        cout << left << setw(20) << "Algorithm"
             << setw(15) << "Time (ms)"
             << setw(15) << "Sorted?"
             << "Time Complexity" << endl;
        cout << string(70, '-') << endl;

        // 测试每个算法
        for (const auto& algo : algorithms) {
            // 对于O(n²)算法,在大数组时跳过以节省时间
            if (algo.skipLarge && size > 5000) {
                cout << left << setw(20) << algo.name
                     << setw(15) << "Skipped"
                     << setw(15) << "-"
                     << "O(n²) - too slow for large arrays" << endl;
                continue;
            }

            // 创建数组副本用于排序
            vector<int> arr = original;

            // 测量执行时间
            double time = measureTime(algo.func, arr);

            // 验证排序结果
            bool sorted = isSorted(arr);

            // 确定时间复杂度
            string complexity;
            if (algo.name == "Bubble Sort" || algo.name == "Selection Sort" ||
                algo.name == "Insertion Sort" || algo.name == "Cocktail Sort" ||
                algo.name == "Gnome Sort" || algo.name == "Odd-Even Sort") {
                complexity = "O(n²)";
            }
            else if (algo.name == "Merge Sort" || algo.name == "Heap Sort") {
                complexity = "O(n log n)";
            }
            else if (algo.name == "Quick Sort") {
                complexity = "O(n log n) avg, O(n²) worst";
            }
            else if (algo.name == "Shell Sort" || algo.name == "Comb Sort") {
                complexity = "O(n log²n)";
            }
            else if (algo.name == "Counting Sort" || algo.name == "Bucket Sort" ||
                     algo.name == "BST Sort") {
                complexity = "O(n + k)";
            }
            else if (algo.name == "Radix Sort") {
                complexity = "O(d × (n + k))";
            }
            else if (algo.name == "Tim Sort") {
                complexity = "O(n log n)";
            }

            // 打印算法测试结果
            cout << left << setw(20) << algo.name
                 << setw(15) << fixed << setprecision(3) << time
                 << setw(15) << (sorted ? "Yes" : "No")
                 << complexity << endl;
        }

        cout << endl << endl;
    }

    // 打印算法特性分析
    cout << "=== ALGORITHM CHARACTERISTICS ===" << endl;
    cout << string(60, '-') << endl;
    cout << "STABLE SORTS: Merge Sort, Insertion Sort, Bubble Sort, Counting Sort, Radix Sort, Bucket Sort, Gnome Sort, Cocktail Sort, Odd-Even Sort, Tim Sort" << endl;
    cout << "UNSTABLE SORTS: Selection Sort, Quick Sort, Heap Sort, Shell Sort, Comb Sort, BST Sort" << endl;
    cout << endl;
    cout << "IN-PLACE SORTS: Bubble, Selection, Insertion, Quick, Heap, Shell Sort, Comb Sort, Cocktail Sort, Gnome Sort, Odd-Even Sort" << endl;
    cout << "NOT IN-PLACE: Merge Sort, Counting Sort, Radix Sort, Bucket Sort, Tim Sort, BST Sort" << endl;
    cout << endl;
    cout << "BEST FOR SMALL ARRAYS: Insertion Sort" << endl;
    cout << "BEST FOR LARGE ARRAYS: Quick Sort, Merge Sort, Heap Sort" << endl;
    cout << "BEST FOR INTEGERS WITH LIMITED RANGE: Counting Sort, Radix Sort" << endl;
    cout << "BEST FOR NEARLY SORTED DATA: Insertion Sort, Bubble Sort (optimized)" << endl;
    cout << "BEST FOR PARALLEL PROCESSING: Odd-Even Sort" << endl;

    return 0;
}



posted on 2025-09-16 15:28  Indian_Mysore  阅读(6)  评论(0)    收藏  举报

导航