1. 程式人生 > >隨機演算法 實現估算集合的勢

隨機演算法 實現估算集合的勢

問題描述:估算一個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;
}
                                                                                                                         
               

總結反思:此題由於集合的元素是有序的整數,故元素的索引值和資料域值相同,其實索引值域可以捨去。