BFPRT

在一大堆數中求其前k大或前k小的問題,簡稱TOP-K問題。而目前解決TOP-K問題最有效的算法即是BFPRT算法,其又稱為中位數的中位數算法,該算法由Blum、Floyd、Pratt、Rivest、Tarjan提出,最壞時間復雜度為O(n)O(n)。

讀者要會快速排序相關知識,如果不會請看這里:

https://blog.csdn.net/hebtu666/article/details/81434236排序,大家在里面找快速排序閱讀即可。

?

我們以前寫過快排的改進求前k大或前k小,但是快排不可避免地存在退化問題,即使我們用了隨機數等優化,最差情況不可避免的退化到了O(N^2),而BFPRT就解決了這個問題,主要的思想精華就是怎么選取劃分值。

我們知道,經典快排是選第一個數進行劃分。而改進快排是隨機選取一個數進行劃分,從概率上避免了基本有序情況的退化。而BFPRT算法選劃分值的規則比較特殊,保證了遞歸最小的縮減規模也會比較大,而不是每次縮小一個數。

這個劃分值如何劃分就是重點。

如何讓選取的點無論如何都不會太差。

1、將n個元素劃分為n/5個組,每組5個元素
2、對每組排序,找到n/5個組中每一組的中位數;?
3、對于找到的所有中位數,調用BFPRT算法求出它們的中位數,作為劃分值。

下面說明為什么這樣找劃分值。

我們先把數每五個分為一組。

同一列為一組。

排序之后,第三行就是各組的中位數。

我們把第三行的數構成一個數列,遞歸找,找到中位數。

這個黑色框為什么找的很好。

因為他一定比A3、B3大,而A3、B3、C3又在自己的組內比兩個數要大。

我們看最差情況:求算其它的數都比c3大,我們也能在25個數中縮小九個數的規模。大約3/10.

我們就做到了最差情況固定遞減規模,而不是可能縮小的很少。

下面代碼實現:

public class BFPRT {
//前k小public static int[] getMinKNumsByBFPRT(int[] arr, int k) {if (k < 1 || k > arr.length) {return arr;}int minKth = getMinKthByBFPRT(arr, k);int[] res = new int[k];int index = 0;for (int i = 0; i != arr.length; i++) {if (arr[i] < minKth) {res[index++] = arr[i];}}for (; index != res.length; index++) {res[index] = minKth;}return res;}
//第k小public static int getMinKthByBFPRT(int[] arr, int K) {int[] copyArr = copyArray(arr);return select(copyArr, 0, copyArr.length - 1, K - 1);}public static int[] copyArray(int[] arr) {int[] res = new int[arr.length];for (int i = 0; i != res.length; i++) {res[i] = arr[i];}return res;}
//給定一個數組和范圍,求第i小的數public static int select(int[] arr, int begin, int end, int i) {if (begin == end) {return arr[begin];}int pivot = medianOfMedians(arr, begin, end);//劃分值int[] pivotRange = partition(arr, begin, end, pivot);if (i >= pivotRange[0] && i <= pivotRange[1]) {return arr[i];} else if (i < pivotRange[0]) {return select(arr, begin, pivotRange[0] - 1, i);} else {return select(arr, pivotRange[1] + 1, end, i);}}
//在begin end范圍內進行操作public static int medianOfMedians(int[] arr, int begin, int end) {int num = end - begin + 1;int offset = num % 5 == 0 ? 0 : 1;//最后一組的情況int[] mArr = new int[num / 5 + offset];//中位數組成的數組for (int i = 0; i < mArr.length; i++) {int beginI = begin + i * 5;int endI = beginI + 4;mArr[i] = getMedian(arr, beginI, Math.min(end, endI));}return select(mArr, 0, mArr.length - 1, mArr.length / 2);//只不過i等于長度一半,用來求中位數}
//經典partition過程public static int[] partition(int[] arr, int begin, int end, int pivotValue) {int small = begin - 1;int cur = begin;int big = end + 1;while (cur != big) {if (arr[cur] < pivotValue) {swap(arr, ++small, cur++);} else if (arr[cur] > pivotValue) {swap(arr, cur, --big);} else {cur++;}}int[] range = new int[2];range[0] = small + 1;range[1] = big - 1;return range;}
//五個數排序,返回中位數public static int getMedian(int[] arr, int begin, int end) {insertionSort(arr, begin, end);int sum = end + begin;int mid = (sum / 2) + (sum % 2);return arr[mid];}
//手寫排序public static void insertionSort(int[] arr, int begin, int end) {for (int i = begin + 1; i != end + 1; i++) {for (int j = i; j != begin; j--) {if (arr[j - 1] > arr[j]) {swap(arr, j - 1, j);} else {break;}}}}
//交換值public static void swap(int[] arr, int index1, int index2) {int tmp = arr[index1];arr[index1] = arr[index2];arr[index2] = tmp;}
//打印public static void printArray(int[] arr) {for (int i = 0; i != arr.length; i++) {System.out.print(arr[i] + " ");}System.out.println();}public static void main(String[] args) {int[] arr = { 6, 9, 1, 3, 1, 2, 2, 5, 6, 1, 3, 5, 9, 7, 2, 5, 6, 1, 9 };// sorted : { 1, 1, 1, 1, 2, 2, 2, 3, 3, 5, 5, 5, 6, 6, 6, 7, 9, 9, 9 }printArray(getMinKNumsByBFPRT(arr, 10));}
}

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/445535.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/445535.shtml
英文地址,請注明出處:http://en.pswp.cn/news/445535.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

180°舵機的使用步驟

一.步驟 1.首先查看舵機的運行參數&#xff0c;包括工作的電壓和電流&#xff0c;轉1&#xff08;60&#xff09;需要的脈寬是多少。 2.根據舵機提供的參數&#xff0c;算出需要的PWM的周期和脈寬的范圍。 3.通過單片機或者其他數字電路產生相應的PWM波&#xff0c;便可以驅…

Qt開源項目

圖像處理&#xff1a; Krita digikam inkscape 編輯器&#xff1a; LiteIDE QDevelper KDeveloper Monkey Studio TeXstudio 繪圖&#xff1a; ZeGrapher QtiPlot qcustomplot QWT HotShots Inkscape 三維建模&#xff1a; QCAD FreeCAD OpenModelica LibreCAD 音樂&#xff1a…

使用Python作為計算器

數值 1.python支持基本的數學運算符&#xff0c;而且應用python你可以像寫數學公式那樣簡單明了。 eg: >>> 2 2 4 >>> 50 - 5*6 20 >>> (50 - 5*6) / 4 5.0 >>> 8 / 5 # division always returns a floating point number 1.6 2.除法…

java整體打印二叉樹

一個調的很好的打印二叉樹的代碼。 用空格和^v來表示節點之間的關系。 效果是這樣&#xff1a; Binary Tree: v7v v6v ^5^ H4H …

前綴樹

是一種哈希樹的變種。典型應用是用于統計&#xff0c;排序和保存大量的字符串&#xff08;但不僅限于字符串&#xff09;&#xff0c;所以經常被搜索引擎系統用于文本詞頻統計。它的優點是&#xff1a;利用字符串的公共前綴來減少查詢時間&#xff0c;最大限度地減少無謂的字符…

學習4層板設計

今天是第一天嘗試設計四層PCB板&#xff0c;以前只畫過雙層板&#xff0c;所以今天花了好多時間來熟悉多層板的設計方法&#xff0c;現在做一下整理&#xff0c;也方便其他同胞少走彎路~~~我用的軟件是Altium Designer 6&#xff08;AD6&#xff09;步驟如下&#xff1a; 1、隨…

PCB設計的基本步驟

一.方案的設計 1.與客戶溝通&#xff0c;確定電路的功能和相關設計指標&#xff08;如&#xff1a;電源&#xff0c;功耗等&#xff09;。 2.畫出項目的硬件功能框圖。 3.設計出多種方案&#xff0c;并對多種方案進行對比&#xff0c;最終選出最合適的方案。 4.根據上述所…

堆應用例題三連

一個數據流中&#xff0c;隨時可以取得中位數。 題目描述&#xff1a;有一個源源不斷地吐出整數的數據流&#xff0c;假設你有足夠的空間來保存吐出的數。請設計一個名叫MedianHolder的結構&#xff0c;MedianHolder可以隨時取得之前吐出所有樹的中位數。 要求&#xff1a; 1…

HistCite 的使用方法

摘要 讀文獻自然要讀精品&#xff0c;在面對一個陌生領域&#xff0c;如何才能以最快速度定位精品文獻呢&#xff1f;本文將詳細介紹 HistCite 的使用方法&#xff0c;結合 Web of Science 和 Endnote &#xff0c;演示如何在幾個小時之內&#xff0c;對某個陌生領域的文獻進行…

數組基操三連(2)

轉圈打印矩陣 題目&#xff1a; 給定一個整型矩陣matrix&#xff0c;請按照轉圈的方式打印它。例如&#xff1a;1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,打印結果為&#xff1a;1,2,3,4,5,12,16,15,14,13,9,5,6,7,11,10 要求&#xff1a; 額外空間復雜度為O&#xff08;1&a…

數據結構課上筆記7

介紹棧和隊列基本概念和用法。 設輸入序列1、2、3、4&#xff0c;則下述序列中&#xff08; &#xff09;不可能是出棧序列。【中科院中國科技大學2005】 A. 1、2、3、4 B. 4、 3、2、1 C. 1、3、4、2 D.&#xff14;、1、2、3 選…

ROC曲線與AUC值

ROC曲線與AUC值 1.概述AUC&#xff08;Area Under roc Curve&#xff09;是一種用來度量分類模型好壞的一個標準。這樣的標準其實有很多&#xff0c;例如&#xff1a;大約10年前在machine learning文獻中一統天下的標準&#xff1a;分類精度&#xff1b;在信息檢索(IR)領域中常…

設置SSH免密碼自動登錄(使用別名)

每次登錄服務器都要寫一大串的用戶名&#xff08;username服務器地址&#xff09;和登錄密碼十分的繁瑣&#xff0c;所以本文就告訴大家如何通過修改配置文件&#xff0c;達到只需要輸入&#xff1a;ssh jack(你起的別名)就可以一鍵登錄到服務器中。 1.創建公鑰&#xff08;相當…

串的定長表示

思想和代碼都不難&#xff0c;和線性表也差不多&#xff0c;串本來就是數據受限的線性表。 串連接&#xff1a; #include <stdio.h> #include <string.h> //串的定長順序存儲表示 #define MAXSTRLEN 255 //用戶可在255以內定義最大串長 typedef unsigned cha…

周志華《Machine Learning》 學習筆記系列(1)--緒論

機器學習致力于研究如何通過計算手段&#xff0c;利用經驗來改善系統本身的性能&#xff0c;在計算機系統中&#xff0c;“經驗”通常是以“數據”形式存在的&#xff0c;所以&#xff0c;機器學習的主要內容是關于在計算機上從數據中產生“模型”的算法&#xff0c;即學習算法…

輕松理解牛頓迭代法且用其求平方根

牛頓迭代法概述 牛頓迭代法&#xff08;Newton’s method&#xff09;又稱為牛頓-拉弗森方法&#xff08;Newton-Raphson method&#xff09;&#xff0c;它是牛頓在17世紀提出的一種在實數域和復數域上近似求解方程的方法。 牛頓迭代公式 設rrr是f(x)0f(x)0f(x)0的根&#…

map+DP leetcode446

如果數字序列由至少三個元素組成并且任何兩個連續元素之間的差異相同&#xff0c;則稱為算術序列。 例如&#xff0c;這些是算術序列&#xff1a; 1&#xff0c;3&#xff0c;5&#xff0c;7&#xff0c;9 7&#xff0c;7,7&#xff0c;7 3&#xff0c;-1&#xff0c;-5&am…

如何使用cookie信息,完成自動登錄

在做爬蟲任務的時候&#xff0c;我們常常會遇到很多網頁必須登錄后&#xff0c;才可以開放某些頁面。所以登錄是爬取網頁的第一步。但是&#xff0c;通過post表單&#xff08;包含用戶名和密碼&#xff09;的方法&#xff0c;對于那些不需要輸入比較復雜的驗證碼的網頁&#xf…

Spring Cloud 學習筆記(1 / 3)

Spring Cloud 學習筆記&#xff08;2 / 3&#xff09; Spring Cloud 學習筆記&#xff08;3 / 3&#xff09; ---01_前言閑聊和課程說明02_零基礎微服務架構理論入門03_第二季Boot和Cloud版本選型04_Cloud組件停更說明05_父工程Project空間新建06_父工程pom文件07_復習Depend…

后綴樹/后綴數組

字典樹&#xff1a;https://blog.csdn.net/hebtu666/article/details/83141560 后綴樹&#xff1a;后綴樹&#xff0c;就是把一串字符的所有后綴保存并且壓縮的字典樹。 相對于字典樹來說&#xff0c;后綴樹并不是針對大量字符串的&#xff0c;而是針對一個或幾個字符串來解決…