溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

c++怎么實(shí)現(xiàn)數(shù)據(jù)偽造

發(fā)布時(shí)間:2022-01-15 17:43:26 來源:億速云 閱讀:193 作者:iii 欄目:大數(shù)據(jù)

這篇文章主要介紹“c++怎么實(shí)現(xiàn)數(shù)據(jù)偽造”的相關(guān)知識,小編通過實(shí)際案例向大家展示操作過程,操作方法簡單快捷,實(shí)用性強(qiáng),希望這篇“c++怎么實(shí)現(xiàn)數(shù)據(jù)偽造”文章能幫助大家解決問題。

大致需求是已知一批數(shù)和每個(gè)數(shù)出現(xiàn)的次數(shù),然后寫個(gè)接口,每次調(diào)用都能返回已知數(shù)據(jù)中的某個(gè)數(shù),且返回的概率和原始數(shù)據(jù)中每個(gè)數(shù)出現(xiàn)的概率一致,題目描述起來有些繞口,我們來舉個(gè)實(shí)際的例子。
c++怎么實(shí)現(xiàn)數(shù)據(jù)偽造
以上面的輸入為例,要求實(shí)現(xiàn)的接口必須以11.96%的概率返回5、18.10%的概率返回91……16.55%的概率返回98,當(dāng)然我的要求不僅僅是這幾個(gè)數(shù),而是可能有10^5個(gè)數(shù)。 先別急著往下看,給你幾分鐘先思考下。

各種語言其實(shí)都內(nèi)置了random函數(shù),可以隨機(jī)返回int或者long型的隨機(jī)數(shù),這里我們先不考慮溢出的問題。為了方便講解,假設(shè)我們已有n個(gè)數(shù)存在在num[n]中,其出現(xiàn)的頻次存放在fre[n]中。 借助已有的random(),我們很簡單就可以生成0-n之間的一個(gè)隨機(jī)數(shù)i,但是如果直接返回num[i]的話,每個(gè)數(shù)返回的概率是一致的,明顯不滿足我們的需求。

其實(shí)解決方案也很簡單,我們按照每個(gè)數(shù)出現(xiàn)的頻次大小,將其映射成不同的區(qū)間大小,出現(xiàn)的概率越大,區(qū)間越大。想象下,這些數(shù)據(jù)按不同的區(qū)間大小把一個(gè)飛鏢盤分成不同的部分,我們生成數(shù)的時(shí)候就是拿個(gè)飛鏢隨機(jī)扎,扎到哪個(gè)算哪個(gè)。
c++怎么實(shí)現(xiàn)數(shù)據(jù)偽造 

當(dāng)然我們可以直接用一位直線區(qū)間描述上面的二維飛鏢盤模型。只需要隨機(jī)生成0-100%之間的數(shù)即可,假設(shè)某次隨機(jī)生成的數(shù)是0.65(65%),我們算一下 正好對應(yīng)在數(shù)字58對應(yīng)的區(qū)間上,所以這次直接返回58就是了,我們可以開始寫代碼了。
c++怎么實(shí)現(xiàn)數(shù)據(jù)偽造

    int[] num; // 數(shù)字
    int[] fre; // 出現(xiàn)的頻次
    double[] pro;  // 出現(xiàn)的概率
    int n;  // 數(shù)據(jù)量
    void init() {
        int sum = 0;
        for (int i = 0; i < n; i++) {
            sum += fre[i];
        }
        for (int i = 0; i < n; i++) {
            pro[i] = fre[i]/sum; // 計(jì)算出每個(gè)數(shù)出現(xiàn)的概率 
        }
    }
    
    int getRandom() {
        double rp = random.getNextDouble();
        double sum = 0;
        for (int i = 0; i < n; i++) {
            if (sum >= r && sum + pro[i] > rp) {  //找到命中的區(qū)間
                return num[i]; 
            }
            sum += pro[i];
        }
        return num[n-1];
    }

似乎一切都很完美,但每次getRandom()的時(shí)間復(fù)雜度是O(n),大量的使用性能也抗不太住。有沒有更好的實(shí)現(xiàn)方式?既然寫到這里了,必然是有的。

上面代碼循環(huán)中有個(gè)sum += pro[i]; 每次計(jì)算都要累加,我們是不是可以提前在init()中累加好?然后你會發(fā)現(xiàn)因?yàn)槊看卫奂拥臄?shù)都只正數(shù),所以pro是個(gè)遞增序列,對于有序序列的查找 二分必然是首選。這時(shí)候我們可以用二分重寫上面代碼。

    int[] num; // 數(shù)字
    int[] fre; // 出現(xiàn)的頻次
    double[] pro;  // 出現(xiàn)的概率
    int n;  // 數(shù)據(jù)量
    void init() {
        int sum = 0;
        for (int i = 0; i < n; i++) {
            sum += fre[i];
        }
        for (int i = 0; i < n; i++) {
            pro[i] = fre[i]/sum; // 計(jì)算出每個(gè)數(shù)出現(xiàn)的概率
            if (i != 0) {
                pro[i] += pro[i-1];
            }
        }
    }

    int getRandom() {
        double rp = random.getNextDouble();
        int l = 0;
        int r = n-1;
        while (l != r) {   // 二分查找確定區(qū)間位置  
            int mid = (l + r) >> 1;
            if (pro[mid] < rp) {
                l = mid + 1;
            } else {
                r = mid;
            }
        }
        return num[n-1];
    }

關(guān)于“c++怎么實(shí)現(xiàn)數(shù)據(jù)偽造”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識,可以關(guān)注億速云行業(yè)資訊頻道,小編每天都會為大家更新不同的知識點(diǎn)。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

c++
AI