插入排序
输入: n个数的一个序列
{
a
1
,
a
2
,
⋯
 
,
a
n
}
\{a_1, a_2, \cdots, a_n\}
{a1,a2,⋯,an}。
输出: 输入序列的一个排序
{
a
1
′
,
a
2
′
,
⋯
 
,
a
n
′
}
\{a^\prime_1, a^\prime_2, \cdots, a^\prime_n\}
{a1′,a2′,⋯,an′}, 满足
a
1
′
≤
a
2
′
≤
⋯
≤
a
n
′
a^\prime_1 \le a^\prime_2 \le \cdots \le a^\prime_n
a1′≤a2′≤⋯≤an′。
插入排序原址排序输入的数,算法在数组 A A A中重排这些数,在任何时候,最多只有其中的常数个数字存储在数组外面。
- Insertion-Sort(A) 伪代码
for j = 2 to A.length
key = A[j]
i = j - 1
while(i > 0 and A [i] > key)
A[i + 1] = A[i]
i = i - 1
A[i + 1] = key
# -*- coding:utf-8 -*-
# 插入排序(降序)
# input: {a1, a2, a3, a4, ..., an}
# output: {a1 >= a2 >= a3 >= a4 >= ... >= an}
import random
def InsertionSort(array):
for i in range(len(array) -2 , -1 , -1):
key = array[i]
j = i + 1
while j < len(array) and array[j] > key:
array[j - 1] = array[j]
j = j + 1
array[j - 1] = key
if __name__ == "__main__":
array = random.sample([x for x in range(100)], 20)
print("before: ", array)
InsertionSort(array)
print("end: ", array)
循环不变式定义
- 初始化 : 循环的第一次迭代之前,它为真。
- 保持 : 如果循环的某次迭代前它为真,那么下次迭代前它仍然为真。
- 终止 :在循环终止时,不变式为我们提供一个有用的性质,该性质有助于证明算法是正确的。
插入排序的循环不变式
- 初始化 : 首先证明在第一次循环之前(当 j = 2 j=2 j=2时),循环不变式成立。所以子数组 A [ 1.. j − 1 ] A[1 .. j-1] A[1..j−1]仅由单个元素 A [ i ] A[i] A[i]组成,实际上就是 A [ 1 ] A[1] A[1]中原来的元素。显然循环不变式在第一次迭代之前成立。
- 保持 : 非形式化的,for循环体的第5~7行将 A [ j − 1 ] , A [ j − 2 ] , A [ j − 3 ] A[j-1],A[j-2],A[j-3] A[j−1],A[j−2],A[j−3]等向右移动一个位置,直到找到 A [ j ] A[j] A[j]的适当位置,第7行将 A [ j ] A[j] A[j]的值插入指定的位置,此时子数组 A [ 1.. j ] A[1..j] A[1..j]由原来在 A [ 1.. j ] 的 元 素 组 成 , 但 是 已 经 排 序 , 那 么 对 f o r 循 环 的 下 一 次 迭 代 增 加 A[1..j]的元素组成,但是已经排序,那么对for循环的下一次迭代增加 A[1..j]的元素组成,但是已经排序,那么对for循环的下一次迭代增加j$将保持循环不变式。
- 终止 :导致for循环终止的条件是 j > A . l e n g t h = n j>A.length = n j>A.length=n。因为每循环迭代增加 j j j增加 1 1 1,那么必有 j = n + 1 j=n+1 j=n+1。在循环不变式中用 j j j代替 n + 1 n+1 n+1,我们有:子数组 A [ 1.. n ] A[1..n] A[1..n]由原来在A[1…n]中的元素组成,但已经排序。因此算法正确。
练习
2.1-1
# -*- coding:utf-8 -*-
def InsertionSort(array):
for i in range(1, len(array)):
key = array[i]
j = i - 1
while j >= 0 and array[j] > key:
array[j+1] = array[j]
j = j - 1
array[j + 1] = key
print(array)
if __name__ == "__main__":
array = [31, 41, 59, 26, 41, 58]
InsertionSort(array)
2.1-2
# -*- coding:utf-8 -*-
# 插入排序 (升序)
# input: {a1, a2, a3, a4, ..., an}
# output: {a1 <= a2 <= a3 <= a4 <= ... <= an}
import random
def InsertionSort(array):
for i in range(1, len(array)):
key = array[i]
j = i - 1
while j >= 0 and array[j] > key:
array[j+1] = array[j]
j = j - 1
array[j + 1] = key
if __name__ == "__main__":
array = random.sample([x for x in range(100)], 20)
print("before: ", array)
InsertionSort(array)
print("end: ", array)
2.1-3
输入 :
n
n
n个数的一个序列
A
=
{
a
1
,
a
2
,
⋯
 
,
a
n
}
A=\{a_1,a_2,\cdots,a_n\}
A={a1,a2,⋯,an}和一个值
v
v
v。
输出 :下标
i
i
i使得
v
=
A
[
i
]
v=A[i]
v=A[i]或者当
v
v
v不在
A
A
A中出现时,
v
v
v为特殊值
N
I
L
NIL
NIL。
伪代码:FIND-KEY(A, v)
for i = 1 to A.length
if A[i] == v
return i
return NIL
循环不变式 :对于每次循环迭代,子数组(已遍历的元素)中没有与 v v v相等的值。
初始化 :第一次循环之前,子数组没有元素,其中肯定没有与 v v v相等的值,循环不变式成立。
保持 :每次迭代都将比较 A [ i ] A[i] A[i]与 v v v的值,如果相等,循环终止;如果不等, A [ 1 ] … A [ i ] A[1] \dots A[i] A[1]…A[i]中没有与 v v v相等的值,循环不变式保持。
终止 :当 i > A . l e n g t h i > A.length i>A.length 时或者 A [ i ] = = v A[i] == v A[i]==v 时循环终止。显然对于子数组即下标小于 i i i的所有元素均没有与 v v v相等的值,算法正确。
2.1-4
A,B各存放了一个二进制n位整数的各位数值,现在通过二进制的加法对其进行计算,结果以二进制的形式把各位上的数值存放在C数组中。
# -*- coding:utf-8 -*-
def binarySum(aArray, bArray):
c = [0]* (len(aArray) + 1)
for i in range(len(aArray) - 1, -1, -1):
if((a[i] + b[i] + c[i + 1]) > 1):
c[i] = 1
c[i + 1] = c[i + 1] ^ a[i] ^ b[i]
return c
if __name__ == "__main__":
a = [1, 0, 1, 1, 0, 1, 0, 1, 1, 1]
b = [0, 1, 1, 1, 0, 0, 1, 1, 0, 1]
#100 1010 0100
c = binarySum(a, b)
print(c)