数组(2)

似梦清欢
• 阅读 425
数组作为函数参数
冒泡排序

冒泡排序算法的原理: 比较相邻的元素。如果第一个比第二个大,就交换他们两个。 对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。 针对所有的元素重复以上的步骤,除了最后一个。 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

#include <stdio.h>

void bubble_sort(int arr[], int sz)
{
    int i = 0;  //冒泡排序的趟数
    for (i;i < sz-1;i++)  //共需要sz-1趟
    {
        int j = 0;
        for (j; j < sz-1-i; j++)
        {
            if (arr[j] > arr[j + 1])  //交换元素大小
            {
                int tmp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = tmp;
            }
        }
    }
}

int main()
{
    int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
    int sz = sizeof(arr) / sizeof(arr[0]);
    bubble_sort(arr, sz);
    int i = 0;
    for (i; i < sz; i++)
    {
        printf("%d ", arr[i]);
    }
    return 0;
}
0 1 2 3 4 5 6 7 8 9

::: tip 代码思路: 数组(2) 上图中一组数字的相邻两个数字比较,确定该组数字中最大的数字。称为一趟冒泡排序。 一趟冒泡拍排序可以确定一个数字的最终位置,上图中一组数字共有10个,需要9趟冒泡排序确定9个数字的位置,剩下一个数字位置不变。 ::: 上述代码中第9行代码的判断条件的选择依据: 每一趟冒泡排序都需要进行上述图片中的相邻数字比较,每趟确定一个数字位置。第一趟需要比较sz-1对数字,第二趟需要比较sz-1-1对数字,第三趟需要比较sz-1-2对数字,即判断条件需要有一个变量,而跟随趟数变化的是变量i,从0开始每次i++,即判断条件可以写成sz-1-i,依此类推直到跳出循环。


代码优化

::: warning 上述代码数组中数字无论怎么排序都要经过相邻两数的比较,效率很低。当对一组数字进行第一趟冒泡排序时,没有数字发生交换,即该组数字的位置不需要交换时,说明该组数字已经是有序的。 ::: 代码优化:

#include <stdio.h>

void bubble_sort(int arr[], int sz)
{
    int i = 0;
    for (i;i < sz-1;i++)
    {
        int flag = 1;  //假设数组中数字已经是有序排列
        int j = 0;
        for (j; j < sz-1-i; j++)
        {
            if (arr[j] > arr[j + 1])  //当存在顺序不对的情况时,进入循环
            {
                int tmp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = tmp;
                flag = 0;  //循环内数字位置发生交换,本趟排序时并不是有序数组,flag置为0
            }
        }
        if (flag == 1)
            break;  //当flag为1时,跳出for循环(见下方提示框)
    }
}

int main()
{
    int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
    int sz = sizeof(arr) / sizeof(arr[0]);
    bubble_sort(arr, sz);
    int i = 0;
    for (i; i < sz; i++)
    {
        printf("%d ", arr[i]);
    }
    return 0;
}

::: danger 在上述代码中,主函数将数组arr作为参数传递给函数bubble_sort时,实际传递的是数组arr的首元素地址&arr[0],即int*arr。 ::: ::: tip break语句只能用于跳出for循环和switch循环,在if语句中不能使用,原因是if不是循环语句,不能用break结束。 上述代码中第21行if语句内的break,实际上是用来跳出外层的for循环。 :::


数组名

验证数组名是数组首元素地址:

#include <stdio.h>

int main()
{
    int arr[] = { 1,2,3,4,5,6 };
    printf("%p\n", arr);
    printf("%p\n", &arr[0]);  //数组首元素地址

    printf("%d\n", *arr);  //数组内首元素解引用
    return 0;
}
000000443CEFFC48
000000443CEFFC48
1
两个例外

数组名在传参等其他场景时表示数组首元素地址,下面两种情况除外:

  1. sizeof(数组名)。数组名表示整个数组。sizeof(数组名) 计算整个数组的大小,单位是字节。
  2. &数组名。数组名表示整个数组。&数组名 取出的是整个数组的地址。
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

int main()
{
    int arr[] = { 1,2,3,4,5,6 };
    printf("%p\n", arr);
    printf("%p\n", &arr[0]);
    printf("%p\n", &arr);
    return 0;
}
0000002B662FFAC8
0000002B662FFAC8
0000002B662FFAC8

上述代码中,第7行和第8行代码打印的是数组arr的首元素地址。第9行打印的是数组arr的地址。虽然结果是相同的,但意义不同。&arr表示数组开始的位置,是整个数组的地址。如下:

#include <stdio.h>

int main()
{
    int arr[] = { 1,2,3,4,5,6 };
    printf("%p\n", arr);
    printf("%p\n", arr+1);
    printf("%p\n", &arr[0]);
    printf("%p\n", &arr[0]+1);
    printf("%p\n", &arr);
    printf("%p\n", &arr+1);
    return 0;
}
000000F5E692F758
000000F5E692F75C
000000F5E692F758
000000F5E692F75C
000000F5E692F758
000000F5E692F770

上述代码中,arr和arr[0]表示的含义相同,它们+1后表示的含义也相同,即第6行和第8行代码结果相同,第7行和第9行代码结果相同,都是增加了4个字节,第10行代码的结果和第6行第8行相同,但&arr和&arr+1之间相差24,正好是数组arr的实际长度4*6,即从数组首元素的位置跳到数组中最后一个元素的位置,跳过了整个数组。

点赞
收藏
评论区
推荐文章

暂无数据

似梦清欢
似梦清欢
Lv1
慢慢来吧...
文章
17
粉丝
12
获赞
1