99道lisp练习题----(三)格雷码和haffman树

P49 (**) Gray code.(格雷码问题)

An n-bit Gray code is a sequence of n-bit strings constructed according to certain rules. For example,
n = 1: C(1) = ['0','1'].
n = 2: C(2) = ['00','01','11','10'].
n = 3: C(3) = ['000','001','011','010',110,111,101,100].

Find out the construction rules and write a predicate with the following specification:

% gray(N,C) :- C is the N-bit Gray code

Can you apply the method of "result caching" in order to make the predicate more efficient, when it is to be used repeatedly?

  当n为1的时候,格雷码为'0','1',当n为2时,将长度为1的格雷码取
  出,然后在第0个末尾添加0和1,形成两个新的格雷码,在第二个末尾添加1和
  0,又形成两个新的格雷码,当n为3时,依次类推

(defun gray-code-gen (n)
  (labels ((rec (i acc)
	     (if (= i n)
		 acc
		 (let ((cw nil))
		   (rec (1+ i)
			(mapcan #'(lambda (ele)
				    (progn
				      (setq cw (not cw))
				      (if cw
					  (list (concatenate 'string ele "0")
						(concatenate 'string ele "1"))
					  (list (concatenate 'string ele "1")
						(concatenate 'string ele "0")))))
				acc))))))
    (rec 1 (list "0" "1"))))


采用分治策略的C++实现代码如下:

#include <iostream>
#include <string>
#include <vector>
void GrayCodeGen( int n, bool reverse, const std::string &s,
      std::vector<std::string> &r ) {
      std::string temp = reverse ? "10" : "01";
      if( n == 0 ) {
          r.push_back( s );
      } else {
         GrayCodeGen( n - 1, false, s + temp[0],
                      r );
         GrayCodeGen( n -1, true, s + temp[1],
                      r );
      }
          
}
int main() {
    std::vector<std::string> result;
    GrayCodeGen( 3, false , "", result );
    for( std::vector<std::string>::iterator iter = result.begin(); iter != result.end();
         ++iter ) {
                std::cout << *iter << std::endl;
    }
    getchar();
    return 0;
}



P50 (***) Huffman code.(haffman编码)

First of all, consult a good book on discrete mathematics or algorithms for a detailed description of Huffman codes!

We suppose a set of symbols with their frequencies, given as a list of fr(S,F) terms. Example: [fr(a,45),fr(b,13),fr(c,12),fr(d,16),fr(e,9),fr(f,5)]. Our objective is to construct a list hc(S,C) terms, where C is the Huffman code word for the symbol S. In our example, the result could be Hs = [hc(a,'0'), hc(b,'101'), hc(c,'100'), hc(d,'111'), hc(e,'1101'), hc(f,'1100')] [hc(a,'01'),...etc.]. The task shall be performed by the predicate huffman/2 defined as follows: 

% huffman(Fs,Hs) :- Hs is the Huffman code table for the frequency table Fs

haffman树的构造过程:不断从一个链表中取出权重最小的两个节点,将两个节
点从链表中删除,将这两个节点构造成一个子树,根节点为两个节点权重之和,
然后将根节点加入链表,重复这个过程,直到链表中剩下一个节点,该节点为树
的根节点. 该haffman树的构造过程仅用11行代码

(defun haffman-tree (lst)
  (let ((lst (sort lst #'< :key #'second)))
    (if (= (length lst) 1)
	(car lst)
	(let ((fi (first lst))
	      (se (second lst))
	      (left (nthcdr 2 lst)))
	  (haffman-encode
	   (cons (list 'parent (+ (second fi)
				  (second se))
		       fi se)
		 left))))))

(defun haffman-code (lst)
  (labels ((rec (lst acc)
	     (if (= (length lst) 2)
		 (list (cons (first lst) acc))
		 (nconc (rec (third lst) (concatenate 'string acc "0"))
			(rec (fourth lst) (concatenate 'string acc "1"))))))
    (rec lst "")))


C++的实现过程如下:

#include <stdio.h>
#include <iostream>
#include <list>
#include <vector>
#include <functional>
#include <algorithm>

struct Node {
       char c_; //\0 donates parent
       int w_;
       struct Node *left_, *right_;
       
       //leaf
       Node( char c, int w ) : c_(c), w_(w), 
         left_(NULL), right_(NULL) {}
       
       Node( int w, Node *l, Node *r ) : c_('\0'), w_(w),
             left_(l), right_(r) {}
             
       bool operator<( const Node & o) const {                 
            return w_ < o.w_;
       }
};
class PtrComp {
public:            
      bool operator()( const Node * p1, const Node* p2 ) {
           return *p1 < *p2;
      }
};

void printTree(const std::string &str, Node * n);

void HaffmanTree( std::list<Node> &vn ) {
  int n = vn.size();
  std::vector<Node *> vnptr;
  for(std::list<Node>::iterator i = vn.begin(); i != vn.end(); i++ ) 
    vnptr.push_back( &*i );
          
  for( int i = 0; i < n - 1 ; i++ ) {
    std::sort( vnptr.begin(), vnptr.end(), PtrComp() );
  
    Node *n0 = vnptr[0], *n1 = vnptr[1];

    vn.push_front( Node(n0->w_+n1->w_, n0, n1) );

    std::copy( &vnptr[2], &vnptr[vnptr.size()], &vnptr[0] );
    vnptr.pop_back(), vnptr.pop_back();
    vnptr.push_back( &vn.front() );
  }

}

void printTree(const std::string &str, Node * n) {
     if( n == NULL )
         return;
     if( n->c_ != '\0' ) {
         std::cout << n->c_ << " " << str << std::endl;
         return ;
     }
     
     printTree( str+'0', n->left_ );
     printTree( str+'1', n->right_ );
}
int main() {
    Node n[6] = { Node('a', 45), Node('b', 13), Node('c', 12),
                  Node('d', 16), Node('e', 9), Node('f', 5) };
    std::list<Node> vn( n, n+6 );
    HaffmanTree( vn );

    printTree( "", &vn.front() );
    getchar();
    return 0;
}

       
注意,上面的std::list<Node>不能换成std::vector<Node>,因为vector在加入元素后,如果原来的内存大小不能够容纳,则所有的元素需要重新申请内存


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值