问题描述:估算一个1—N 整数集合的势
思路:设X是具有n个元素的集合,我们有回放地随机,均匀和独立地从X中选取元素,设k是出现第1次重复之前所选出的元素数目,则当n足够大时,k的期望趋近为β√n,
这里β=√(π/2),利用此结论可以得出估计|X|的概率算法:n=2k2/π 。
算法伪代码如下:
SetCount (X) SetCount (X) { k ← 0; S ← Ф; a ← uniform(X); do { k++; S ← S∪{a}; a ← uniform(X); } while (a ∉S) return 2k2/π; } 复杂度:注意:∵k 的期望值是β√n,∴上述算法 n 需足够大,且运行多次后才能确定 n=|X|,即取多次运行后的平均值才能是 n。该算法的时间和空间均为θ(√n),因为k = θ(√n)
c语言项目实现:
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include<stdbool.h>
#define Pi 3.1415926
typedef int ElemType;
typedef struct Node
{
ElemType data; //元素值
int index; //索引
struct Node *next;
}Node,*Linklist; //用单链表来表示集合
Linklist LinkedListInit(); //单链表初始化
Linklist LinkedListCreat(int n);// 创建一个1-n的单链表集合
void append(Linklist L,int s);//往集合中添加一个元素,链表尾部添加一个值为S的元素
int findIndex(Linklist L,int index);//在集合找到索引为index的元素的值
bool checkElem(Linklist L,int x); //判断x是否在集合中
int SetCount(Linklist L,int n); //求集合L的势
int main()
{
printf("随机算法估计整数子集1~n的大小:\n");
printf("输入n的值");
int m,n,i,answer;
while(scanf("%d",&n) != EOF)
{
Linklist L;
L = LinkedListCreat(n);
answer =0;
for(i=0;i<70;i++) //重复计算70次取平均
{
m = SetCount(L,n);
answer += m;
}
printf("集合的势为:%d\n", answer/70);
}
return 0;
}
Linklist LinkedListInit()
{
Node *L;
L = (Node *)malloc(sizeof(Node)); //申请结点空间
if(L == NULL) //判断是否有足够的内存空间
printf("申请内存空间失败\n");
L->next = NULL; //将next设置为NULL,初始长度为0的单链表
return L;
}
Linklist LinkedListCreat(int n) //尾插法建表
{
Node *L,*p;
L = (Node*)malloc(sizeof(Node));
L->next = NULL;
Node *current ;
current = L;
int i;
for(i=1;i<=n;i++){
p = (Linklist)malloc(sizeof(Node));
p->data = i;
p->index = i;
current->next = p;
current = p;
}
return L;
}
void append(Linklist L,int s)
{
int n = 1;
Linklist p,q;
p = L;
while(p->next)
{
p = p->next;
n++;
}
q = (Linklist)malloc(sizeof(Node));
q->data = s;
q->index = n+1;
p->next = q;
}
int findIndex(Linklist L,int a)
{
Linklist p;
p = L;
int i;
for(i=1;i<=a;i++)
p = p->next;
return p->data;
}
bool checkElem(Linklist L,int x)
{
Linklist p ;
p = L;
while(p->next != NULL)
{
p = p->next;
if (p->data == x)
return true;
}
return false;
}
int SetCount(Linklist L,int n) //用随机算法求集合L的势
{
int k = 0;
int result,x,num,answer;
Linklist p,q;
p = L;
q = LinkedListInit();
srand((unsigned)time(NULL));
x = rand()%n+1; //n个元素 n个索引 随机选取一个
num = findIndex(p,x);
do{
k++;
append(q,num);
x = rand()%n+1; //n个元素 n个索引 随机选取一个
num = findIndex(p,x);
}while(!checkElem(q,num));
answer = (int) ((2*k*k)/Pi);
return answer;
}
总结反思:此题由于集合的元素是有序的整数,故元素的索引值和数据域值相同,其实索引值域可以舍去。
本文介绍了如何使用随机算法来估算1到N整数集合的势。通过随机、均匀和独立地选择元素,发现在出现第一次重复之前所选元素的平均数k接近于β√n,其中β为√(π/2)。据此,提出了一种概率算法,当n足够大时,可通过公式n=2k²/π来估计集合的大小。并提供了相应的C语言项目实现伪代码。

468

被折叠的 条评论
为什么被折叠?



