【算法】逐层深度解析冒泡排序法

算法系列

本节以C语言来深度讲述冒泡排序。


冒泡排序的原理

冒泡排序的原理是:数组中,从左到右,相邻元素进行比较。每次比较一次找到两个之间最大或者最小的数,向右排序,一轮过后就会有最大或者最小的一个数从序列的最右边冒出。
本文用C语言详细讲解冒泡排序。

思维引导

比如将下面的一串数字进行排序

2,4,6,1,7,30,5,8,20,49

定义数组会吧!先定义一个数组对他进行初始化

#include<stdio.h>
int main()
{
	int a[] = {2,4,6,1,7,30,5,8,20,49};
}

计算数组的元素个数会吧

int N;
N = sizeof(a)/sizeof(a[0]);

OK! for循环遍历数组会吧!

for(int i = 0; i < N; i++)
{
	printf("%d ", a[i]);
}

相邻的两个数组元素进行交换会吧

int max;
max = a[i];
a[i+1] = max;
a[i] = a[i+1];

ok! 结合上方的判断数组相邻的两个元素的大小会吧

if(a[i]>a[i+1])//判断数组相邻两个元素的大小,前者大于后者将进行交换
{
	max = a[i];
	a[i+1] = max;
	a[i] = a[i+1];
}

那么将上面的整合在一起就能实现数组两个相邻元素之间的交换!

#include <stdio.h>
int main()
{
    int a[] = {2, 4, 6, 1, 7, 30, 5, 8, 20, 49};
    int N, i, max;
    N = sizeof(a) / sizeof(a[0]);
    for (int i = 0; i < N; i++) 
    {
        printf("%d ", a[i]);// 打印交换前
    }
    printf("\n");//换行分开
    for (int i = 0; i < N; i++)
    {
        printf("%d ", a[i]); // 打印交换后的数据
        if (a[i] > a[i + 1])
        {
            max = a[i];
            a[i] = a[i + 1];
            a[i + 1] = max;
        }
    }
}
打印出的数据如下:
2 4 6 1 7 30 5 8 20 49
2 4 1 6 7 5 8 20 30 32

出现32是因为当i=9时i-1没有值,出现错误!

以上可以简单实现数组相邻元素之间的大小比较和交换,但是并没有实现数组的排序!
并且出现小错误。问题在哪?你会发现再添加一个for循环就会实现!

冒泡排序

每次进行比较,最大的放到右边,一轮过后就会把所有数中最大的放到最右边!

举个栗子:1,-1,2,-2四个数中进行比较
第一轮(i=0)时:
j=0时:1和-1比较,1和-1进行交换:-1,1,2,-2
j=1时:1和2比较,1和2不进行交换:-1,1,2,-2
j=2时:2和-2比较,2和-2进行交换:-1,1,-2,2
最终结果为:-1,1,-2,2
第二轮(i=1)时:
j=0时:-1和1比较,-1和1不交换:-1,1,-2,2
j=1时:1和-2比较,1和-2进行交换:-1,-2,1,2
因为第一轮最大的已经放在右边所以不用再进行比较
最终结果为:-1,-2,1,2
第三轮(i=2)时:
j=0时:-1和-2进行比较,-1和-2进行交换:-2,-1,1,2
最终结果为:-2,-1,1,2
此时已经比较完。

具体如下图:
在这里插入图片描述
由上方推导不难看出:

当N=4时,外层循环 i 执行 N-1 次,内层循环 j 执行 N-1-i 次

循环如下:

 for ( i = 0; i < N-1; i++)
    {
        for ( j = 0; j < N-1-i; j++)
        {
            if (a[j]>a[j+1])
            {
                //此处是交换两个值,而不是取最大的
                max = a[j];
                a[j]=a[j+1];
                a[j+1]=max;
            }
        }    
    }

ok!循环部分搞定了,将上方的数组结合试试看!
完整代码如下:

#include <stdio.h>
int main()
{
    int a[] = {2, 4, 6, 1, 7, 30, 5, 8, 20, 49};
    int N, i, j, max;
    N = sizeof(a) / sizeof(a[0]);
    for (int i = 0; i < N; i++) 
    {
        printf("%d ", a[i]);// 打印交换前
    }
    printf("\n"); // 换行分开
    // 冒泡排序
    for (i = 0; i < N- 1; i++)
    {
        for (j = 0; j < N- 1 - i; j++)
        {
            if (a[j] > a[j + 1])
            {
                // 此处是交换两个值,而不是取最大的
                max = a[j];
                a[j] = a[j + 1];
                a[j + 1] = max;
            }
        }
    }
    for (i = 0; i < N; i++) // 打印排序后的数据
    {
        printf("%d ", a[i]);
    }
    return 0;
}

OK!成功!结果如下:

2 4 6 1 7 30 5 8 20 49
1 2 4 5 6 7 8 20 30 49

请继续向下看!现在已经完成对数组的排序,可以尝试改善一下代码。加入一些其他的元素!

手动输入数组

比如手动输入一串数组,对其进行排序!
循环遍历键入数组值!

#include <stdio.h>
#define M 1000 // 宏定义数组的元素个数(足够大)
int main()
{
    int a[M];
    for (int i = 0; i < M; i++)
    {
        scanf("%d", &a[i]);
    }
}

我们可以看到上述代码有缺陷!它的M值太大就会导致输入没有上限,也就是缺少终止命令!
OK那添加一个终止命令,我们换一种循环方式如下:

#include <stdio.h>
#define M 1000 // 宏定义数组的元素个数(足够大)
int main()
{
    int a[M];
    int i=0;
    do
    {
        scanf("%d",&a[i]);
        i++;
    } while ((a[i]=getchar())!='\n');//终止条件,当键入回车时退出循环!
}

此时就可以实现输入数组,进行排序,代码如下:

#include <stdio.h>
#define M 1000 // 宏定义数组的元素个数(足够大)
int main()
{
    int a[M];
    int i=0,j,N,max;
    do
    {
        scanf("%d",&a[i]);
        i++;
        N += 1;//每循环一次N加1,用来记录N的值,键入数组元素的个数!(因为M值为1000,所以要记录数组的元素个数)
    } while ((a[i]=getchar())!='\n');//终止条件,当键入回车时退出循环!
    //N = sizeof(a)/sizeof(a[0]);N已经计录过数组的元素个数!所以此处不用计算
    for (int i = 0; i < N; i++) 
    {
        printf("%d ", a[i]);// 打印交换前
    }
    printf("\n"); // 换行分开
    // 冒泡排序
    for (i = 0; i < N- 1; i++)
    {
        for (j = 0; j < N- 1 - i; j++)
        {
            if (a[j] > a[j + 1])
            {
                // 此处是交换两个值,而不是取最大的
                max = a[j];
                a[j] = a[j + 1];
                a[j + 1] = max;
            }
        }
    }
    for (i = 0; i < N; i++) // 打印排序后的数据
    {
        printf("%d ", a[i]);
    }
    return 0;
}

运行代码如下:

4 3 2 6 5 1 7 9 (回车输入)
4 3 2 6 5 1 7 9
1 2 3 4 5 6 7 9

OK已经实现手动输入数组进行排序。那么如果再进一步不想进行手动输入呢?

生成随机数

我们引入随机数函数 rand()srand() 函数!

#include <stdio.h>
#include <time.h>
#include <stdlib.h>//随机数需要引入两个头文件time.h和stdlib.h
int main()
{
	int i;
	srand((unsigned)time(NULL));//使用传入空指针播种子
   	i = rand()%100;//随机生成100以内的数
   	printf("%d ",i);
}

生成随机数搞定,下面结合上述程序
程序如下:

#include <stdio.h>
#include <time.h>
#include <stdlib.h>//随机数需要引入两个头文件time.h和stdlib.h
#define M 1000 // 宏定义数组的元素个数(足够大)
int main()
{
    int a[M];
    int i = 0, j, N, max;
    printf("请输入你要的数组元素个数:\n");
    scanf("%d",&N);//此处对N赋值,让用户控制输入的数组元素个数
    srand((unsigned)time(NULL));//使用传入空指针播种子
    for (int i = 0; i < N; i++) 
    {
    	a[i] = rand()%100;//随机生成100以内的数
        printf("%d ", a[i]);// 打印交换前
    }
    printf("\n"); // 换行分开
    // 冒泡排序
    for (i = 0; i < N - 1; i++)
    {
        for (j = 0; j < N - 1 - i; j++)
        {
            if (a[j] > a[j + 1])
            {
                // 此处是交换两个值,而不是取最大的
                max = a[j];
                a[j] = a[j + 1];
                a[j + 1] = max;
            }
        }
    }
    for (i = 0; i < N; i++) // 打印排序后的数据
    {
        printf("%d ", a[i]);
    }
    return 0;
}

代码实现如下,非常成功!

请输入你要的数组元素个数:
10
71 67 29 70 0 31 11 46 47 31
0 11 29 31 31 46 47 67 70 71

OK本文到这里就结束了!希望看到这里的每个人都有所收获!祝你们学有所成,谢谢大家的支持!

  • 8
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木梓辛铭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值