完美洗牌算法

116 阅读1分钟
#include <iostream>
using namespace std;

// 翻转 start 开始位置 end 结束位置
void Reverse(int *a,int start,int end){
        while(start < end){
            swap(a[start],a[end]);
            ++start;
            --end;
        }//while
}
// 循环右移m位 n数组长度 下标从1开始
void LeftRotate(int *a,int m,int n){
        // 翻转前m位
        Reverse(a,1,m);
        // 翻转剩余元素
        Reverse(a,m+1,n);
        // 整体翻转
        Reverse(a,1,n);
}
// 走圈算法
void CycleLeader(int *a,int start, int n) {
        int pre = a[start];
        // 2 * i % (2 * n + 1)
        int mod = 2 * n + 1;
        // 实际位置
        int next = start * 2 % mod;
        // 按环移动位置
        while(next != start){
            swap(pre,a[next]);
            next = 2 * next % mod;
        }//while
        a[start] = pre;
}
// 完美洗牌算法
void PerfectShuffle(int *a,int n){
    
    while(n >= 1){
            // 计算环的个数
            int k = 0;
            // 3^1
            int r = 3;
            // 2 * m  = 3^k - 1
            // m <= n  ->  2 * m <= 2 * n  -> 3^k - 1 <= 2 * n
            // 寻找最大的k使得3^k - 1 <= 2*n
            while(r - 1 <= 2*n){
                r *= 3;
                ++k;
            }//while
            int m = (r / 3 - 1) / 2;
            // 循环左移n-m位
            LeftRotate(a+m,n-m,n);
            // k个环 环起始位置start: 1,3...3^(k-1)
            for(int i = 0,start = 1;i < k;++i,start *= 3) {
                // 走圈
                CycleLeader(a,start,m);
            }//for
            a += 2*m;
            n -= m;
        }
}



int main() {

    int A[] = {0,1,2,3,4,5,6,7,8,9,10,11,12};
    PerfectShuffle(A,6);
    /*
    
    
    //如果想输出为a1,b1,a2,b2……an,bn的形式,则为:
    int A[] = {0,2,3,4,5,6,7,8,9,10,11};
    PerfectShuffle(A,5);
    cout<<"1";
    for(int i = 1;i <= 10;++i){
        cout<<A[i]<<" ";
    }
    cout<<"12"<<endl;
    
    
    */
    for(int i = 1;i <= 12;++i){
        cout<<A[i]<<" ";
    }//for
    cout<<endl;
}

 

参考:blog.csdn.net/SunnyYoona/…