算法系列
本节以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本文到这里就结束了!希望看到这里的每个人都有所收获!祝你们学有所成,谢谢大家的支持!