冒泡排序法作为C语言入门所接触的第一个排序类算法,由于它嵌套的for循环结构,使人理解起来较为困难。
下面我们将冒泡排序法拆分开来,从准备区域,核心交换区域,打印区域三方面进行讨论,希望能够帮助读者更好地理解。
#include<stdio.h>
int main()
{
//准备区域
int arr[10] = { 3,6,1,2,3,8,54,123,5,9 };
int i = 0; int j = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
//核心交换区域
for (i = 0; i < sz - 1; i++)
{
for (j = 0; j < sz - i - 1; j++)
{
if (arr[j] < arr[j + 1])
{
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
//打印区域
}
for (i = 0; i < sz ; i++)
{
printf("%d\n", arr[i]);
}
return 0;
}
准备区域:
1.在初期接触计算机时,大部分人并没有算法思维的储存。因此对于初学C语言的人来说,准备区域不需要像自己老师一样,在编写其他区域之前就把所有本程序用到的变量全部定义。用到哪个就回去定义就好啦。(老师毕竟还是很专业的,而且还经过细致的备课,这些程序他们会非常熟悉)
2.在编程过程中如果发现自己需要某些变量,建议大部分还是回到准备区域集中定义,不要再非准备区域进行变量的定义,养成良好的代码风格。
3.本代码基于整型数组arr[10]={3,6,1,2,3,8,54,123,5,9}为基础进行演示。
核心交换区域:
1.本区域用到了两个for循环,分别以i,j作为循环变量。
2.外层循环控制冒泡,每一次的外层循环都会伴随着一个位于正确位置的数据。
内层循环控制排序的具体过程。
3.两层循环分层+if判断区域解析:
外层循环:
①外层循环主要控制的是循环的整体执行次数
②对于 sz-1 可以理解为:每次外层循环结束,会浮出一个元素,该元素不需要再继续参与循环,他的位置已经是正确地址。如果所有元素都排在在自己的正确位置上,该数组即完成冒泡排序过程。试想:
此时一共四个元素,外层循环结束了两次,自然有两个元素在他的正确位置上;与此同时也有两个元素仍未排好顺序;那显而易见,这两个相邻的、未排序的元素仅通过一次排序即可获得这两个元素间的正确顺序,也可以获得整体的正确顺序。
③所以,对于 sz-1次排序可以认为:
第sz次排序是无意义排序(有sz-1个元素已经确定了正确位置,第sz次排序仅是自己检查自己有没有排好顺序。且仅存在一个对象,怎么检查顺序都是正确的);
而第sz-1次排序是将最后两个未排序的数字进行排序的操作,通过这次操作从而获得整体序列的正确顺序。
内层循环:
①对于冒泡排序,不论是从大到小还是从小到大排序,每次外层循环的结束,都会在右侧出现的位于正确位置的数据。
②内层循环的主要难点在于循环次数:sz-1-i(外层循环的循环变量)
对于内层循环,主要的目的便是依次检索数据,根据程序设计进行位置的调换。而正如我们在外层循环中提到,每次外层循环的结束都会伴随着一个位于正确位置的数据。因此每产生一个正确位置的数据,下一次的内层循环就可以不再考虑已经浮出水面的数据了(正确位置的数据)。
③对于第一次进行排序,没有一个数据通过检查判断其在正确位置上,所以需要和除了第一个元素本身之外的所有数据进行比较,比较进行sz-1次。
对于第二次排序,有一个数据已经到了正确的位置,所以下一次的排序不在把他列入考虑范围内,即sz-1-1,此时i恰好为1。
如此类推,不难发现内层循环需要进行sz-1-i次
打印区域:
利用for循环进行数组遍历,同时将遍历的数组置于printf函数中进行打印。
summary:
经过两次循环次数的分析,配合下图进行理解