题目
冒泡排序(bubblesort)算法是一种流行的排序算法,它重复地交换相邻的两个反序元素。
A'[1]<=A'[2]<=...<=A'[n]
其中n=length[A]。为了证明BUBBLESORT的确能实现排序的效果,还需要证明什么?
b)对于第3~5行中的for循环,给出一个准确的循环不变式,并证明该循环不变式是成立 的。在证明中采用本章给出的循环不变式证明结构。
c)利用在b)中证明的循环不变式的终止条件,为第2~5行中的for循环给出一个循环不变 式,它可以用来证明a)中的不等式。你的证明应采用本章中给出的循环不变式的证明结 构。
d)冒泡排序算法的最坏情况运行时间是什么?比较它与插入排序的运行时间。
- BUBBLE-SORT(A)
- for i <- 1 to length(A)
- do for j <- length(A) downto i+1
- do if A[j] < A[j-1]
- then exchange A[j] <-> A[j-1]
A'[1]<=A'[2]<=...<=A'[n]
其中n=length[A]。为了证明BUBBLESORT的确能实现排序的效果,还需要证明什么?
b)对于第3~5行中的for循环,给出一个准确的循环不变式,并证明该循环不变式是成立 的。在证明中采用本章给出的循环不变式证明结构。
c)利用在b)中证明的循环不变式的终止条件,为第2~5行中的for循环给出一个循环不变 式,它可以用来证明a)中的不等式。你的证明应采用本章中给出的循环不变式的证明结 构。
d)冒泡排序算法的最坏情况运行时间是什么?比较它与插入排序的运行时间。
分析
问题a
还需要证明A'是A的一个排列。
问题b
循环不变式:在循环的每次迭代开始前,A[j]为子数组A[j...n]中的最小元素,并且 A[j...n]是原A[j...n]的一个排列。
初始化:在循环的第一次迭代开始前,j=n,A[j...n]=A[n]只有一个元素,显然A[n]是 A[n]中最小的元素,并且A[n]就是A[n]的一个排列。循环不变式成立。
保持:假设在循环的某次迭代开始前,循环不变式成立。此时j=k,根据循环不变式, A[j]=A[k]为A[j...n]=A[k...n]中的最小元素,并且A[k...n]是原A[k...n]的一个排列。 执行此次迭代,设A[k]=p,A[k-1]=q,如果第四行的判断为真,那么A[k] < A[k-1],因为A[k]是A[k...n]中 的最小值,而A[k]比A[k-1]小,所以p是A[k-1...n]中的最小值;当A[k]与A[k-1]交 换后,交换后A[k-1...n]从[q,p,A[k+1...n]]变为 [p,q,A[k+1...n]],所以A[k-1]为A[k-1...n]中的最小值;又因为A[k...n]是原A[k...n]的一个排列,所以A[k+1...n]包含了除 p外的所有原A[k...n]的所有元素,而A[k-1...n]包含了p,q和A[k...n]中除p外的所有 元素,所以交换后A[k-1...n]包含了原A[k-1...n]的所有 元素,是原A[k-1]的一个排列。
如果第4行的判断为假,说明A[k-1]小于等于A[k...n]中的任何元素,所以A[k-1]为 A[k-1...n]中最小的元素;又因为A[k...n]是原A[k...n]的一个排列,即A[k...n]包含 原A[k..n]的所有元素,而A[k-1...n]包 含A[k-1]和A[k...n]中的所有元素,是原A[k-1...n]的一个排列
当下一次迭代开始前,此时j=k-1,由上面的分析可知,A[k-1]为A[k-1...n]的最小值, 并且A[k-1...n]为原A[k-1...n]的一个排列。
终止:当迭代终止时,此时j=i,从保持的分析可知,A[i]是A[i...n]的最小值,并且 A[i...n]是原A[i...n]的一个排列。
初始化:在循环的第一次迭代开始前,j=n,A[j...n]=A[n]只有一个元素,显然A[n]是 A[n]中最小的元素,并且A[n]就是A[n]的一个排列。循环不变式成立。
保持:假设在循环的某次迭代开始前,循环不变式成立。此时j=k,根据循环不变式, A[j]=A[k]为A[j...n]=A[k...n]中的最小元素,并且A[k...n]是原A[k...n]的一个排列。 执行此次迭代,设A[k]=p,A[k-1]=q,如果第四行的判断为真,那么A[k] < A[k-1],因为A[k]是A[k...n]中 的最小值,而A[k]比A[k-1]小,所以p是A[k-1...n]中的最小值;当A[k]与A[k-1]交 换后,交换后A[k-1...n]从[q,p,A[k+1...n]]变为 [p,q,A[k+1...n]],所以A[k-1]为A[k-1...n]中的最小值;又因为A[k...n]是原A[k...n]的一个排列,所以A[k+1...n]包含了除 p外的所有原A[k...n]的所有元素,而A[k-1...n]包含了p,q和A[k...n]中除p外的所有 元素,所以交换后A[k-1...n]包含了原A[k-1...n]的所有 元素,是原A[k-1]的一个排列。
如果第4行的判断为假,说明A[k-1]小于等于A[k...n]中的任何元素,所以A[k-1]为 A[k-1...n]中最小的元素;又因为A[k...n]是原A[k...n]的一个排列,即A[k...n]包含 原A[k..n]的所有元素,而A[k-1...n]包 含A[k-1]和A[k...n]中的所有元素,是原A[k-1...n]的一个排列
当下一次迭代开始前,此时j=k-1,由上面的分析可知,A[k-1]为A[k-1...n]的最小值, 并且A[k-1...n]为原A[k-1...n]的一个排列。
终止:当迭代终止时,此时j=i,从保持的分析可知,A[i]是A[i...n]的最小值,并且 A[i...n]是原A[i...n]的一个排列。
问题c
循环不变式:在循环的每次迭代开始前,子数组A[1...i-1]保存着A[1...n]中最小的 i-1个数,并且是已经排序好的。
初始化:在循环的第一次迭代开始前,i=1,A[1...0]不包含任何元 素,可以规定空数组比任何非空数组中的元素都小,循环不变式成立;
保持:假设在循环的某次迭代开始前,循环不变式成立。此时i=k, A[1...k-1]包含已排序的A[1...n]中最小的k-1个元素。执行此次迭代,由问题b的终止 条件得知,A[i]=A[k]为A[k...n]中的最小值,有因为A[k]大于等于A[1...k-1]中的任 一元素,所以A[1...k]为已排序的A[1...n]中最小的k个元素,那么在下次迭代开始前, 此时i=k+1,循环不变式也成立;
终止:当循环终止时,i=n+1,由循环不变式的值,A[1...n]是 A[1...n]中已排序的最小的n个数,而A[1...n]包含了原来A[1...n]中的所有元素,因 此整个数组已经排序好,这意味着算法正确。
问题d
显然冒泡排序的运行时间由外层和内层循环次数决定,内层每次运行n-i次,所以冒泡 排序总的运行次数为
=
,与插 入排序相同。
伪代码
# BUBBLE-SORT(A)
# for i <- 1 to length(A)
# do for j <- length(A) downto i+1
# do if A[j] < A[j-1]
# then exchange A[j] <-> A[j-1]
# for i <- 1 to length(A)
# do for j <- length(A) downto i+1
# do if A[j] < A[j-1]
# then exchange A[j] <-> A[j-1]
Python代码实现
def bubble_sort(a, p, r):
for i in range (p, r+1):
for j in range(r, i, -1):
if a[j] < a[j-1]:
temp = a[j]
a[j] = a[j-1]
a[j-1] = temp