Programming Pearls笔记之一

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的示意图:

      http://images.cnblogs.com/cnblogs_com/Open_Source/201208/201208040813436402.png

      图一 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*")就可以找到他的号码.如何实现?
    

    http://images.cnblogs.com/cnblogs_com/Open_Source/201208/201208040813445878.png

    图二 标准电话键

  • 解答

      将名字的按键编码作为它的标识值,对于问题中的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
    
  • 解答

      这是一个数学难题,目前无解.

Date: 2012-07-25 三

Author: Hu Wenbiao

Org version 7.8.11 with Emacs version 24

Validate XHTML 1.0
posted @ 2012-08-04 08:14  open source  阅读(624)  评论(6编辑  收藏  举报