C语言程序设计——数组(冒泡排序)

三、冒泡排序

冒泡排序是一种为数组内元素排序的基本方法。

冒泡排序的函数在使用时需要将数组作为参数传入,以下为示例。

对数组arr进行升序排序

先思考如何实现元素的升序排列。

可以以第一个元素为起点,和它的下一个元素作比较,当第n个元素大于n+1时就将二者的值调换,否则就保留,这样使得右端为大值。就这样遍历整个数组,即完成一趟排序。

这时候右端元素应该是众多数字比较下的最大的一个,即最右端已经确定,然后继续重复上述过程,比较剩下的元素以确定右2位。

不断进行下去即可成功实现升序排列。

如果给定数组有n个元素,那么需要遍历以排序的趟数即为n-1趟,而每一趟比较完成后所需要比较的元素就会减少一个,所以第m趟中所要比较的元素数量为n-m+1,因此第n趟需要比较n-m次。

通过代码实现:

#include

void bubble_sort(int arr[])
{
    int i = 0;
    int sz = sizeof(arr) / sizeof(arr[0]);
    for(i=1;i<=sz-1;i++) //此循环是趟数的循环,i即为进行的趟数,需要进行(元素个数-1)次
    {
        int j = 0;
        for(j=0;j

这个代码看似正确,实际上是存在问题的。本人在“函数”的第一次博客中已经提到了这个问题,今天再次强调一遍。

对于数组的参数传递,一定要明确传递过去的是数组arr的首元素地址,即&arr[0]

所以在数组中sizeof(arr)实际上是arr首元素地址,即&arr[0]的大小,也就是一个地址的大小。因为编译环境是32位,所以sizeof(arr)就是4。那么此处的sz恒为1,而不再是数组元素个数。

修改方法很简单,只需要在main函数中算出sz传入函数即可。

#include

void bubble_sort(int arr[],int sz)
{
    int i = 0;
    for(i=1;i<=sz-1;i++) //此循环是趟数的循环,i即为进行的趟数,需要进行(元素个数-1)次
    {
        int j = 0;
        for(j=0;j

针对上述错误,我们不禁发问,数组arr出现在不同地方到底对应着什么含义,这里我们可以做以总结:

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

    return 0;
}

//output:
//00D3F900
//00D3F900
//0

通过编译结果我们可以看到,arr与&arr[0]输出结果一致,均为一个地址,而*arr输出了arr数组第一个元素,这就说明arr与&arr[0]是等价的,即数组名表示数组首元素的地址

两个例外情况:

1)sizeof(数组名),计算的是整个数组的大小,即arr在此处表示整个数组。在函数中传递参数后,进入函数的arr是首元素地址,所以函数中sizeof计算元素个数自然是错误的。

2)&数组名,取出的是整个数组的地址。数组名表示整个数组

通过代码加深理解:

int main()
{
    int arr[] = {1,2,3,4,5,6,7};
    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;
}
//output:
//00D3F900
//00D3F904
//00D3F900
//00D3F904
//00D3F900
//00D3F91C

可以看到arr与&arr[0]是一致的,当+1后,也是指向下一个元素的地址。

数组的地址以首元素地址呈现,所以&arr结果与上两者一致,但是&arr+1就可以看出与&arr相差了28,正好是4*数组元素个数。

最后,这个程序还不是很合理,因为当元素已经成为正序排列,程序仍然会一一比较,所以我们需要一点小技巧来优化这个程序。

#include

void bubble_sort(int arr[],int sz)
{
    int i = 0;
    for(i=1;i<=sz-1;i++) //此循环是趟数的循环,i即为进行的趟数,需要进行(元素个数-1)次
    {
        int j = 0;
        int flag = 1;
        for(j=0;j

此处引入了变量flag,当执行元素调换之后,会修改flag的值。所以如果未进行元素调换,那么也就意味着元素已经是升序排列,则flag的值便不会有变化。这时只需要在程序中加入判断flag的值是否有变化,如果某一趟结束后flag的值没有变化,那么就意味着达成了目的,直接break即可。

本文为学习C语言心得与笔记记录,部分举例来源于B站C语言教学up主鹏哥  

你可能感兴趣的:(c语言,算法,排序算法)