算法分析之排序
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) 收藏 举报
浙公网安备 33010602011771号