BFPRT算法

本文详细介绍了BFPRT算法的工作原理及其实现过程。通过将数组分成小组并找到每组的中位数,再递归地查找这些中位数的中位数来确定一个较好的支点。之后使用该支点对原始数组进行划分,从而高效地找到第k小的元素。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第一步:将给定的一串数字以5为一组,分好组
第二步:将分组的数据排好序
第三步:创建中位数数组,获取每个分组的中位数
第四步:循环第三步:直到中位数数组中只有一个数,那就是我们需要的比较数字
第五步:利用partition,小于该数的放左边,等于放中间,大于放右边
第六步:循环第五步,得到我们想要的第i个数

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

public static int  getMinKNumsByBFPRT(int [] arr,int k)
	{
		int[] copyArr = copyArray(arr);
		return bfprt(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 bfprt (int [] arr,int begin,int end,int i)
	//在begin和end范围上求第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])//[0]和[1]是相同区域的两个边界
		{
			return arr[i];
		}
		else if(i<pivotRange[0])
		{
			return bfprt(arr,begin,pivotRange[0]-1,i);//i在左边界
		}
		else
		{
			return bfprt(arr,pivotRange[1]+1,end,i);//i在右边界
		}	
	}
	
	
	public static int medianofMedians(int []arr,int begin,int end)//将数组5个一组分组
	{
		int num=end-begin+1;
		int offset=num%5==0?0:1;//是否整除5,整除就是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));//获得5个一组分组中的中位数
		}
		return bfprt(mArr,0,mArr.length-1,mArr.length/2);//递归得到mArr的中位数
	}
	
	public static int getMedian(int []arr,int begin,int end)
	{
		insertionSort(arr,begin,end);//将5个一组的5个数排好序
		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 int [] partition(int []arr,int begin,int end,int pivotValue)
	//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 void main(String[] args) {
		         int[] arr = { 1, 3, 2, 5, 9 };
		          // 测试普通方法
		         System.out.println(getMinKNumsByBFPRT(arr,1));
		         System.out.println(getMinKNumsByBFPRT(arr,2));
		         System.out.println(getMinKNumsByBFPRT(arr,3));
		         System.out.println(getMinKNumsByBFPRT(arr,4));
		         System.out.println(getMinKNumsByBFPRT(arr,5));
		      }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值