ITPub博客

首页 > 应用开发 > IT综合 > qsort风格冒泡排序实现:通用排序算法设计与回调机制

qsort风格冒泡排序实现:通用排序算法设计与回调机制

投稿 IT综合 作者:bhluo 时间:2025-11-25 14:34:06 0 删除 编辑

**qsort风格冒泡排序实现:通用排序算法设计与回调机制**


通过模拟qsort函数的接口来重新实现冒泡排序,不仅能够深入理解排序算法的本质,还能掌握通用算法设计和函数指针的应用。本文将详细展示如何构建一个具有qsort风格的冒泡排序函数。


### qsort函数接口分析


首先理解标准库qsort函数的接口设计,这是我们实现的基础。


```c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <time.h>


// qsort函数原型分析

void qsort_interface_analysis() {

    printf("=== qsort函数接口分析 ===\n");

    printf("标准qsort函数原型:\n");

    printf("void qsort(void *base, size_t nmemb, size_t size,\n");

    printf("           int (*compar)(const void *, const void *));\n\n");

    

    printf("参数说明:\n");

    printf("base   - 指向数组起始位置的指针\n");

    printf("nmemb  - 数组元素个数\n");

    printf("size   - 每个元素的大小(字节)\n");

    printf("compar - 比较函数指针\n");

    printf("         返回负值: 第一个参数小于第二个\n");

    printf("         返回零:   两个参数相等\n");

    printf("         返回正值: 第一个参数大于第二个\n");

}


// 常用比较函数示例

int compare_int(const void *a, const void *b) {

    return (*(int*)a - *(int*)b);

}


int compare_double(const void *a, const void *b) {

    double diff = (*(double*)a - *(double*)b);

    if (diff < 0) return -1;

    if (diff > 0) return 1;

    return 0;

}


int compare_string(const void *a, const void *b) {

    return strcmp(*(const char**)a, *(const char**)b);

}

```


### 基础冒泡排序实现


从传统的冒泡排序开始,逐步过渡到通用版本。


```c

// 传统整型冒泡排序

void bubble_sort_int(int arr[], int n)<"ES.5283.HK"> {

    printf("=== 传统整型冒泡排序 ===\n");

    

    for (int i = 0; i < n - 1; i++) {

        int swapped = 0;

        for (int j = 0; j < n - 1 - i; j++) {

            if (arr[j] > arr[j + 1]) {

                // 交换元素

                int temp = arr[j];

                arr[j] = arr[j + 1];

                arr[j + 1] = temp;

                swapped = 1;

            }

        }

        // 如果没有发生交换,说明已经有序

        if (!swapped) break;

    }

}


void traditional_bubble_demo() {

    int arr[] = {64, 34, 25, 12, 22, 11, 90};

    int n = sizeof(arr) / sizeof(arr[0]);

    

    printf("排序前: ");

    for (int i = 0; i < n; i++) printf("%d ", arr[i]);

    printf("\n");

    

    bubble_sort_int(arr, n);

    

    printf("排序后: ");

    for (int i = 0; i < n; i++) printf("%d ", arr[i]);

    printf("\n");

}

```


### 通用冒泡排序核心实现


关键步骤:实现通用的交换和比较机制。


```c

// 通用字节交换函数

void swap_bytes(void *a, void *b, size_t size) {

    // 使用临时缓冲区进行交换

    char *ptr_a = (char*)a;

    char *ptr_b = (char*)b;

    char temp;

    

    for (size_t i = 0; i < size; i++)<"PX.5283.HK"> {

        temp = ptr_a[i];

        ptr_a[i] = ptr_b[i];

        ptr_b[i] = temp;

    }

}


// 通用冒泡排序实现

void bubble_sort(void *base, size_t nmemb, size_t size, 

                int (*compar)(const void*, const void*)) {

    if (base == NULL || compar == NULL || nmemb <= 1 || size == 0) {

        return;

    }

    

    char *array = (char*)base;  // 转换为字节指针便于计算

    

    for (size_t i = 0; i < nmemb - 1; i++) {

        int swapped = 0;

        

        for (size_t j = 0; j < nmemb - 1 - i; j++) {

            // 计算当前元素和下一个元素的地址

            void *current = array + j * size;

            void *next = array + (j + 1) * size;

            

            // 使用用户提供的比较函数

            if (compar(current, next) > 0) {

                swap_bytes(current, next, size);

                swapped = 1;

            }

        }

        

        // 提前终止优化

        if (!swapped) break;

    }

}

```


### 完整测试框架


构建全面的测试来验证通用冒泡排序的正确性。


```c

// 测试各种数据类型

void test_various_data_types() {

    printf("\n=== 多数据类型测试 ===\n");

    

    // 整型数组测试

    int int_arr[] = {64, 34, 25, 12, 22, 11, 90, 5, 77, 18};

    int int_count = sizeof(int_arr) / sizeof(int_arr[0]);

    

    printf("整型数组排序:\n");

    printf("排序前: ");

    for (int i = 0; i < int_count; i++) printf("%d ", int_arr[i]);

    

    bubble_sort(int_arr, int_count, sizeof(int), compare_int);

    

    printf("\n排序后: ");

    for (int i = 0; i <"QJ.5283.HK">< int_count; i++) printf("%d ", int_arr[i]);

    printf("\n");

    

    // 浮点数数组测试

    double double_arr[] = {3.14, 2.71, 1.41, 1.73, 0.57, 9.81, 6.28};

    int double_count = sizeof(double_arr) / sizeof(double_arr[0]);

    

    printf("\n浮点数数组排序:\n");

    printf("排序前: ");

    for (int i = 0; i < double_count; i++) printf("%.2f ", double_arr[i]);

    

    bubble_sort(double_arr, double_count, sizeof(double), compare_double);

    

    printf("\n排序后: ");

    for (int i = 0; i < double_count; i++) printf("%.2f ", double_arr[i]);

    printf("\n");

    

    // 字符串数组测试

    const char *str_arr[] = {"orange", "apple", "banana", "grape", "cherry"};

    int str_count = sizeof(str_arr) / sizeof(str_arr[0]);

    

    printf("\n字符串数组排序:\n");

    printf("排序前: ");

    for (int i = 0; i < str_count; i++) printf("%s ", str_arr[i]);

    

    bubble_sort(str_arr, str_count, sizeof(char*), compare_string);

    

    printf("\n排序后: ");

    for (int i = 0; i < str_count; i++) printf("%s ", str_arr[i]);

    printf("\n");

}


// 结构体排序测试

typedef struct {

    int id;

    char name[20];

    double score;

} Student;


int compare_student_by_id(const void *a, const void *b) {

    const Student *s1 = (const Student*)a;

    const Student *s2 = (const Student*)b;

    return s1->id - s2->id;

}


int compare_student_by_score(const void *a, const void *b) {

    const Student *s1 = (const Student*)a;

    const Student *s2 = (const Student*)b;

    if (s1->score < s2->score) return -1;

    if (s1->score > s2->score) return 1;

    return 0;

}


int compare_student_by_name(const void *a, const void *b) {

    const Student *s1 = (const Student*)a;

    const Student *s2 = (const Student*)b;

    return strcmp(s1->name, s2->name);

}


void test_student_sorting() {

    printf("\n=== 结构体排序测试 ===\n");

    

    Student students[] = {

        {103, "张三", 85.5},

        {101, "李四", 92.0},

        {105, "王五", 78.5},

        {102, "赵六", 88.0},

        {104, "钱七", 76.5}

    };

    int count = sizeof(students) / sizeof(students[0]);

    

    // 按ID排序

    printf("按ID排序:\n")<"HL.5283.HK">;

    bubble_sort(students, count, sizeof(Student), compare_student_by_id);

    for (int i = 0; i < count; i++) {

        printf("ID: %d, 姓名: %s, 分数: %.1f\n", 

               students[i].id, students[i].name, students[i].score);

    }

    

    // 按分数排序

    printf("\n按分数排序:\n");

    bubble_sort(students, count, sizeof(Student), compare_student_by_score);

    for (int i = 0; i < count; i++) {

        printf("ID: %d, 姓名: %s, 分数: %.1f\n", 

               students[i].id, students[i].name, students[i].score);

    }

    

    // 按姓名排序

    printf("\n按姓名排序:\n");

    bubble_sort(students, count, sizeof(Student), compare_student_by_name);

    for (int i = 0; i < count; i++) {

        printf("ID: %d, 姓名: %s, 分数: %.1f\n", 

               students[i].id, students[i].name, students[i].score);

    }

}

```


### 性能分析与优化


对比标准qsort和我们的冒泡排序实现。


```c

// 性能测试函数

void performance_test() {

    printf("\n=== 性能测试 ===\n");

    

    const int SIZE = 10000;

    int *test_data1 = malloc(SIZE * sizeof(int));

    int *test_data2 = malloc(SIZE * sizeof(int));

    

    if (!test_data1 || !test_data2) {

        printf("内存分配失败\n");

        return;

    }

    

    // 生成相同的测试数据

    srand(time(NULL));

    for (int i = 0; i < SIZE; i++) {

        int val = rand() % 10000;

        test_data1[i] = val;

        test_data2[i] = val;

    }

    

    // 测试我们的冒泡排序

    clock_t start = clock();

    bubble_sort(test_data1, SIZE, sizeof(int), compare_int);

    clock_t end = clock();

    double bubble_time = (double)(end - start) * 1000 / CLOCKS_PER_SEC;

    

    // 测试标准qsort

    start = clock();

    qsort(test_data2, SIZE, sizeof(int), compare_int);

    end = clock();

    double qsort_time = (double)(end - start) * 1000 / CLOCKS_PER_SEC;

    

    printf("数据量: %d 个整数\n", SIZE);

    printf("冒泡排序耗时: %.2f 毫秒\n", bubble_time);

    printf("qsort耗时: %.2f 毫秒\n", qsort_time);

    printf("性能比率: %.2fx\n", bubble_time / qsort_time);

    

    // 验证排序正确性

    int correct = 1;

    for (int i = 0; i < SIZE - 1; i++) {

        if (test_data1[i] > test_data1[i + 1]) {

            correct = 0;

            break;

        }

    }

    printf("排序正确性: %s\n", correct ? "通过" : "失败");

    

    free(test_data1);

    free(test_data2);

}


// 优化版本:减少交换操作

void optimized_bubble_sort(void *base, size_t nmemb, size_t size,

                          int (*compar)(const void*, const void*)) {

    if (base == NULL || compar == NULL || nmemb <= 1 || size == 0) {

        return;

    }

    

    char *array = (char*)base;

    

    for (size_t i = 0; i < nmemb - 1; i++) {

        int swapped = 0;

        size_t last_swap = nmemb - 1;  // 记录最后一次交换的位置

        

        for (size_t j = 0; j < nmemb - 1 - i; j++) {

            void *current = array + j * size;

            void *next = array + <"CW.5283.HK">(j + 1) * size;

            

            if (compar(current, next) > 0) {

                swap_bytes(current, next, size);

                swapped = 1;

                last_swap = j;  // 更新最后一次交换的位置

            }

        }

        

        // 优化:下一轮只需要遍历到最后一次交换的位置

        if (!swapped) break;

        // nmemb - 1 - i = last_swap;  // 这个优化需要调整循环结构

    }

}

```


### 边界情况和错误处理


确保实现的健壮性。


```c

// 边界情况测试

void edge_cases_test() {

    printf("\n=== 边界情况测试 ===\n");

    

    // 空数组测试

    printf("1. 空数组测试: ");

    int empty_arr[] = {};

    bubble_sort(empty_arr, 0, sizeof(int), compare_int);

    printf("通过\n");

    

    // 单元素数组测试

    printf("2. 单元素数组测试: ");

    int single_arr[] = {42};

    bubble_sort(single_arr, 1, sizeof(int), compare_int);

    printf("排序后: %d - 通过\n", single_arr[0]);

    

    // 已排序数组测试

    printf("3. 已排序数组测试: ");

    int sorted_arr[] = {1, 2, 3, 4, 5};

    bubble_sort(sorted_arr, 5, sizeof(int), compare_int);

    int still_sorted = 1;

    for (int i = 0; i < 4; i++) {

        if (sorted_arr[i] > sorted_arr[i + 1]) {

            still_sorted = 0;

            break;

        }

    }

    printf("%s\n", still_sorted ? "通过" : "失败");

    

    // 逆序数组测试

    printf("4. 逆序数组测试: ");

    int reverse_arr[] = {5, 4, 3, 2, 1};

    bubble_sort(reverse_arr, 5, sizeof(int), compare_int);

    int now_sorted = 1;

    for (int i = 0; i < 4; i++) {

        if (reverse_arr[i] > reverse_arr[i + 1]) {

            now_sorted = 0;

            break;

        }

    }

    printf("%s\n", now_sorted ? "通过" : "失败");

    

    // 包含重复元素的数组

    printf("5. 重复元素测试: ");

    int duplicate_arr[] = {3, 1, 2, 1, 3, 2};

    bubble_sort(duplicate_arr, 6, sizeof(int), compare_int);

    int duplicate_ok = 1;

    for (int i = 0; i < 5; i++) {

        if (duplicate_arr[i] > duplicate_arr[i + 1]) {

            duplicate_ok = 0;

            break;

        }

    }

    printf("%s\n", duplicate_ok ? "通过" : "失败");

}


// 错误处理测试

void error_handling_test() {

    printf("\n=== 错误处理测试 ===\n");

    

    int normal_arr[] = {3, 1, 2};

    

    printf("1. NULL基础指针测试: ");

    bubble_sort(NULL, 3, sizeof(int), compare_int);

    printf("通过(无崩溃)\n");

    

    printf("2. NULL比较函数测试: ");

    bubble_sort(normal_arr, 3, sizeof(int), NULL);

    printf("通过(无崩溃)\n");

    

    printf("3. 零大小元素测试: ");

    bubble_sort(normal_arr, 3, 0, compare_int);

    printf("通过(无崩溃)\n");

    

    printf("4. 零元素数量测试: ")<"NY.5283.HK">;

    bubble_sort(normal_arr, 0, sizeof(int), compare_int);

    printf("通过(无崩溃)\n");

}

```


### 算法可视化与调试支持


添加调试功能来理解算法执行过程。


```c

// 带调试信息的冒泡排序

void debug_bubble_sort(void *base, size_t nmemb, size_t size,

                      int (*compar)(const void*, const void*),

                      void (*print_array)(const void*, size_t)) {

    if (base == NULL || compar == NULL) return;

    

    char *array = (char*)base;

    

    printf("开始排序,元素数量: %zu\n", nmemb);

    

    for (size_t i = 0; i < nmemb - 1; i++) {

        printf("\n第 %zu 轮:\n", i + 1);

        int swapped = 0;

        

        for (size_t j = 0; j < nmemb - 1 - i; j++) {

            void *current = array + j * size;

            void *next = array + (j + 1) * size;

            

            if (compar(current, next) > 0) {

                printf("  交换位置 %zu 和 %zu: ", j, j + 1);

                if (print_array) print_array(base, nmemb);

                

                swap_bytes(current, next, size);

                swapped = 1;

                

                printf(" -> ");

                if (print_array) print_array(base, nmemb);

                printf("\n");

            }

        }

        

        if (!swapped) {

            printf("  本轮无交换,提前终止\n");

            break;

        }

    }

    

    printf("排序完成\n");

}


// 整型数组打印函数

void print_int_array(const void *base, size_t nmemb) {

    const int *arr = (const int*)base;

    for (size_t i = 0; i < nmemb; i++) {

        printf("%d ", arr[i]);

    }

}


void debug_demo() {

    printf("\n=== 调试模式演示 ===\n");

    

    int arr[] = {5, 2, 8, 1, 9};

    int count = sizeof(arr) / sizeof(arr[0]);

    

    printf("原始数组: ");

    print_int_array(arr, count);

    printf("\n");

    

    debug_bubble_sort(arr, count, sizeof(int), compare_int, print_int_array);

    

    printf("最终结果: ");

    print_int_array(arr, count);

    printf("\n");

}

```


### 完整示例程序


```c

int main() {

    printf("基于qsort模拟实现冒泡排序\n");

    printf("=========================\n");

    

    qsort_interface_analysis();

    traditional_bubble_demo();

    test_various_data_types();

    test_student_sorting();

    performance_test();

    edge_cases_test();

    error_handling_test();

    debug_demo<"AT.5283.HK">();

    

    printf("\n=== 实现总结 ===\n");

    printf("1. 成功模拟了qsort的通用接口设计\n");

    printf("2. 通过函数指针支持任意数据类型的比较\n");

    printf("3. 使用字节操作实现通用交换功能\n");

    printf("4. 包含性能优化和错误处理机制\n");

    printf("5. 提供了调试支持以便理解算法执行过程\n");

    printf("\n这个实现展示了如何将特定算法提升为通用工具的重要技巧\n");

    

    return 0;

}

```


通过这个qsort风格的冒泡排序实现,我们不仅深入理解了排序算法的本质,还掌握了通用算法设计、函数指针应用、内存操作等C语言核心概念。这种设计思想可以扩展到其他算法的实现中,创建出灵活且可重用的代码库。


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/19545/viewspace-3103370/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2015-11-01

  • 博文量
    895
  • 访问量
    933887