它是一种基础的交换排序。
把相邻的元素两两比较,当一个元素大于右侧相邻元素时,交换他们的位置:当一个元素小于或等于右侧相邻元素时,位置不变。
数列如下排序:
{5,8,6,3,9,2,1,7}
{5,8,6,3,9,2,1,7}
{5,6,8,3,9,2,1,7}
{5,6,3,8,9,2,1,7}
{5,6,3,8,9,2,1,7}
{5,6,3,8,2,9,1,7}
{5,6,3,8,2,1,9,7}
{5,6,3,8,2,1,7,9}
{5,6,3,8,2,1,7,9}
{5,3,6,8,2,1,7,9}
{5,3,6,8,2,1,7,9}
{5,3,6,2,8,1,7,9}
{5,3,6,2,1,8,7,9}
{5,3,6,2,1,7,8,9}
{5,3,6,2,1,7,8,9}
{3,5,2,1,6,7,8,9}
{3,2,1,5,6,7,8,9}
{2,1,3,5,6,7,8,9}
{1,2,3,5,6,7,8,9}
{1,2,3,5,6,7,8,9}
冒泡排序是一种稳定排序,值相等的元素并不会打乱原本的顺序。由于改排序排序算法每一轮都要遍历所有元素,总共遍历(元素数量-1)轮,所以平均时间复杂度是O(n^2)
/// d ##class(PHA.YX.Arithmetic).BubbleSortFirst()
ClassMethod BubbleSortFirst()
{
s array = $lb(5,8,6,3,9,2,1,7)
f i = 1 : 1 : $ll(array) - 1 d
.f j = 1 : 1 : $ll(array) - i d
..s tmp = 0
..i ($li(array, j) > $li(array, j + 1)) d
...s tmp = $li(array, j)
...s $li(array, j) = $li(array, j + 1)
...s $li(array, j + 1) = tmp
zw array
}
DHC-APP> d ##class(PHA.YX.Arithmetic).BubbleSortFirst()
array=$lb(1,2,3,5,6,7,8,9)
当数列 {5,8,6,3,9,2,1,7} 排序到第六轮,第七轮时
{1,2,3,5,6,7,8,9}
{1,2,3,5,6,7,8,9}
经过六轮排序后,整个数列已然是有序的了。可是算法还是进行到了第七轮。
在这种情况下,如果能判断出数列已经有序,那么剩下的几轮排序就不比执行。
我们增加quitFlag来标记退出循环 sortFlag标记来标记是否有交换的数据。
代码如下:
/// d ##class(PHA.YX.Arithmetic).BubbleSortSecond()
ClassMethod BubbleSortSecond()
{
s array = $lb(5,8,6,3,9,2,1,7)
/* 循环退出标志 */
s quitFlag = 1
f i = 1 : 1 : $ll(array) -1 q:quitFlag=0 d
.s sortFlag = 1 /* 有序标志,每一轮的初始值都是true */
.f j = 1 : 1 : $ll(array) - i d
..s tmp = 0
..i ($li(array, j) > $li(array, j + 1)) d
...s tmp = $li(array, j)
...s $li(array, j) = $li(array, j + 1)
...s $li(array, j + 1) = tmp
...s sortFlag = 0 /* 因为有元素进行交换,所以不是有序的,标记变为false */
.i sortFlag = 1 s quitFlag = 0
.zw array
}
我们把数组 改成s array = $lb(2,1,3,4,5,6,7,8)
并增加 一些w i j sortFlag
看他们的值
/// d ##class(PHA.YX.Arithmetic).BubbleSortSecond()
ClassMethod BubbleSortSecond()
{
s array = $lb(2,1,3,4,5,6,7,8)
s quitFlag = 1
f i = 1 : 1 : $ll(array) -1 q:quitFlag=0 d
.w "i:"_i,!
.s sortFlag = 1
.f j = 1 : 1 : $ll(array) - i d
..w "j:"_j,!
..s tmp = 0
..i ($li(array, j) > $li(array, j + 1)) d
...s tmp = $li(array, j)
...s $li(array, j) = $li(array, j + 1)
...s $li(array, j + 1) = tmp
...s sortFlag = 0
.i sortFlag = 1 s quitFlag = 0
.w "sortFlag:"_sortFlag,!
.zw array
}
运行结果发现:2轮就停止排序了,因为数组已经成为有序数列。
DHC-APP>d ##class(PHA.YX.Arithmetic).BubbleSortSecond()
i:1
j:1
j:2
j:3
j:4
j:5
j:6
j:7
sortFlag:0
array=$lb(1,2,3,4,5,6,7,8)
i:2
j:1
j:2
j:3
j:4
j:5
j:6
sortFlag:1
array=$lb(1,2,3,4,5,6,7,8)
为了说明这个问题,我们以一个新的数列为例:s array = $lb(3,4,2,1,5,6,7,8)
这个数列的特点是前半部分(3,4,2,1)无序,后半部分的元素(5,6,7,8)按升序排列。
第一轮:
(3,4,2,1,5,6,7,8)
(3,2,4,1,5,6,7,8)
(3,2,1,4,5,6,7,8)
后面一次比较发现依然有序,但是还是进行了N次比较。后面的多次元素比较是没有意义的。
我们发现最后一次交换之前的是无序边界,之后是有序边界。所以我们增加lastExchangeIndex来记录最后的交换位置
/// d ##class(PHA.YX.Arithmetic).BubbleSortThird()
ClassMethod BubbleSortThird()
{
s array = $lb(3,4,2,1,5,6,7,8)
s quitFlag = 1
/* 记录最后一次交换的位置 */
s lastExchangeIndex = 0
/* 无序数列的边界,每次比较只需要比到这里为止 */
s sortBorder = $ll(array) -1
f i = 1 : 1 : $ll(array) -1 q:quitFlag=0 d
.w "i:"_i,!
.s sortFlag = 1
.f j = 1 : 1 : sortBorder d
..w "j:"_j,!
..s tmp = 0
..i ($li(array, j) > $li(array, j + 1)) d
...s tmp = $li(array, j)
...s $li(array, j) = $li(array, j + 1)
...s $li(array, j + 1) = tmp
...s sortFlag = 0
...s lastExchangeIndex = j /* 更新为最后一次交换元素的位置 */
...w "lastExchangeIndex "_lastExchangeIndex,!
.s sortBorder = lastExchangeIndex
.i sortFlag = 1 s quitFlag = 0
.zw array
}
运行我们看一下结果
DHC-APP>d ##class(PHA.YX.Arithmetic).BubbleSortThird()
i:1
j:1
j:2
lastExchangeIndex 2
j:3
lastExchangeIndex 3
j:4
j:5
j:6
j:7
array=$lb(3,2,1,4,5,6,7,8)
i:2
j:1
lastExchangeIndex 1
j:2
lastExchangeIndex 2
j:3
array=$lb(2,1,3,4,5,6,7,8)
i:3
j:1
lastExchangeIndex 1
j:2
array=$lb(1,2,3,4,5,6,7,8)
i:4
j:1
array=$lb(1,2,3,4,5,6,7,8)
在第三版代码中sortBorder就是无序数列的边界,每一轮排序中,处于sortBorder之后的元素就不需要在进行比较了。肯定是有序的。