冒泡排序与数组传递全解析 一维二维指针数组及二级指针应用指南

冒泡排序与数组传递全解析 一维二维指针数组及二级指针传参指南

一、冒泡排序核心知识点

冒泡排序是一种简单的交换排序算法,核心思想是通过相邻元素的比较与交换,让较大(或较小)的元素像气泡一样逐步"浮"到数组末端。以升序排序为例,步骤如下:

  1. 比较相邻元素:从数组第一个元素开始,依次比较相邻的两个元素(如arr[i]和arr[i+1])。

  2. 交换逆序元素:如果前一个元素大于后一个元素(arr[i] > arr[i+1]),则交换它们的位置。

  3. 重复多轮:每一轮排序后,最大的元素会"沉"到当前未排序部分的末尾。因此,若有n个元素,需进行n-1轮排序(最后一个元素无需再比较)。

  4. 优化:若某一轮未发生交换,说明数组已有序,可提前结束排序。

二、传递一维数组给冒泡排序函数
知识点

C语言中,数组作为函数参数时会退化为指针 ,因此传递一维数组时需同时传递数组长度(编译器无法通过数组名获取长度)。函数参数可写为int arr[](等价于int *arr),接收数组首地址。

示例代码(含注释)
cpp 复制代码
#include <stdio.h>  

// 冒泡排序函数:对一维数组升序排序  
// 参数:arr 数组首地址(退化为指针),len 数组长度  
void bubble_sort_1d(int arr[], int len) {  
    int i, j, temp;  
    int swapped; // 标记本轮是否发生交换,用于优化  
    for (i = 0; i < len - 1; i++) { // 共需 len-1 轮排序  
        swapped = 0; // 初始化为未交换  
        // 每轮比较次数:未排序部分长度为 len - i,需比较 len - i - 1 次  
        for (j = 0; j < len - i - 1; j++) {  
            if (arr[j] > arr[j + 1]) { // 前大后小,交换  
                temp = arr[j];  
                arr[j] = arr[j + 1];  
                arr[j + 1] = temp;  
                swapped = 1; // 标记发生交换  
            }  
        }  
        if (!swapped) break; // 本轮无交换,数组已有序,提前退出  
    }  
}  

// 打印数组  
void print_array(int arr[], int len) {  
    int i;  
    for (i = 0; i < len; i++) {  
        printf("%d ", arr[i]);  
    }  
    printf("\n");  
}  

int main() {  
    int nums[] = {64, 34, 25, 12, 22, 11, 90};  
    int len = sizeof(nums) / sizeof(nums[0]); // 计算数组长度  

    printf("排序前数组:");  
    print_array(nums, len);  

    bubble_sort_1d(nums, len); // 传递一维数组和长度  

    printf("排序后数组:");  
    print_array(nums, len);  
    return 0;  
}
三、传递二维数组给冒泡排序函数
知识点

二维数组传递需注意函数参数必须指定第二维的大小(除非用指针数组或数组指针)。可将二维数组视为"一维数组"(内存连续),对所有元素统一排序。

示例代码(含注释)
cpp 复制代码
#include <stdio.h>  

// 冒泡排序二维数组(整体排序,视为一维数组)  
// 参数:arr 二维数组首地址(第二维固定为4),rows 行数,cols 列数  
void bubble_sort_2d(int arr[][4], int rows, int cols) {  
    int total = rows * cols; // 总元素个数  
    int i, j, temp;  
    int swapped;  

    for (i = 0; i < total - 1; i++) {  
        swapped = 0;  
        for (j = 0; j < total - i - 1; j++) {  
            // 计算当前元素的行列坐标(模拟一维索引转二维)  
            int row1 = j / cols, col1 = j % cols;  
            int row2 = (j + 1) / cols, col2 = (j + 1) % cols;  

            if (arr[row1][col1] > arr[row2][col2]) {  
                temp = arr[row1][col1];  
                arr[row1][col1] = arr[row2][col2];  
                arr[row2][col2] = temp;  
                swapped = 1;  
            }  
        }  
        if (!swapped) break;  
    }  
}  

// 打印二维数组  
void print_2d_array(int arr[][4], int rows, int cols) {  
    int i, j;  
    for (i = 0; i < rows; i++) {  
        for (j = 0; j < cols; j++) {  
            printf("%d ", arr[i][j]);  
        }  
        printf("\n");  
    }  
}  

int main() {  
    int matrix[3][4] = {{9, 5, 7, 3}, {2, 8, 1, 6}, {4, 0, 10, 12}};  
    int rows = 3, cols = 4;  

    printf("排序前二维数组:\n");  
    print_2d_array(matrix, rows, cols);  

    bubble_sort_2d(matrix, rows, cols);  

    printf("排序后二维数组(整体升序):\n");  
    print_2d_array(matrix, rows, cols);  
    return 0;  
}
四、指针数组与冒泡排序
知识点

指针数组是数组元素为指针变量 的数组(如char *str_arr[])。对指针数组排序时,交换指针 (而非内容)更高效,常用于字符串排序(按字典序)。指针数组名退化为二级指针char **)。

示例代码(含注释)
cpp 复制代码
#include <stdio.h>  
#include <string.h>  

// 冒泡排序指针数组(交换指针,按字符串字典序升序)  
// 参数:str_arr 指针数组首地址(等价于二级指针 char **),len 数组长度  
void bubble_sort_str_ptr(char *str_arr[], int len) {  
    int i, j;  
    char *temp; // 临时指针(交换指针用)  
    int swapped;  

    for (i = 0; i < len - 1; i++) {  
        swapped = 0;  
        for (j = 0; j < len - i - 1; j++) {  
            // strcmp比较字符串:返回正数表示前者大于后者  
            if (strcmp(str_arr[j], str_arr[j + 1]) > 0) {  
                temp = str_arr[j];       // 交换指针(核心)  
                str_arr[j] = str_arr[j + 1];  
                str_arr[j + 1] = temp;  
                swapped = 1;  
            }  
        }  
        if (!swapped) break;  
    }  
}  

// 打印字符串数组  
void print_str_array(char *str_arr[], int len) {  
    int i;  
    for (i = 0; i < len; i++) {  
        printf("%s ", str_arr[i]);  
    }  
    printf("\n");  
}  

int main() {  
    char *fruits[] = {"banana", "apple", "cherry", "date"}; // 指针数组  
    int len = sizeof(fruits) / sizeof(fruits[0]);  

    printf("排序前字符串数组:");  
    print_str_array(fruits, len);  

    bubble_sort_str_ptr(fruits, len); // 传递指针数组(退化为二级指针)  

    printf("排序后字符串数组(字典序升序):");  
    print_str_array(fruits, len);  
    return 0;  
}
五、二级指针传参与冒泡排序
知识点

二级指针 (如int **pp)是指向指针的指针,用于存储"指针变量的地址"。在数组传递中,二级指针主要用于两种场景:

  1. 传递指针数组 :指针数组名本身就是二级指针(如char *str_arr[]等价于char **str_arr)。

  2. 传递动态二维数组 :通过malloc动态分配的二维数组(如int **arr),其数组名也是二级指针。

下面通过两个示例讲解二级指针传参的用法。

示例1 二级指针传递指针数组

之前的指针数组排序中,bubble_sort_str_ptr(char *str_arr[], int len) 的参数**char *str_arr[]** 等价于**char **str_arr**(二级指针)。这里显式用二级指针参数重写,更直观展示二级指针传参逻辑。

cpp 复制代码
#include <stdio.h>  
#include <string.h>  

// 显式用二级指针参数:pp 指向指针数组的指针(即二级指针)  
void bubble_sort_2ptr(char **pp, int len) {  
    int i, j;  
    char *temp;  
    int swapped;  

    for (i = 0; i < len - 1; i++) {  
        swapped = 0;  
        for (j = 0; j < len - i - 1; j++) {  
            if (strcmp(pp[j], pp[j + 1]) > 0) { // 比较字符串  
                temp = pp[j];       // 交换指针(通过二级指针访问元素)  
                pp[j] = pp[j + 1];  
                pp[j + 1] = temp;  
                swapped = 1;  
            }  
        }  
        if (!swapped) break;  
    }  
}  

int main() {  
    char *fruits[] = {"banana", "apple", "cherry", "date"};  
    int len = sizeof(fruits) / sizeof(fruits[0]);  

    // fruits 是指针数组名,退化为二级指针 char **,直接传递给函数  
    bubble_sort_2ptr(fruits, len);  

    printf("排序后(二级指针传参):");  
    for (int i = 0; i < len; i++) {  
        printf("%s ", fruits[i]);  
    }  
    printf("\n");  
    return 0;  
}

核心逻辑 :二级指针pp指向指针数组的首元素(即第一个字符串的地址),通过pp[j]访问第j个字符串的指针,交换时直接操作指针值。

示例2 二级指针传递动态二维数组(动态分配内存)

动态二维数组通过malloc分配:先分配行指针数组(int **arr),再为每行分配列空间。此时arr是二级指针,可直接传递给排序函数。

cpp 复制代码
#include <stdio.h>  
#include <stdlib.h>  

// 冒泡排序动态二维数组(整体排序,视为一维数组)  
// 参数:pp 动态二维数组首地址(二级指针),rows 行数,cols 列数  
void bubble_sort_dynamic_2d(int **pp, int rows, int cols) {  
    int total = rows * cols;  
    int i, j, temp;  
    int swapped;  

    for (i = 0; i < total - 1; i++) {  
        swapped = 0;  
        for (j = 0; j < total - i - 1; j++) {  
            // 计算行列坐标(动态数组同样连续存储)  
            int row1 = j / cols, col1 = j % cols;  
            int row2 = (j + 1) / cols, col2 = (j + 1) % cols;  

            if (pp[row1][col1] > pp[row2][col2]) {  
                temp = pp[row1][col1];  
                pp[row1][col1] = pp[row2][col2];  
                pp[row2][col2] = temp;  
                swapped = 1;  
            }  
        }  
        if (!swapped) break;  
    }  
}  

// 打印动态二维数组  
void print_dynamic_2d(int **pp, int rows, int cols) {  
    int i, j;  
    for (i = 0; i < rows; i++) {  
        for (j = 0; j < cols; j++) {  
            printf("%d ", pp[i][j]);  
        }  
        printf("\n");  
    }  
}  

int main() {  
    int rows = 3, cols = 4;  
    int **matrix = (int **)malloc(rows * sizeof(int *)); // 分配行指针数组  
    for (int i = 0; i < rows; i++) {  
        matrix[i] = (int *)malloc(cols * sizeof(int)); // 为每行分配列空间  
    }  

    // 初始化动态数组  
    int init_data[3][4] = {{9, 5, 7, 3}, {2, 8, 1, 6}, {4, 0, 10, 12}};  
    for (int i = 0; i < rows; i++) {  
        for (int j = 0; j < cols; j++) {  
            matrix[i][j] = init_data[i][j];  
        }  
    }  

    printf("动态数组排序前:\n");  
    print_dynamic_2d(matrix, rows, cols);  

    bubble_sort_dynamic_2d(matrix, rows, cols); // 传递二级指针  

    printf("动态数组排序后(整体升序):\n");  
    print_dynamic_2d(matrix, rows, cols);  

    // 释放内存(避免泄漏)  
    for (int i = 0; i < rows; i++) free(matrix[i]);  
    free(matrix);  
    return 0;  
}

核心逻辑 :动态二维数组的二级指针pp指向行指针数组,通过pp[i][j]访问元素,排序时视为一维数组处理(利用内存连续性)。

六、总结
数组类型 传递方式 本质(退化后) 排序核心思路 典型场景
一维数组 int arr[]int *arr 一级指针 相邻元素比较交换 普通数值数组排序
二维数组(静态) int arr[][N]int (*arr)[N] 数组指针(行指针) 视为一维数组整体排序 固定列数的矩阵排序
指针数组 char *arr[]char **arr 二级指针 交换指针(高效)或交换内容 字符串数组按字典序排序
动态二维数组 int **arr 二级指针 视为一维数组整体排序 运行时动态创建的多维数组排序

二级指针传参的关键 :明确其指向"指针数组"或"动态二维数组的行指针数组",通过解引用(pp[j]pp[i][j])访问元素,排序逻辑与普通数组一致,仅传递方式不同。掌握二级指针传参,能灵活处理更复杂的数组场景(如动态内存、多级指针数据结构)。

相关推荐
m0_561359672 小时前
C++代码冗余消除
开发语言·c++·算法
蒸蒸yyyyzwd2 小时前
c网络编程学习笔记
c语言·网络·学习
烟花落o2 小时前
贪吃蛇及相关知识点讲解
c语言·前端·游戏开发·贪吃蛇·编程学习
近津薪荼2 小时前
优选算法——滑动窗口1(单调性)
c++·学习·算法
头发还没掉光光2 小时前
Linux 高级 IO 深度解析:从 IO 本质到 epoll全面讲解
linux·服务器·c语言·c++
diediedei2 小时前
嵌入式C++驱动开发
开发语言·c++·算法
燃于AC之乐2 小时前
《算法实战笔记》第10期:六大算法实战——枚举、贪心、并查集、Kruskal、双指针、区间DP
算法·贪心算法·图论·双指针·区间dp·二进制枚举
diediedei2 小时前
高性能计算通信库
开发语言·c++·算法
蒸蒸yyyyzwd2 小时前
算法学习笔记
笔记·算法