冒泡法的原理是在一个关键字是数值的记录序列中,关键字大的记录(元素)向上冒泡到恰当位置,因此每一趟排序中,选择数值最大的元素,到当前顶端位置。当在某一趟排序中,没有元素间的交换,则冒泡排序停止。实际上,大的元素向上冒泡(bubble),则存在小的元素向下沉积(sink)。下面是高德纳在《计算机程序设计的艺术》中冒泡排序的算法思想。
1.算法B(冒泡排序)
重新排列记录R1,...,RN,在排序完成后所有记录的关键字有序,K1<=K2<=...<=KN。
B1.[初始化BOUND] 置BOUND<-N。(BOUND是未在排序最终位置元素的当前最高边界。)
B2.[loop on j,数组下标j的循环] 置t<-0。在j=1,2,...,BOUND-1时,进行B3步骤,然后j=BOUND时,进行B4步骤。(若BOUND=1,则仅进行B4步骤。)。
/* t是标识,是否再进行下一趟排序(a pass)。若所有元素都没有向上冒泡,因此排序完成。*/
B3.[比较或交换记录Rj与Rj+1] if Kj>Kj+1,交换Rj<->Rj+1,并且t<-j。
/*Rj+1,Kj+1表示第K+1个记录Rj+1与它的关键字Kj+1,可以认为j+1的+优先级高于右边的大写字符*/
B4.[记录间有任何交换吗?] if t=0,算法终止。否则,置BOUND<-t,算法返回到B2步骤。
/*表明B4步骤是一个循环,冒泡排序算法的主循环。*/
高德纳的算法表示方法,循环(B2.[loop on j])和循环中的语句常常在相邻的不同步骤中,循环中的语句我们称为循环语句块(loop block),例如,loop on j中的B3步骤。若循环语句块中有另一个路径出口,则常常转向一个新的步骤(step)。而且程序的关键执行路径上的主循环,常常在循环最后出现,而不是主循环开始时,例如B4步骤是冒泡法的主循环,并且返回到前面的某一个步骤,B4返回到B2步骤。有时候并不容易理解。
算法或者程序的阅读理解,在了解程序的结构时,程序的控制流(control flow),还要了解布尔表达式条件的意义。循环条件称为test或者condition,loop on j的循环边界是j=1,2,...,BOUND-1,进行B3步骤的两个元素的比较(扫描或查找)或者交换(向上冒泡)的操作,因此在一个记录的关键字比记录序列中后面的关键字都小时,并不停止循环,而是找到这个记录序列中的最大关键字。当j==BOUND时,表示此一趟排序结束。找到一个最大值,下标保存在t中,并且存放在第BOUND个位置上。这是冒泡法一趟排序的一个完整过程。然而冒泡排序并没有结束,因此应再进行一趟排序,找到一个次大值,存放在BOUND=N-1位置上。是否进行下一趟排序,应该看t是否保持0,若t不为0,表示有元素的交换,排序没有完成,BOUND=t,下标t之后的元素在最终的正确位置上,否则将出现元素间的交换。因此,冒泡法的多次一趟排序,组成一个最值序列,最后得到一个关键字的有序数组。
算法的数据分析。N=16
703* |-> 908向上冒泡 ... 908
765 | 703* 897向上冒泡 897
677 | 765 703* 765
612 | 677 765 703
509 | 612 677 677
154 | 509 612 653
426 | 154 509 612
653 | 426 154 512
275 | 653 426 509
897 | 275 653 503
170 | 897 275 426
908 -| 170 512向上冒泡 275
061 |-> 512向上冒泡 170 170
512-| 061 503向上冒泡 154
087 |-> 503向上冒泡 061 087
503 -| 087 087扫描或查找 061
pass 1 2 ... 9
t=15 t=14 t=0