Data Structure - Cantor Cantor expansion and inverse expansion

meaning

  Cantor Expand is a full array to a natural number of two-shot , commonly used in constructing the hash table space compression. Cantor essence calculate the current unfolding all arranged in ascending order of the whole arrangement, and therefore is reversible in.

principle

  X = s1(n-1)! + s2(n-2)! + s3(n-3)! + …… + sn-1 * 1! + sn * 0! 

  Where S i represents the i-th bit to the right than the A i a smaller number of values.

  We now use S L denotes an i-bit left than A i a smaller number of values, S R & lt showing the right side than the i-th bit A i a smaller number of values, the following equation can be obtained clearly:
  A i = S L + S R & lt +. 1

  Therefore si formula above equation can be calculated: S R & lt = A I - S L -1

  According to the above principle, the one {1,2,3,4,5} {3,4,1,5,2} full array may be mapped to {2,2,0,1,0}

  According to the formula, the collection is actually a variation on the number of decimal representation.

  Simple calculation: X-= ((S . 1 * (. 1-n-) S + 2 ) * (. 3-n-) + S . 3 ) * (. 3-n-) + ...... 

Cantor Expand

  Violence O (n- 2 ):

  To facilitate explanation below tree line optimization, maintenance vis embodiment selected here in the array (direct course is the same size ratio).

  VIS [j] j to whether the record has occurred, does not appear as 0, 1 has occurred. Therefore, a [i] on the left of the number smaller than the number of which is vis [j] and (j <a [i]).

  Calculating ANS, since fixing the last bit is 0, it only needs to calculate the n-1 bit.

  The whole arrangement is less than all of the sequence has a ans, so the sequence in the first row ans + 1 bits.

  code show as below:

int Power_Cantor()
{
    int ans=0;
    for(int i=1;i<=n-1;i++)
    {
        scanf("%d",&a[i]);
        int sum=0;
        for(int j=1;j<=a[i];j++)sum+=vis[j];
        vis[a[i]]=1;
        a[i]-=sum+1;
        ans=(ans+a[i])*(n-i);
    }
    returnyears + 1; 
}

  Segment tree optimization O (nlogn):

  We use segment tree structure vis storage array, you can achieve the results obtained within logn time complexity.

  code show as below:

int Cantor()
{
    int ans=0;
    for(int i=1;i<=n-1;i++)
    {
        int now=a[i];
        now-=query(1,1,n,1,a[i])+1;
        update(1,1,n,a[i],1);
        ans=(ans+now)*(n-i);
    }
    return ans+1;
}

Inverse Cantor Expand

  The first is the number of bits are arranged into a given number of decimal change we need:

  Still {3,4,1,5,2}, which is deployed Cantor 61:

  With 61/4! 13 I = 2, then a [1] = 2, i.e. first on the right is smaller than the first number there are two, the first three.

  With 13/3! 2 I = 1, A [2] = 2, i.e., less than a second after the second has 2-bit number, the second 4 bits.

  1/2! = I 01, then a [3] = 0, i.e., no less than the third number of bits after the third bit, the third bit is 1.

  1/1! 1 I = 0, a [4] = 1, i.e., less than the fourth number of bits is 1, after the fourth, the fourth bit 5.

  It is the last remaining natural number 2.

  By this analysis, the required permutations of 34,152.

  Still maintain vis array with tree line, when the first bit of each contribution value of 1 indicates the number of all were not there.

  Provided that a number of the current i, is a decimal number becomes a [i], the requirements for x. The goal is to find the number does not appear in the number smaller than the number x is the position number of a [i] th, corresponding to [. 1, x] to find the a [i] + 1'd interval.

  Here the a [i] +1 referred to as s [i]. A binary search position x: The number for each s [i], first find the left subtree is smaller than the number x of sum, s look at whether there is s [i] a: if so, show the results of left subtree, then the left subtree continues to look for s [i]; if not, to find s [i] to the right subtree - sum.

  After the lookup vis [x] modify the value 0.

  code show as below:

int search(int num)
{
    int l=1,r=n;
    while(l<r)
    {
        int mid=l+r>>1;
        int find=query(1,1,n,l,mid);
        
        if(find>=num) r=mid;
        else{
            l=mid+1;
            num-=find;
        }
    }
    return r;
}

void R_Cantor(int num)
{
    num--;  
    memset(a,0,sizeof a);
    build_tree(1,1,n);
    for(int i=1;i<=n;i++)
    {
        a[i]=num/(jc[n-i]);
        a[i]=search(a[i]+1);
        update(1,1,n,a[i],0);
        num%=jc[n-i];
    }
    
    for(int i=1;i<=n;i++)printf("%d ",a[i]);
    puts("");    
}

Attached complete code

#include <algorithm>
#include <cstring>
#include <cstdio>
#include <iostream>
using namespace std;
const int N = 1e5+10;

int n;
int a[N],tree[3*N];
int jc[10]={1,1,2,6,24,120,720,5040,40320,362880}; 

void out()
{
    for(int i=1;i<=14;i++)
    {
        printf("tree[%d] = %d\n",i,tree[i]);
    }
    puts("");
}

void build_tree(int node,int start,int end)
{
    if(start==end)
    {
        tree[node]=1;
        return;
    }
    int mid=start+end>>1;
    int left=2*node;
    int right=2*node+1;
    build_tree(left,start,mid);
    build_tree(right,mid+1,end);
    tree[node]=tree[left]+tree[right];
}

void update(int node,int start,int end,int idx,int val)
{
    if(start==end)
    {
        tree[node]=val;
        return;
    }
    int mid=start+end>>1;
    int left=2*node;
    int right=2*node+1;
    if(idx<=mid)update(left,start,mid,idx,val);
    else update(right,mid+1,end,idx,val);
    tree[node]=tree[left]+tree[right];
}

int query(int node,int start,int end,int l,int r)
{
    if(end<l || start>r)return 0;
    else if(start>=l && end<=r)return tree[node];
    
    int mid=start+end>>1;
    int left=2*node;
    int right=2*node+1;
    
    return query(left,start,mid,l,r) + query(right,mid+1,end,l,r);
}

int Cantor()
{
    int ans=0;
    for(int i=1;i<=n-1;i++)
    {
        int now=a[i];
        now-=query(1,1,n,. 1 , A [I]) + . 1 ; 
        Update ( . 1 , . 1 , n-, A [I], . 1 ); 
        ANS = (now + ANS) * (N- I); 
    } 
    return ANS + . 1 ;   // all full array the small sequences than ans one, so the sequence in the first row ans + 1 bit 
} 

int Search ( int NUM) 
{ 
    int L = . 1 , R & lt = n-;
     the while (L < R & lt) 
    { 
        int MID = L + R & lt >> . 1 ;
         int Find = Query ( . 1 , . 1 , n-, L, MID); 
        
        //A small number number number of requirements than look at the left subtree not present enough of a num 
         // if enough, then continue left subtree find num 
         // if not enough, then continue to look for the right subtree (num - the number of the found) 
        
        IF (find> = NUM) = R & lt MID;
         the else { 
            L = MID + . 1 ; 
            NUM - = find; 
        } 
    } 
    return R & lt; 
} 

void R_Cantor ( int NUM) 
{ 
    NUM -; // the sequence num ranked position, are arranged so that a small full num-1 more than in its. 
    Memset (A, 0 , the sizeof A); 
    build_tree ( . 1 , . 1 , n-);
    for(int i=1;i<=n;i++)
    {
        a[i]=num/(jc[n-i]);
        a[i]=search(a[i]+1);
        update(1,1,n,a[i],0);
        num%=jc[n-i];
    }
    
    for(int i=1;i<=n;i++)printf("%d ",a[i]);
    puts("");    
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    
    memset(tree,0,sizeof tree);
    
    int ans=Cantor();
    
//    R_Cantor(62);

    printf("%d\n",ans);
    return 0;
}

 

Guess you like

Origin www.cnblogs.com/ninedream/p/11521141.html