现在的位置: 首页 > 综合 > 正文

全排列的Hash算法

2013年11月08日 ⁄ 综合 ⁄ 共 1990字 ⁄ 字号 评论关闭

全排列的Hash算法

OI 2009-08-28 15:43:39 阅读69 评论0   字号:大中小 订阅

我们经常使用的数的进制为常数进制,即始终逢p1。例如,p进制数K可表示为
K = a0*p^0 + a1*p^1 + a2*p^2 + ... + an*p^n
(其中0 <= ai <= p-1),
它可以表示任何一个自然数。

对于这种常数进制表示法,以及各种进制之间的转换大家应该是很熟悉的了,但大家可能很少听说变进制数。这里我要介绍一种特殊的变进制数,它能够被用来实现 全排列的Hash函数,并且该Hash函数能够实现完美的防碰撞和空间利用(不会发生碰撞,且所有空间被完全使用,不多不少)。这种全排列Hash函数也 被称为全排列数化技术。下面,我们就来看看这种变进制数。

我们考查这样一种变进制数:第1位逢21,第2位逢31……,第n位逢n+11。它的表示形式为
K = a1*1! + a2*2! + a3*3! + ... + an*n!
(其中0 <= ai <= i),
也可以扩展为如下形式(因为按定义a0始终为0),以与p进制表示相对应:
K = a0*0! + a1*1! + a2*2! + a3*3! + ... + an*n!
(其中0 <= ai <= i)。
(后面的变进制数均指这种变进制数,且采用前一种表示法)

先让我们来考查一下该变进制数的进位是否正确。假设变进制数K的第iaii+1,需要进位,而ai*i!=(i+1)*i!=1*(i+1)!,即正确的向高位进1。这说明该变进制数能够正确进位,从而是一种合法的计数方式。

接下来我们考查n位变进制数K的性质:
1)当所有位ai均为i时,此时K有最大值
MAX[K] = 1*1! + 2*2! + 3*3! + ... + n*n!
          = 1! + 1*1! + 2*2! + 3*3! + ... + n*n! - 1
          = (1+1)*1! + 2*2! + 3*3! + ... + n*n! - 1
          = 2! + 2*2! + 3*3! + ... + n*n! - 1
          = ...
          = (n+1)!-1
因此,nK进制数的最大值为(n+1)!-1
2)当所有位ai均为0时,此时K有最小值0
因此,n位变进制数能够表示0(n+1)!-1的范围内的所有自然数,共(n+1)!个。

在一些状态空间搜索算法中,我们需要快速判断某个状态是否已经出现,此时常常使用Hash函数来实现。其中,有一类特殊的状态空间,它们是由全排列产生 的,比如N数码问题。对于n个元素的全排列,共产生n!个不同的排列或状态。下面将讨论如何使用这里的变进制数来实现一个针对全排列的Hash函数。

从数的角度来看,全排列和变进制数都用到了阶乘。如果我们能够用0n!-1n!个连续的变进制数来表示n个元素的所有排列,那么就能够把全排列完全地 数化,建立起全排列和自然数之间一一对应的关系,也就实现了一个完美的Hash函数。那么,我们的想法能否实现呢?答案是肯定的,下面将进行讨论。

假设我们有b0,b1,b2,b3,...,bnn+1个不同的元素,并假设各元素之间有一种次序关系 b0<b1<b2<...<bn。对它们进行全排列,共产生(n+1)!种不同的排列。对于产生的任一排列 c0,c1,c2,..,cn,其中第i个元素ci1 <= i <= n)与它前面的i个元素构成的逆序对的个数为di0 <= di <= i),那么我们得到一个逆序数序列d1,d2,...,dn0 <= di <= i)。这不就是前面的n位变进制数的各个位么?于是,我们用n位变进制数M来表示该排列:
M = d1*1! + d2*2! + ... + dn*n!
因此,每个排列都可以按这种方式表示成一个n位变进制数。下面,我们来考查n位变进制数能否与n+1个元素的全排列建立起一一对应的关系。

由于n位变进制数能表示(n+1)!个不同的数,而n+1个元素的全排列刚好有(n+1)!个不同的排列,且每一个排列都已经能表示成一个n位变进制数。如果我们能够证明任意两个不同的排列产生两个不同的变进制数,那么我们就可以得出结论:
定理1 n+1个元素的全排列的每一个排列对应着一个不同的n位变进制数。

/*
补充: 什么是逆序数:
跟标准列相反序数的总和
比如说
标准列是1 2 3 4 5
那么 5 4 3 2 1 的逆序数算法:
看第二个,4之前有一个5,在标准列中54的后面,所以记1
类似的,第三个 3 之前有 4 5 都是在标准列中3的后面,所以记2
同样的,2 之前有3个,1之前有4
将这些数加起来就是逆序数=1+2+3+4=10

再举一个 2 4 3 1 5
4
之前有0
3
之前有1
1
之前有3
5
之前有0
所以逆序数就是1+3=4
*/

对于全排列的任意两个不同的排列p0,p1,p2,...,pn(排列P)和q0,q1,q2,...,qn(排列Q),从后往前查找第一个不相同的元素,分别记为piqi0 < i <= n)。
1)如果qi > pi,那么,
如果在排列Qqi之前的元素x

抱歉!评论已关闭.