1到n全排列的hash函数(o(n))

1到n全排列的hash函数(o(n))

  全排列的hash函数,可以利用N位变进制,一般做法是用逆序数,但时间复杂度比较大。

 

 

  设n位变进制数M,+i位逢i+1进一,显然M可表示的数的范围为[0, n!)共n!个

  要生成n个数的排列,可以先从n个数挑一个,再从剩下的n-1个数挑一下,如此反复n次。

  若最初的n个数是 0,1,2 … n-1,第一次挑选的数是t,则可以将t放入到M的n-1位,
  若第二次挑选的数是m,则 0 <= r <= n-1 且 r != t,当r等于n-1时,
  不能将r放入到M的n-2位(可以放的最大数为n-2),但是注意到r值不可能为t,
  该情况下将它的值改为t,得到的新r值肯定小等于n-2,因而可放入到M的n-2位。

  重复上面的处理,最终得到的M值与排列是一一对应的。

 

 

#include
<
algorithm
>

#include

<
cstdio
>

#include

<
cassert
>


//
template<int n> 

//
struct Factorial { enum { v = Factorial<n – 1>::v * n}; };

//


//
template<> struct Factorial<0> { enum { v = 1}; };

//


//
static const int Max_n = 12; 

//
static const int factorial[Max_n] = {  
//
0! 1! 2! .. 11!   12!= 4.8e8

//
  Factorial<0>::v, Factorial<1>::v, Factorial<2>::v,

//
  Factorial<3>::v, Factorial<4>::v, Factorial<5>::v,

//
  Factorial<6>::v, Factorial<7>::v, Factorial<8>::v,

//
  Factorial<9>::v, Factorial<10>::v, Factorial<11>::v,  

//
};




static
 inline 
bool
 init_factorial(
int
 arr[], 
int
 len) 
{

  

for
 (
int
 i 
=
 
0
, k 
=
 
1
; i 
<
 len; k 
*=
 
++
i) arr[i] 
=
 k; 
//
arr[i]为i!


  
return
 
true
;
}


int
 hash_permutation(
int
 arr[], 
const
 
int
 len)
{

  

static
 
const
 
int
 Max_n 
=
 
12
;      
//
 12!= 4.8e8


  
static
 
int
 factorial[Max_n];
  

static
 
bool
 tmp 
=
 init_factorial(factorial, Max_n);
  (

void
)tmp;
  assert(len 

>=
 
1
 
&&
 len 
<=
 Max_n);
  

//
mapped[i]记录数i最终被映射到哪个数字,index[i]记录数i在mapped数组中的位置


  
int
 mapped[Max_n], index[Max_n];
  

for
 (
int
 i 
=
 
0
; i 
<
 len; 
++
i) mapped[i] 
=
 index[i] 
=
 i;
  
  

int
 ret 
=
 
0
;
  

//
设变进制数M的+i位为(i+1)进制。从高位到低位放入数字


  
for
 (
int
 i 
=
 len 
–
 
1
; i 
>
 
0
; 
—
i) { 
    assert(arr[i] 

>=
 
0
 
&&
 arr[i] 
<
 len);  
    

int
 k 
=
 mapped[arr[i]];     
//
mapped数组中所有的数是0,1, 2, … i的一个排列,


    ret 
+=
 k 
*
 factorial[i];    
//
因而可以将数字k放到变进制数M的+i位


    
    

int
 idx 
=
 index[i];         
//
将k从mapped数组中删除,删除k前                 


    mapped[idx] 
=
 k;            
//
先将mapped数组中最大的数(也就是i)映射到k,


    index[k] 
=
 idx;             
//
保证删除k后剩下的数恰好是0,1,2 … i-1的一个排列


  }
  

return
 ret;
}


int
 main()
{

  

const
 
int
 N 
=
 
4
;
  

int
 arr[N];
  

for
 (
int
 i 
=
 
0
; i 
<
 N; 
++
i) arr[i] 
=
 i;
  

int
 count 
=
 
0
;
  

do
 {

    printf(

“
 %3d:  
“
, 
++
count);
    

for
 (
int
 i 
=
 
0
; i 
<
 N; 
++
i) printf(
“
 %2d
“
, arr[i]);
    printf(

“
  %6d\n
“
, hash_permutation(arr, N));
  } 

while
(std::next_permutation(arr, arr 
+
 N));
}

 

 

 

 

转载于:https://www.cnblogs.com/flyinghearts/archive/2011/05/08/2040612.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/110617.html原文链接:https://javaforall.net

赞 (0)
全栈程序员-站长的头像全栈程序员-站长

相关推荐

  • phpstorm2021.5.1激活码[在线序列号]「建议收藏」

    phpstorm2021.5.1激活码[在线序列号],https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月19日
  • 资源网站链接[通俗易懂]

    资源网站链接[通俗易懂]JavaScript代码在线压缩   http://oncoding.net/tools/jsmin/CSSValidationService  http://jigsaw.w3.org/cs

    2022年8月5日
  • linux如何改sftp端口,CentOS如何更改SFTP端口[通俗易懂]

    linux如何改sftp端口,CentOS如何更改SFTP端口[通俗易懂]SFTP(SSH文件传输协议)是一种安全文件协议,用于通过加密连接在两个主机之间传输文件。本文介绍了如何在Linux中更改默认的SFTP端口。我们还将向您展示如何配置防火墙以允许在新端口上使用。SFTP(SSH文件传输协议)是一种安全文件协议,用于通过加密连接在两个主机之间传输文件。它还允许您对远程文件执行各种文件操作并恢复文件传输。SFTP可以替代旧版FTP协议。它具有FTP的所有功能,但连接更…

    2022年9月14日
  • linux系统平均负载参数_变压器平均负载率怎么计算

    linux系统平均负载参数_变压器平均负载率怎么计算定义平均负载,表示当前正在运行的线程加上等待运行的线程的数量。##8.70表示过去1分钟的平均负载,7.33表示过去5分钟的平均负载,6.29表示过去15分钟的平均负载top-10:01:07up83days,23min,1user,loadaverage:8.70,7.33,6.29分析对于一个良好的系统,平均负载应该小于CPU核心数,这意味着所有的任务都可以被及时处理,而不需要等待,反之说明任务过多,无法及时响应,长期处于这样的状态,机器存在性能问题。

    2022年9月13日
  • react路由传参的几种方式[通俗易懂]

    react路由传参的几种方式[通俗易懂]第一种传参方式,动态路由传参通过设置link的path属性,进行路由的传参,当点击link标签的时候,会在上方的url地址中显示传递的整个url<Linkto=’/home?name=dx’>首页</Link>如果想真正获取到传递过来的参数,需要在对应的子组件中this.props.location.search获取字符串,再手动解析因为传参能够被用户看见…

    2022年6月11日
  • python利用cookie登录(python爬虫教程pdf)

    http://blog.csdn.net/pipisorry/article/details/47948065实战1:使用cookie登录哈工大ACM网站获取网站登录地址http://acm.hit.edu.cn/hoj/system/login查看要传送的post数据user和passwordCode:#!/usr/bin/envpython#-*-

    2022年4月17日

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号