排序与查找

二、插入排序

排序算法如下:

//例 11.1 插入排序
#include<stdio.h>

#define LEN 5
int a[LEN]={10,5,2,4,7};

void insertion_sort(void){
	int i,j,key;
	for(j=1;j<len;j++){
		key=a[j];
		i=j-1;
		while(i>=0&&a[i]>key){
			a[i+1]=a[i];
			i--;
		}
		a[i+1]=key;
	}
}

int main(void){
	insertion_sort();
	return 0;
}

如何严格证明这个算法是正确的?换句话说,只要反复执行该算法的for循环体,执行LEN-1次,就一定能把数组a排好序,而不管数组a的原始数据是什么,如何证明这一点?我们可以借助Loop Invariant的概念和数学归纳法来理解循环结构的算法,假如某个判断条件满足以下三条准则,它就称为loop invariant:

  1. 第一次执行循环体之前该判断条件为真
  2. 如果”第N-1次循环之后(或者说第N次循环之前)该判断条件为真“这个前提可以成立,那么就有办法证明第N次循环之后该判断条件为真
  3. 如果在所有循环结束后该判断条件为真,那么就有办法证明该算法正确地解决了问题

只要我们找到这个Loop Invariant,就可以证明一个循环结构的算法是正确的。上述插入排序算法的Loop Invariant是这样的判断条件:第j次循环之前,子序列a[0,…,j-1]是排好序的。接下来我们验证下Loop Invariant的三条准则:

  1. 第一次执行循环之前,j=1,子序列a[0,…,j-1]只有一个元素a[0],只有一个元素的序列显然是排好序的
  2. 第j次循环之前,如果”子序列a[0,…,j-1]是排好序的“这个前提成立,按照该算法的步骤,把a[j-1]、a[j-2]、a[j-3]等等比key大的元素都依次往后移一个,直到找到合适的位置给key插入,就能证明循环结束时子序列a[0,…,j]是排好序的。
  3. 当循环结束时,j=LEN,如果”子序列a[0,…,j-1]是排好序的“这个前提成立,那就是说a[0,…,LEN-1]是排好序的,也就是说整个数组a的LEN个元素都是排好序的

可见,有了这三条,就可以用数学归纳法证明这个循环是正确的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值