自己写的产生随机数组的算法,注释详细,这里不多说了,请大佬帮我找找有没有BUG,或者有没有注释写的不对的地方,或者有没有优化。 另外,这是我自己想到的,如果有人知道有人已经发明了这种算法,也请指出来。
//exam_KeyUpsetAlgorithm
/*
*算法理论:
* 对于一棵无根树,令任何一个结点为根都会行程一棵全新的、随机的树。重复此过程,令每一棵长度>1的子树达到随
* 机,(不一定是二叉树,但最大度数一定在[2,树的结点数/2]的区间内)返回回来之后,形成的树是一个随机的,则
* 该树产生的生成数组也是一个随机的。
*伪代码:
* 对于每次生成根结点:
* root<-(-INF)
* 如果root在树中出现过或者非法或者root还未生成
* root<-rand(1,n) //可以优化为rand(l,r)
* num<-rand(2,n/2) //n表示树的结点数
* a[++cnt]=g[root] //a表示生成数组,cnt表示当前点的位置,g表示第i个位置表示的值是什么
* 循环num次,继续生成num个子树
*时间复杂度估计:
* 耗时部分:
* 1.产生root,最坏为n
* 2.产生子树,最坏为n/2
* 3.枚举每个生成的根结点,时间为n
* 综上考虑: 保守估计: O(2*n^2+n^2)
* 大致为: O(n^2)
*产生随机数组数量估计:
* 对于每一个点,都可能产生n+1种选择,但是由于是一个整体,所以是一个近似(n+1)!的数量
*/
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <ctime>
#include <map>
#define INF (0x3f3f3f3f)
#define MAXN 1005
using namespace std;
typedef int t1;
int n,m,cnt;
map<t1,int> book;
int a[MAXN],g[MAXN];
void KeyUpsetAlgorithm(){
if(n==0)return ;
int root=-INF;
while(root==-INF||!book[g[root]]){
root=rand()%m+1;
}
a[++cnt]=g[root];
book[g[root]]--;
n--;if(n==0){return ;}
int num=rand()%n+1;
// cout<<"将根结点定为"<<root<<",生成"<<num<<"个子树,现在"<<g[root]<<"还剩"<<book[root]<<"个\n";
for(int i=1;i<=num&&n!=0;i++){
KeyUpsetAlgorithm();
}
}
int main(){
srand(time(NULL));//令随机数按照时间戳生成
while(cin>>g[++n])book[g[n]]++;
n--;
m=n;
KeyUpsetAlgorithm();
for(int i=1;i<=cnt;i++){
cout<<a[i]<<" ";
}
return 0;
}