[算法导论][练习题]2.1

本文详细解析了插入排序算法的工作原理及其在特定数组上的执行过程,并提供了非升序排序的改进算法。此外,还介绍了线性查找算法的实现及其正确性的证明。

2.1-1

以图2-2为模型,说明INSERTION-SORT在数组A=<31,41,59,26,41,58>A=<31,41,59,26,41,58>A=<314159264158>上的执行过程。


答:
图a
图b
图c
图d
图e
图f
图g

  1. 图a显示了数组AAA的初始化状态,也就是数组AAA在排序前的顺序。
  2. 在图b中,我们认定由第1个元素31为已排序的元素,此时我们指定第2个元素41为当前待插入的元素。因为41>31,所以41继续保存在数组第2个元素的位置。此时,数组AAA中已排序的子数组为<31,41><31, 41><31,41>,剩余元素为未排序的。
  3. 在图c中,我们指定数组第3个59元素为当前待插入的元素。因为59>41,所以59继续保存在数组第3个元素的位置。此时,数组AAA中已排序的子数组为<31,41,59><31, 41, 59><31,41,59>,剩余元素为未排序的。
  4. 在图d中,我们指定数组第4个元素26为当前待插入的元素。因为26<59,所以将数组第3个元素移动到第4个元素的位置;因为26<41,所以继续将数组第2个元素移动到第3个元素的位置;又因为26<31,故继续将数组第1个元素移动到第2个元素的位置。因此时数组中再无元素与待插入的元素想比较,故将26保存在数组第1个元素中的位置。此时,数组AAA中已排序的子数组为<26,31,41,59><26, 31, 41, 59><26,31,41,59>,剩余元素为未排序的。
  5. 在图e中,我们指定数组第5个元素41为当前待插入的元素。因为59>41,所以将数组第4个元素移动到第5个元素的位置;但因为41==41,故数组第3个元素不再移动。此时,数组AAA中已排序的子数组为<26,31,41,41,59><26, 31, 41, 41, 59><2631414159>,剩余元素为未排序的。
  6. 在图f中,我们指定数组第6个元素58为当前待插入的元素。以为59>58,所以将数组第5个元素移动到第6个元素的位置;而因为41<58,故数组第4个元素不再移动。此时,数组AAA中已排序的子数组为<26,31,41,41,58,59><26, 31, 41, 41, 58, 59><26,31,41,41,58,59>,因为再无剩余的未排序元素,故排序结束。
  7. 在图g中,表示出已排序的数组状态,其中的顺序为排序结果,即经排序后的数组A′=<26,31,41,41,58,59>A'=<26, 31, 41, 41, 58, 59>A=<26,31,41,41,58,59>

综上所述,在排序的过程中,数组AAA的变化如下:
A=<31,41,59,26,41,58>A=<31, 41, 59, 26, 41, 58>A=<31,41,59,26,41,58>
A=<31,41,59,26,41,58>A=<31, 41, 59, 26, 41, 58>A=<31,41,59,26,41,58>
A=<31,41,59,26,41,58>A=<31, 41, 59, 26, 41, 58>A=<31,41,59,26,41,58>
A=<26,31,41,59,41,58>A=<26, 31, 41, 59, 41, 58>A=<26,31,41,59,41,58>
A=<26,31,41,41,59,58>A=<26, 31, 41, 41, 59, 58>A=<26,31,41,41,59,58>
A=<26,31,41,41,58,59>A=<26, 31, 41, 41, 58, 59>A=<26,31,41,41,58,59>

2.1-2

重写过程INSERTION-SORT,使之按非升序(而不是非降序)排序。


答:

INSERTION-SORT-DESC(A)
	for j = 2 to A.length
		key = A[j]
		// Insert A[j] into the sorted sequence A[1 .. j-1]
		i = j - 1
		while i > 0 and A[i] < key
			A[i + 1] = A[i]
			i = i - 1
		A[i + 1] = key

2.1-3

考虑以下查找问题:
输入:nnn个数的一个序列A=<a1,a2,...,an>A=<a_1,a_2, ...,a_n >A=<a1,a2,...,an>和一个值vvv
输出:下标iii使得v=A[i]v=A[i]v=A[i]或者当vvv不在AAA中出现时,vvv为特殊值NIL。
写出线性查找的伪代码,它扫描整个序列来查找vvv。使用一个循环不变式来证明你的算法时正确的。确保你的循环不变式满足三条必要的性质。


答:

  • 算法伪命题
LINEAR-SEARCH(A, v)
	for i = 1 to A.length
		if A[i] == v
			return i
	return NIL

此处将“当vvv不在AAA中出现时,vvv为特殊值NIL”,改成“当vvv不在AAA中出现时,返回特殊值NIL”

  • C#语言实现
private static int LinearSearch(int[] array, int value)
{
	for(int i = 0; i < array.Length; i++)
	{
		if(array[i] == value)
		{
			return i;
		}
	}

	return -1;
}
  • 证明
  1. 循环不变式:在for循环的每次迭代开始时,子数组[1 … i - 1]由不同于vvv的元素组成。
  2. 初始化:在第一次循环迭代(i=1)之前,子数组是空数组,所以证明循环不变式成立。
  3. 保持:在每次循环迭代中,我们将vvvA[i]A[i]A[i]进行比较。如果它们是相同的,我们返回iii,这是正确的结果。否则,我们将继续进行循环的下一个迭代。在每次循环迭代结束时,我们知道子数组A[1..i]A[1 .. i]A[1..i]不包含vvv,所以循环不变性保持正确。为循环的下一次迭代增加iii,然后保持循环不变。
  4. 终止:当i>A.length=ni > A.length = ni>A.length=n时,循环结束。因为iii已经被增加了1,所以此时iii的值是n+1n + 1n+1。此时,对应于循环不定式中的描述,我们有子数组A[1..n]A[1 .. n]A[1..n]由不同于vvv的元素组成。因此返回NIL。
    观察到A[1…n]A[1…n]A[1n],我们得出结论,整个数组没有任何等于vvv的元素,因此该算法是正确的。

2.1-4

考虑把两个nnn位二进制整数加起来的问题,这两个整数分别存储在两个nnn元数组AAABBB中。这两个整数的和应按二进制形式存储在一个(n+1n+1n+1)元数组C中。请给出该问题的形式化描述,并写出伪代码。


答:

  • 输入:一个布尔类型的数组A=<a1,a2,...,an>A = <a_1, a_2, ... , a_n>A=<a1,a2,...,an>,以及另一个布尔类型的数组B=<b1,b2,...,bn>B = <b_1, b_2, ... , b_n>B=<b1,b2,...,bn>。数组AAA和数组BBB均表示为一个整数的二进制表示(数组中的每一个元素是0或1,对应于二进制位中的对应数位),每一个数组的长度均是nnn
  • 输出:一个数组C=<c1,c2,...,cn+1>C = <c_1, c_2, ... , c_{n+1}>C=<c1,c2,...,cn+1>。这个数组CCC表示的是C′=A′+B′C' = A' + B'C=A+B的结果,其中A′A'A表示数组AAA、‘B’‘表示数组BBB,而C′C'C表示数组’C’。

伪代码:

ADD-WITH-BINARY-BITS(A, B)
	C = new integer[A.length + 1]

	carry = 0
	for i = 1 to A.length
		temp = A[i] + B[i] + carry
		C[i] = temp % 2
		carry = temp / 2
	C[n + 1] = carry

	return C

c#代码:

static int[] AddWithBinaryBits(int[] A, int[] B)
{
	int[] result = new int[A.Length + 1];

	int carry = 0;
	for(int i = 0; i < A.Length; i++)
	{
		int temp = A[i] + B[i] + carry;
		result[i] = temp % 2;
		carry = temp / 2;
	}
	result[A.Length] = carry;

	return result;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值