key 发表于 19-5-2009 01:42:57

一道排列题的做法讨论

题目大概是这样的:

定义desirable数:如果一个数的每一位都严格升序,则该数为desirable数。
如:123, 489, 2678
某人使用了一个desirable数做密码。现在你被告称这个密码的长度为N位,
请用程序排列出所有的可能性。

二楼开始讨论实现方法。

key 发表于 19-5-2009 01:54:13

显然这是一道10选N的排列问题。最简单的做法就是用递归函数来实现。
这个递归函数的定义大概是这样:

列出desirable数:起始于b, 共n位
相当于:
   * 列出第一位数 <1>
   * 在余下的数中做list_desirable(k+1, n-1),这里k为上面列出来的数的值

对于<1>,直觉上我会列出b:9的所有数,但事实上只需要写出 b : 9 - n + 1 这些数则可。

由于程序需要打印所有的排列,所以需要一个数据结构来记录现在已经列出来的数。
我们知道,当递归前进一步时,这个记录添加一个数;递归完成一步后,这个记录会减少一个数,
是明显的LIFO结构,所以用堆栈来实现

于是pseudo-code可以这样写:ADT list_stack {
   V[] {记录已经入栈的数}
   top : integer
push(int x);
pop();
as_string() : string;
is_empty() : boolean
}

list_desirable(list_stack, int begin, int num)
{
for(k = begin : 9 - num + 1)
{
    list_stack.push(k);
    if(num==1)
       print(list_stack);
   else
      list_desirable(list_stack, k+1, num-1);
   list_stack.pop();
}

key 发表于 19-5-2009 18:55:41

再看非递归的实现方法

代码很短,直接贴代码好了。由于C++中的stack不支持遍历,只好用vector来做栈(其实应该用list)8 template<class T> void print_stack(vector<T> &s)
9 {
10   typename vector<T>::iterator it;
11   for(it=s.begin(); it!=s.end(); it++)
12         cout << * it << ", ";
13   cout << endl;
14 }         
15         
16 void t(int n)
17 {         
18   int k;
19         
20   vector<int> s;
21
22   for(k=0; k<n; k++)
23         s.push_back(k);
24
25   while(!s.empty())
26   {
27         print_stack(s);
28
29         int x = s;
30         s.pop_back();
31
32         while(s.size() < n && !( s.empty() && x == 9))
33         {
34             if(x < 9)
35               s.push_back(++x);
36             else
37             {
38               x = s;
39               s.pop_back();
40             }
41         }
42
43   }
44 }其中第32条的循环条件有点tricky
页: [1]
查看完整版本: 一道排列题的做法讨论