zoukankan      html  css  js  c++  java
  • BFPRT算法

    解决的问题:在一个数组中找到最小的k个数

    常规解法:1、排序,输出前k个数,时间复杂度O(n*log(n))。

                      2、利用一个大小为k的大根堆,遍历数组维持大根堆,最后返回大根堆就可以了,时间复杂度O(n*log(k))。

    BFPRT解法:

    利用快速排序的思路,选取一个划分值,小于这个数的放右边,等于这个数的放中间,大于这个数的放右边。如下图:

    这样我们就可以把问题转化为:在这个数组中找第k小的数,然后把k左边的数返回就可以得到最小的k个数了。

    上图可得到两个边界值L,R,与k进行比较,如果L,R中有一个与K相等表示,已经找到k了。

    BFPRT的流程(时间复杂度O(n)):

    1、把数组分成以大小为5的小组,最后面不足5个的,单独一组。(至于为什么是以5为单位,因为这个算法是由BFPRT这五个人发明的)。

    2、每个小组内排序。

    3、把每个小组内的中位数拿出来组成大小为 n/5 的数组,再去这个数组中的中位数,便得到了我们所需要的划分值X

    4、递归上述流程。如:(如果k < L,则在(0~L)中找,

                                             如果 L < k < R,就在(L~R)中寻找,

                                             如果K > R,就在(R~N)中寻找 )。

    代码:

    package basic_class_02;
    
    public class Code_06_BFPRT {
        // 解决的问题:找到一个数组最小的k个数
    	// O(N*logK)
    	public static int[] getMinKNumsByHeap(int[] arr, int k) {
    		if (k < 1 || k > arr.length) {
    			return arr;
    		}
    		int[] kHeap = new int[k];
    		for (int i = 0; i != k; i++) {  // 建立一个大根堆,堆的大小为 k
    			heapInsert(kHeap, arr[i], i);
    		}
    		
    		for (int i = k; i != arr.length; i++) { // 把之后的 arr 数组中,下标k之后的数依次加入大根堆
    			if (arr[i] < kHeap[0]) {   // 如果比堆顶要小,加入大根堆
    				kHeap[0] = arr[i];
    				heapify(kHeap, 0, k);
    			}
    		}
    		return kHeap;
    	}
    
    	public static void heapInsert(int[] arr, int value, int index) {
    		arr[index] = value;
    		while (index != 0) {
    			int parent = (index - 1) / 2;
    			if (arr[parent] < arr[index]) {
    				swap(arr, parent, index);
    				index = parent;
    			} else {
    				break;
    			}
    		}
    	}
    
    	public static void heapify(int[] arr, int index, int heapSize) {
    		int left = index * 2 + 1;
    		int right = index * 2 + 2;
    		int largest = index;
    		while (left < heapSize) {
    			if (arr[left] > arr[index]) {
    				largest = left;
    			}
    			if (right < heapSize && arr[right] > arr[largest]) {
    				largest = right;
    			}
    			if (largest != index) {
    				swap(arr, largest, index);
    			} else {
    				break;
    			}
    			index = largest;
    			left = index * 2 + 1;
    			right = index * 2 + 2;
    		}
    	}
    
    	// O(N)
    	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;
    	}
    
    	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;
    	}
    
    	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);
    		}
    	}
    
    	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);
    	}
    
    	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(getMinKNumsByHeap(arr, 10));
    		printArray(getMinKNumsByBFPRT(arr, 10));
    
    	}
    
    }
    
  • 相关阅读:
    Mysql面对高并发修改的问题处理【2】
    HSF处理流程分析
    com.jcraft.jsch.JSchException: invalid privatekey
    linux常用命令
    VPS教程:VPS主机能PING通但是SSH无法连接
    Windows 和Linux 不同操作系统的VPS有哪些区别,如何选择?
    Windows VPS有哪些?
    VPS教程:搭建个人云笔记服务器
    VPS搭个人网盘,seafile、kodexplorer、h5ai谁更合适?
    VPS教程:搭建个人网盘—seafile
  • 原文地址:https://www.cnblogs.com/horken/p/10706116.html
Copyright © 2011-2022 走看看