Programming Pearls笔记之一
Programming Pearls笔记之一
这里是编程珠玑(Programming Pearls)第一部分(前五个专栏)的笔记.
1 排序
- 问题
一个文件包含至多n个不大于n且无重复的正整数(n=10^7).要求排序之后输出.
- 解答
由于都是正整数且没有重复,可以用二进制串表示.对于二进制数组bit,如果整数i存在,则让bit[i]=1,否则bit[i]=0.例如集合{1,2,3,5,8,13}可以用二进制01110100100001000000来表示.
下面分三步解决:
/* phase 1: initialize set to empty */ for i = [0, n) bit[i] = 0 /* phase 2: insert present elements into the set */ for each i in the input file bit[i] = 1 /* phase 3: write sorted output */ for i = [0, n) if bit[i] == 1 write i on the output file
由于不是基于比较的排序算法,时间复杂度为不受O(n log n)的局限,此时为O(n).对于存在重复数值的情况也可以使用这个算法,只是要用整型数组来表示,
2 向量平移
- 问题
将一个长度为n的向量x左移i位.当n=8,i=3时,对于向量abcdefgh,左移之后为defghabc.
- 解答
记得在《数据结构》课上老师说过这是一个考研题目.下面给出两个时间复杂度为O(n),空间复杂度为O(1)的算法.方法一比较繁琐,方法二则比较优美.
- 方法一
先从x[0]开始,将x[0]保存到变量t中,将x[i]移到x[0]中,x[2*i]移到x[i]中...直到要从x[0]中取数据时,将t值取出移到相应位置.
如果向量中还有数据没有移动,然后从X[1]开始,将x[1]保存到t中...
直到x中所有的数据都移动过了,结束.
对于n=12,i=3的示意图:
图一 i=3,n=12示意图
- 方法二
只用三步.
reverse(0, i-1) ⇒ /* cbadefgh */ reverse(i, n-1) ⇒ /* cbahgfed */ reverse(0, n-1) ⇒ /* defghabc */
- 方法一
3 变位词查找
- 问题
给一个词典,从中查找所有的变位词(如pots,stop,tops,spot和post是变位词).
- 解答
由于变位词是由相同的字母重新排列组成的,所以可以将字母按字母序重排作为它的标识值(signature),题目中的例子的标识值即opst.然后按标识值对词典中的词进行排序,变位词由于标识值相同会相邻.这时只要比较相邻的词即可找出所有的变位词.
4 电话簿软件
- 问题
上世纪70年代,贝尔实验室发明了一个电话簿软件.可以通过下图所示的标准键盘输入来查找号码.比如,对于Mike Lesk,输入"LESK*M*"(即"5375*6*")就可以找到他的号码.如何实现?
图二 标准电话键
- 解答
将名字的按键编码作为它的标识值,对于问题中的Mike Lesk,标识值为"5375*6*".然后将标识标识值作为第一关键字,名字作为第二关键字进行排序.当查找号码时利用二分查找即可.
5 二分查找
- 问题
从有序列表中查找一个数值t.当t有多个时,返回第一个.
- 解答
这个问题比较简单,可以先利用常规的二分查找找到其中的一个t,然后再向前查找第一个,但有个更简洁的方法.
l = -1; u = n while l+1 !=u /* invariant: x[l] < t && x[u] >=t && l < u */ m = (l + u) / 2 if x[m] < t l = m else u = m /* assert l+1 =u && x[l] < t && x[u] >=t */ p = u if p >=n || x[p] != t p = -1
由于始终保持x[l]<t且x[u]>=t,又跳出循环时有l+1=u,故当x[u]=t时,一定是是第一个.
6 程序终止性
- 问题
证明当x是正整数时下面的这个程序定能终止. while x != 1 do if even(x) x = x/2 else x = 3*x+1
- 解答
这是一个数学难题,目前无解.