三条性质:
- 初始化:循环的第一次迭代前,循环不变式为真。
即初始化的数据结构与原始数据都是正确的。 - 保持:如果某次迭代前它为真,那么下次迭代之前它仍为真。
即每次迭代都保证正确的处理。 - 终止:在循环终止时,不变式为我们提供一个有用的性质,该性质有助于证明算法是正确的。
即研究在循环终止时发生了什么,并对循环结果进行判断。
看完这些挺懵的,大概理解是一种归纳总结的概念,但回到具体的算法中。又似乎不太知道怎么去理解和做了。
- 循环不变式,在每个算法中,我们要不变什么?
- 理解后有什么意义?
具体算法示例:
- 冒泡法:
/**
* 冒泡法
1. 每一次循环将[0~i-1]为有序
2. 每次循环结束后[0~i]为有序
3. 当i=n时,[0~n]也变得有序
4. 每次循环结束后,有序的+1,无序的-1
抓住以上几个点,可以很好地捋清代码逻辑:
1. 外循环:
i可以理解即将变得有序的个数,那么0~i-1之前的数就都是有序的。
那么在处理内循环的时候,最终冒的泡应该在i这个位置,就可以理解到内循环应该把i作为一个最后的交换位置了。并且内循环的其实位置,不需要包含已经排序好的数;
据此就很好的写出内循环逻辑
for(int j = nums.length-1;j>i;j--){
swap(nums,i,j)
}
*/
- 选择法:
/**
* 选择法法
1. 每一次循环将[0~i-1]为有序
2. 每次循环结束后[0~i]为有序
3. 当i=n时,[0~n]也变得有序
4. 每次循环结束后,有序的+1,无序的-1
其实可以看到几个点非常的类型。并且选择法使用的内循环,由于最终的交换是在循环外控制的,所以不需要考虑内循环的终点应该到达哪里。只需要考虑内循环的选择区间即可。由于已知0~i-1是有序的数据,内循环的选择区间则可以不需要包含它们。这样就明确了内循环区间了
*/
总结:循环不变式到底有什么用呢?
可以分析算法的正确性(这个我还有待提升)
可以捋清代码写的思路:
1. 上面两个例子应该就可以比较明白了。特别是冒泡法,内循环的选择区间是哪个,以及终点是哪个?虽然读代码也能理解,但其实过后容易忘。理解循环不变式后,就会特别有助于捋清相关的思路。
今天收获就算还行吧