插入排序

</pre><pre name="code" class="html">

对于插入排序,我们将其伪代码过程命名为INSERTION-SORT,其中的参数是一个数组A[1..n],包含长度为n的要排序的一个序列。(在代码中,A中元素的数目n用A.length来表示。)该算法原址排序输入的数:算法在数组A中重排这些数,在任何时候,最多只有其中的常数个数字存储在数组外面。在过程INSERTION-SORT结束时,输入数组A包含排序好的输出序列。
INSERTION-SORT(A)
1 for j = 2 to A.length
2  key = A[j]
3  // Insert A[j] into the sorted sequence A[1..j - 1].
4  i = j - 1
5  while i > 0 and A[i] > key
6    A[i+1] = A[i]
7    i = i - 1
8  A[i + 1] = key

循环不变式与插入排序的正确性


 

图2-2表明对A=〈5,2,4,6,1,3〉该算法如何工作。下标j指出正被插入到手中的“当前牌”。在for循环(循环变量为j)的每次迭代的开始,包含元素A[1..j-1]的子数组构成了当前排序好的左手中的牌,剩余的子数组A[j+1..n]对应于仍在桌子上的牌堆。事实上,元素A[1..j-1]就是原来在位置1到j-1的元素,但现在已按序排列。我们把A[1..j-1]的这些性质形式地表示为一个循环不变式:

在第1~8行的for循环的每次迭代开始时,子数组A[1..j-1]由原来在A[1..j-1]中的元素组成,但已按序排列。

图2-2 在数组A=〈5,2,4,6,1,3〉上INSERTION-SORT的操作。数组下标出现在长方形的上方,数组位置中存储的值出现在长方形中。(a)~(e)第1~8行for循环的迭代。每次迭代中,黑色的长方形保存取自A[j]的关键字,在第5行的测试中将它与其左边的加阴影的长方形中的值进行比较。加阴影的箭头指出数组值在第6行向右移动一个位置,黑色的箭头指出在第8行关键字被移到的地方。(f)最终排序好的数组

/**
	 * 插入排序
	 * 对指定数组进行排序
	 * @param a  要排序的数组
	 * @return  返回排序好的数组
	 */
	public static int[] insertSort(int[] a){
		for(int j=1;j<a.length;j++){
			int key = a[j];
			int i = j-1;
			while(i>=0&&a[i]>key){
				a[i+1] = a[i];   //将大的向后推移一个
				i = i-1;
			}
			a[i+1] = key;  //插入将要插入的数
		}
		return a;
	}



循环不变式主要用来帮助我们理解算法的正确性。关于循环不变式,我们必须证明三条性质:

初始化:循环的第一次迭代之前,它为真。

保持:如果循环的某次迭代之前它为真,那么下次迭代之前它仍为真。

终止:在循环终止时,不变式为我们提供一个有用的性质,该性质有助于证明算法是正确的。

当前两条性质成立时,在循环的每次迭代之前循环不变式为真。(当然,为了证明循环不变式在每次迭代之前保持为真,我们完全可以使用不同于循环不变式本身的其他已证实的事实。)注意,这类似于数学归纳法,其中为了证明某条性质成立,需要证明一个基本情况和一个归纳步。这里,证明第一次迭代之前不变式成立对应于基本情况,证明从一次迭代到下一次迭代不变式成立对应于归纳步。

第三条性质也许是最重要的,因为我们将使用循环不变式来证明正确性。通常,我们和导致循环终止的条件一起使用循环不变式。终止性不同于我们通常使用数学归纳法的做法,在归纳法中,归纳步是无限地使用的,这里当循环终止时,停止“归纳”。

让我们看看对于插入排序,如何证明这些性质成立。

初始化:首先证明在第一次循环迭代之前(当j=2时),循环不变式成立。所以子数组A[1..j-1]仅由单个元素A[1]组成,实际上就是A[1]中原来的元素。而且该子数组是排序好的(当然很平凡)。这表明第一次循环迭代之前循环不变式成立。

保持:其次处理第二条性质:证明每次迭代保持循环不变式。非形式化地,for循环体的第4~7行将A[j-1]、A[j-2]、A[j-3]等向右移动一个位置,直到找到A[j]的适当位置,第8行将A[j]的值插入该位置。这时子数组A[1..j]由原来在A[1..j]中的元素组成,但已按序排列。那么对for循环的下一次迭代增加j将保持循环不变式。

第二条性质的一种更形式化的处理要求我们对第5~7行的while循环给出并证明一个循环不变式。然而,这里我们不愿陷入形式主义的困境,而是依赖以上非形式化的分析来证明第二条性质对外层循环成立。

终止:最后研究在循环终止时发生了什么。导致for循环终止的条件是j>A.length=n。因为每次循环迭代j增加1,那么必有j=n+1。在循环不变式的表述中将j用n+1代替,我们有:子数组A[1..n]由原来在A[1..n]中的元素组成,但已按序排列。注意到,子数组A[1..n]就是整个数组,我们推断出整个数组已排序。因此算法正确。






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值