免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: tyc611
打印 上一主题 下一主题

一种变进制数及其应用(全排列之Hash实现) [复制链接]

论坛徽章:
1
狮子座
日期:2013-12-16 16:09:24
11 [报告]
发表于 2008-10-09 12:54 |只看该作者
mark!
强帖!

论坛徽章:
0
12 [报告]
发表于 2008-10-09 14:49 |只看该作者
不光是全排列,A(m,n)这样的选择排列也可以hash,某年的国家队论文上讲过

论坛徽章:
0
13 [报告]
发表于 2008-10-09 18:42 |只看该作者

“十进制数 <--> 变进制数 <--> 排列”的之间转换实现

在“十进制数 <--> 变进制数 <--> 排列”的转换中,
(1)从十进制数到变进制数的转换方法与p进制数之间的转换类似,但区别是被除数和模数是依次是2,3,4,...n,而不是固定的p
(2)从变进制数到排列的转换算法如下:
使用一个有序的(升序)元素集合作为初始待排子集,然后按照如下过程处理:
从变进制数的高位向低位扫描,对于变进制数的每一位ai,
从当前待排子集中选出第ai+1大元素E,并把它与当前待排子集中它后面的子序列进行交换,然后从当前待排子集中去掉元素E
重复以上过程,直到所有变进制数的位扫描完毕,此时当前待排子集将刚好剩下一个元素,得到与变进制数对应的排列

“十进制数 <--> 变进制数 <--> 排列”之间的转换代码如下:

  1. #include <iostream>
  2. #include <iterator>
  3. #include <vector>
  4. #include <algorithm>
  5. #include <cassert>

  6. using namespace std;

  7. // 把十进制数转换为变进制数,并返回变进制数的位数
  8. // 变进制数varNumber[0]对应着变进制数的最低位
  9. int DecimalToVariableRadix(size_t decimalNumber, vector<int> &varNumber)
  10. {
  11.     varNumber.clear();

  12.     int carry = 2;
  13.     while (decimalNumber > 0) {
  14.         varNumber.push_back(decimalNumber % carry);
  15.         decimalNumber /= carry;
  16.         ++carry;
  17.     }

  18.     if (varNumber.empty())
  19.         varNumber.push_back(0);

  20.     return varNumber.size();
  21. }

  22. // 把十进制数转换为指定位数的变进制数(高位填充0),并返回变进制数的实际有效位数
  23. // 如果产生的变进制数的位数比指定的位数要多,则指定位数不起作用
  24. // 变进制数varNumber[0]对应着变进制数的最低位
  25. int DecimalToVariableRadix(size_t decimalNumber, vector<int> &varNumber, int num)
  26. {
  27.     varNumber.clear();

  28.     int carry = 2;
  29.     while (decimalNumber > 0) {
  30.         varNumber.push_back(decimalNumber % carry);
  31.         decimalNumber /= carry;
  32.         ++carry;
  33.     }

  34.     int size = varNumber.size();
  35.     if (size < num)
  36.         varNumber.insert(varNumber.end(), num - size, 0);

  37.     return size;
  38. }

  39. // 把变进制数转换为十进制数
  40. // 变进制数varNumber[0]对应着变进制数的最低位
  41. size_t VariableRadixToDecimal(const int varNumber[], int num)
  42. {
  43.     size_t factor = 1;
  44.     size_t result = 0;
  45.    
  46.     for (int i = 0; i < num; ++i) {
  47.         result += varNumber[i] * factor;
  48.         factor *= i + 2;
  49.     }

  50.     return result;
  51. }

  52. // 把排列转换为变进制数,变进制数的高位可能会出现多个0
  53. // 变进制数varNumber[0]对应着变进制数的最低位
  54. template <typename ElemType>
  55. void PermutationToVariableRadix(const ElemType permutation[], int num, vector<int> &varNumber)
  56. {
  57.     for (int i = 1; i < num; ++i) {
  58.         int count = 0;
  59.         for (int k = 0; k < i; ++k) {
  60.             if (permutation[k] > permutation[i])
  61.                 ++count;
  62.         }
  63.         varNumber.push_back(count);
  64.     }
  65. }

  66. // 把变进制数转换为排列,要求传入的排列元素集合是有序的(升序)
  67. // 并且要求变进制数的位数(包括高位的0)刚好比排列元素少一
  68. // 变进制数varNumber[0]对应着变进制数的最低位
  69. template <typename ElemType>
  70. void VariableRadixToPermutation(const int varNumber[], int num, ElemType perm[])
  71. {
  72.     for (int k = num - 1; k >= 0; --k) {
  73.         // 交换当前待排子集中第(varNumber[k] + 1)大元素和它后面的子序列
  74.         int m = k + 1;             // 当前待排子集中最后一个元素下标
  75.         int j = m - varNumber[k];  // 当前待排子集中第(varNumber[k] + 1)大元素
  76. #if 0
  77.         // 实现std::rotate的功能
  78.         ElemType tmp = perm[j];
  79.         for (; j < m; ++j)
  80.             perm[j] = perm[j + 1];
  81.         perm[m] = tmp;
  82. #else
  83.         rotate(perm + j, perm + j + 1, perm + m + 1);
  84. #endif
  85.     }
  86. }

  87. //////////////////////////////////////////////////////////////////////////////////////
  88. class AssureException: public std::exception
  89. {
  90. };

  91. #define Assure(os, x) (void)((!!(x)) || (ShowFailedMessage(os, #x, __FILE__, __LINE__), 0))

  92. inline void ShowFailedMessage(std::ostream &os, const char* expr, const char *file, size_t line)
  93. {
  94.     os << "Failed: " << expr << ", file \"" << file << "\", line " << line << '\n';
  95.     throw AssureException();
  96. }


  97. void ShowUsage1()
  98. {
  99.     try {
  100.         size_t num = 235;
  101.         vector<int> varNumber;

  102.         DecimalToVariableRadix(num, varNumber);
  103.         cout << "Decimal number: " << num;
  104.         cout << "\nConverted to variable radix number (low -> high): ";
  105.         copy(varNumber.begin(), varNumber.end(), ostream_iterator<int>(cout, " "));

  106.         size_t newNum = VariableRadixToDecimal(&varNumber[0], varNumber.size());
  107.         cout << "\nConverted back to decimal number: " << newNum << '\n';

  108.         Assure(cout, num == newNum);
  109.         cout << endl;
  110.     }
  111.     catch (AssureException) {
  112.     }
  113. }

  114. void ShowUsage2()
  115. {
  116.     try {
  117.         char perm[] = {'d', 'e', 'a', 'b', 'f', 'c', 'g'};
  118.         const int NUM = sizeof(perm) / sizeof(perm[0]);
  119.         vector<int> varNumber;

  120.         PermutationToVariableRadix(perm, NUM, varNumber);
  121.         cout << "Permutation: ";
  122.         copy(perm, perm + NUM, ostream_iterator<char>(cout));
  123.         cout << "\nConverted to variable radix number (low -> high): ";
  124.         copy(varNumber.begin(), varNumber.end(), ostream_iterator<int>(cout, " "));

  125.         char newPerm[NUM] = {'a', 'b', 'c', 'd', 'e', 'f', 'g'};
  126.         VariableRadixToPermutation(&varNumber[0], varNumber.size(), newPerm);
  127.         cout << "\nConverted back to permutation: ";
  128.         copy(newPerm, newPerm + NUM, ostream_iterator<char>(cout));
  129.         cout << '\n';

  130.         Assure(cout, equal(perm, perm + NUM, newPerm));
  131.         cout << endl;
  132.     }
  133.     catch (AssureException) {
  134.     }
  135. }

  136. void Test()
  137. {
  138.     try {
  139.         cout << "testing \"permutation -> variable radix -> decimal -> "
  140.             "variable radix -> permutation\"...";

  141.         const int NUM = 9;
  142.         char perm[NUM] = {'1', '2', '3', '4', '5', '6', '7', '8', '9'};

  143.         do {
  144.             // permutation will be  converted to variable radix number
  145.             vector<int> varNumber;
  146.             PermutationToVariableRadix(perm, NUM, varNumber);

  147.             // variable radix number will be converted to decimal number
  148.             size_t decimalNumber = VariableRadixToDecimal(&varNumber[0], varNumber.size());

  149.             // decimal number will be converted back to variable radix number
  150.             vector<int> newVarNumber;
  151.             DecimalToVariableRadix(decimalNumber, newVarNumber, NUM - 1);

  152.             // variable radix number will be converted back to permutation
  153.             char newPerm[NUM] = {'1', '2', '3', '4', '5', '6', '7', '8', '9'};
  154.             VariableRadixToPermutation(&newVarNumber[0], newVarNumber.size(), newPerm);

  155.             Assure(cout, equal(varNumber.begin(), varNumber.end(), newVarNumber.begin()));
  156.             Assure(cout, equal(perm, perm + NUM, newPerm));
  157.         } while (next_permutation(perm, perm + NUM));

  158.         cout << "done. Ok!" << endl;
  159.     }
  160.     catch (AssureException) {
  161.     }
  162. }

  163. int main()
  164. {
  165.     ShowUsage1();
  166.     ShowUsage2();
  167.     Test();
  168. }
复制代码

论坛徽章:
0
14 [报告]
发表于 2008-10-09 18:46 |只看该作者
原帖由 wzcsoft 于 2008-10-9 14:49 发表
不光是全排列,A(m,n)这样的选择排列也可以hash,某年的国家队论文上讲过

A(m,n)这种排列也可产生一种更一般的m-n变进制数,但觉得用途不大,可能是我还没掌握
如果你有相应的资料,还望提供

论坛徽章:
1
IT运维版块每日发帖之星
日期:2016-07-05 06:20:00
15 [报告]
发表于 2008-10-10 23:47 |只看该作者
想问楼主一个问题:
你是说:十进制数 <--1--> 变进制数 <--2--> 排列(Hash)
那如果:十进制数 <--    一步到位实现      --> 排列(Hash),
也就是,把中间1、2的过程看成是黑盒子,

我想问:1、过程1+2的总体实现代价是否小于或等于一步到位的实现方法?
           2、若是,是否可以说,变进制数仅算作是一个中间产物或者解决思路,仅仅是逻辑上更清晰?
谢谢!

[ 本帖最后由 cheveu 于 2008-10-10 23:48 编辑 ]

论坛徽章:
0
16 [报告]
发表于 2008-10-11 09:59 |只看该作者
原帖由 cheveu 于 2008-10-10 23:47 发表
想问楼主一个问题:
你是说:十进制数 <--1--> 变进制数 <--2--> 排列(Hash)
那如果:十进制数 <--    一步到位实现      --> 排列(Hash),
也就是,把中间1、2的过程看成是黑盒子,

我想问:1、过程1+2的总体实现代价是否小于或等于一步到位的实现方法?
           2、若是,是否可以说,变进制数仅算作是一个中间产物或者解决思路,仅仅是逻辑上更清晰?
谢谢!

从逻辑角度上说,变进制数的中间过程是必须的,不然我们也没必要引入这个东西
但是实际计算时可以把两个过程实现在一起(逻辑上仍存在变进制数,虽然不一定要真实表示出来)

论坛徽章:
0
17 [报告]
发表于 2008-10-11 11:19 |只看该作者
很佩服这些搞好算法的高手,能否指点下达到如此境界的学习历程

论坛徽章:
0
18 [报告]
发表于 2008-10-22 14:40 |只看该作者
写得太好了,很受启发

论坛徽章:
0
19 [报告]
发表于 2008-10-22 14:54 |只看该作者
我顶

论坛徽章:
0
20 [报告]
发表于 2008-10-22 18:42 |只看该作者
看来没文化是不行,写不出这样的长文。
上星期看高程的书上讲穷举算法,嫌它太麻烦,我就模拟数字进制搞了和兔子尾巴差不多长小代码。
不知lz所说的用变进制实现全排列,是不是差不多意思。
至于 hash 的,文太长,还没仔细看,等下再学习

#! /usr/bin/perl

use warnings;
use strict;

my %dict = ('A'=>'E', 'E'=>'F', 'F'=>'H', 'H'=>'J', 'J'=>'K',
&nbsp;&nbsp;&nbsp;&nbsp;'K'=>'M', 'M'=>'P', 'P'=>'A', ' '=>'A');
my $max = 'P';
my $str_len = 4;

my @tmp;
for (my $i=0; $i<$str_len; $i++) { push(@tmp, ' ') }

sub up {
&nbsp;&nbsp;&nbsp;&nbsp;my($pos) = @_;
&nbsp;&nbsp;&nbsp;&nbsp;if (($tmp[$pos] eq $max) and ($pos < $str_len)) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$tmp[$pos] = $dict{$tmp[$pos]};

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$pos++; up($pos);
&nbsp;&nbsp;&nbsp;&nbsp;} else {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$tmp[$pos] = $dict{$tmp[$pos]};
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 0;
&nbsp;&nbsp;&nbsp;&nbsp;}
}

while (!($tmp[3] eq $max)) {
&nbsp;&nbsp;&nbsp;&nbsp;up(0);

&nbsp;&nbsp;&nbsp;&nbsp;for (@tmp) { print if ($_ ne ' ') }
&nbsp;&nbsp;&nbsp;&nbsp;print "\n";
}


[ 本帖最后由 redspider 于 2008-10-22 18:45 编辑 ]
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP