冒泡排序的双重循环理解 冒泡排序的双重循环理解

原文链接: https://blog.csdn.net/publicstaticfinal/article/details/90155040

冒泡排序的双重循环理解

主要说一下冒泡排序的一些关键地方的个人理解,比如算法思想,两个循环的作用意义,中间循环变量范围的确定等。

原理:比较两个相邻的元素,将值大的元素交换至右端。

思路:依次比较相邻的两个数,将小数放在前面,大数放在后面。即在第一趟:首先比较第1个和第2个数,将小数放前,大数放后。然后比较第2个数和第3个数,将小数放前,大数放后,如此继续,直至比较最后两个数,将小数放前,大数放后。重复第一趟步骤,直至全部排序完成。
第一趟比较完成后,最后一个数一定是数组中最大的一个数,所以第二趟比较的时候最后一个数不参与比较;

第二趟比较完成后,倒数第二个数也一定是数组中第二大的数,所以第三趟比较的时候最后两个数不参与比较;

依次类推,每一趟比较次数-1;
……

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

举例说明:要排序数组:int[] arr={6,3,8,2,9,1};

第一趟排序:

第一次排序:6和3比较,6大于3,交换位置: 3 6 8 2 9 1

第二次排序:6和8比较,6小于8,不交换位置:3 6 8 2 9 1

第三次排序:8和2比较,8大于2,交换位置: 3 6 2 8 9 1

第四次排序:8和9比较,8小于9,不交换位置:3 6 2 8 9 1

第五次排序:9和1比较:9大于1,交换位置: 3 6 2 8 1 9

第一趟总共进行了5次比较, 排序结果: 3 6 2 8 1 9


第二趟排序:

第一次排序:3和6比较,3小于6,不交换位置:3 6 2 8 1 9

第二次排序:6和2比较,6大于2,交换位置: 3 2 6 8 1 9

第三次排序:6和8比较,6大于8,不交换位置:3 2 6 8 1 9

第四次排序:8和1比较,8大于1,交换位置: 3 2 6 1 8 9

第二趟总共进行了4次比较, 排序结果: 3 2 6 1 8 9


第三趟排序:

第一次排序:3和2比较,3大于2,交换位置: 2 3 6 1 8 9

第二次排序:3和6比较,3小于6,不交换位置:2 3 6 1 8 9

第三次排序:6和1比较,6大于1,交换位置: 2 3 1 6 8 9

第二趟总共进行了3次比较, 排序结果: 2 3 1 6 8 9


第四趟排序:

第一次排序:2和3比较,2小于3,不交换位置:2 3 1 6 8 9

第二次排序:3和1比较,3大于1,交换位置: 2 1 3 6 8 9

第二趟总共进行了2次比较, 排序结果: 2 1 3 6 8 9


第五趟排序:

第一次排序:2和1比较,2大于1,交换位置: 1 2 3 6 8 9

第二趟总共进行了1次比较, 排序结果: 1 2 3 6 8 9


最终结果:1 2 3 6 8 9


由此可见:N个数字要排序完成,总共进行N-1趟排序,每i趟的排序次数为(N-i)次,所以可以用双重循环语句,外层控制循环多少趟,内层控制每一趟的循环次数,即

for(i=0;i<n-1;i++)

for(j=0;j<n-i-1;j++) //n是数组长度,即元素个数

外层循环的作用是:

提取出目前未排序数组中最大的数,放置于已排数据的左边。也就是说我们第一次外层循环,是把最大数的位置交换到数组的最右边,第二次外层循环是把次大数交换到数组的次右边,依次类推。

内层循环的作用是:

实现我们想要的大数下沉的过程。每次比较的是相邻两个数据,所以一个数组的长度为n,我们只需要做 n-1 次相邻的比较,就可以实现大数下沉,而 之前循环已经沉淀的大数并不需要再进行 排序了。

很清楚的看到N个数字要排序完成,总共进行N-1趟排序

为什么外层循环判断条件是i<n-1呢?

n 个数字总共需要 n-1 趟排序,外层循环 i 从0到 n-1 正好是 n-1 次。

为什么内层循环判断条件是j<n-i-1呢?

这要从冒泡排序原理说起:冒泡排序每循环排序一次,就把最大的一个数排在了最右边(默认升序排),每一次排序都是在上一次排序的基础上再排序,(比如)第2次排序之后,i已经成2了,第三次排序是要在第二次的基础上在进行排序,而第二次排序后就已经把两个最大的数已经放到最后了,所以第三次排序就不需要在去比他俩,就得把这个“2“减掉,只需要循环n-i次(此时的i是2);为什么-i之后还要-1呢? 这是因为在内层循环的判断中是把当前值和后面一个值做比较的。如果不减1,则当循环到最后一个值的时候,再取下一个值就取不到,就需要额外的操作,或者抛出数组下标越界的异常。

其实内层的 j<n-i-1 这个范围的确定 让人纠结,它主要有两种理解方式

1 就是标准解释 上述的防止数组下标越界,比如n[] = {5, 22, 7, 42, 23},个数n=5,i现为2,n-i=3,i为2即进行第3趟,两个数已经确定好,只需要比较前三个数了,而这只需要比较2次,即n-i(为2)-1=2。如果不减一,这里就是n-i(为2)= 3比三次,这显然是错的。就是正常是:

if n(0)>n(1)
if n(1)>(2)  这是正确的

  
  
  • 1
  • 2

不正确时,5-2=3 j从0到3 得比3次:

if n(0)>n(1)
if n(1)>(2) 
if n(2)>(3) 这就比错了  这都把 确定好的倒数第二大的数再给比较,这就是错了。就成乐下表越界了。

  
  
  • 1
  • 2
  • 3

2 每趟的比较中,都是n-1次,每趟中都是比总共这次要比的数的个数减一次,再加上要把i这已经确定的数的个数减去,即就是 j-i-1。实际上这也是n-i,n把来的i减去,剩下的待排序的数共有多少个,他们的个数再减去一就是他们这些剩下的数需要比较的次数了,这个跟网上说的数组是从下标0开始,没啥关系,下标从0或1开始,影响的是内层循环的比较,是0,就直接引用,是1,就得n[i-1]。至于说的这个从0开始的说法,则它根本上也是想说防止下标越界。

至于算法优化什么的,暂时不考虑,这里只简单说明了算法中几个关键的点。
个人学习感悟,如有错误,还请指正。

附一些讲冒泡比较好的说的文章:
https://blog.csdn.net/kelinfeng16/article/details/84034386
https://www.cnblogs.com/shen-hua/p/5422676.html

猜你喜欢

转载自blog.csdn.net/qq_41933149/article/details/102252641