问题引出:给出一个集合N,求出其中第k小的数,第K小的元素指对集合L中的元素升序排列好后第K的元素。
1:惯性思维是对该集合中的每个数进行排序,然后找到索引为k的元素,最好的情况应该是O(nlogn)
2:BFPTR算法,一个即使是最坏情况下,也能达到O(n)的算法,通过对这个算法的学习,很直观的感受到,这个算法首先将集合中的数分5个一组,然后找到每组的中位数,将中位数放入一个集合,然后再求这个集合的中位数m,然后按照该中位数对数组进行划分,左边放比m小的,右边放比m大的,然后观察m的位置与k的关系进行相应递归,按照以前学过的快速排序算法,其实这个算法改变了枢纽(pivot)的选择方式,并且能明显提高算法的效率
个人的一点理解:
将元素分为5个一组,(这样做能使后续的划分更加合理,是由五位数学家研究出来的)对每组进行排序,则在找到中位数的中位数m后进行划分时,集合大部分已经处于有序状态,此时采取快速排序的思路,对集合进行划分,即修改快速排序的主元选取规则,将中位数集合的中位数作为主元,最坏情况下的时间复杂度也是O(n)
伪代码(纯属个人理解,希望得到批评指正):
1:Find(){ //找集合N中第k小的数 FindMid();//将集合N分为5个一组,共n/5组,将每组进行插入排序,找出每组的中位数,并将其纳入集合M。 //找出M中的中位数Mid FindIndex();//在集合N找到Mid的下标 //以Mid为界,将N中比Mid小的放到Mid左边,比Mid大的放到Mid右边,并且记录划分后Mid的下标 //若Mid的下标<k,则在Mid右边的集合找 //若Mid的下标>k,则在Mid左边的集合找 //若Mid的下标=k,则找到第k小的数 }
代码(参考了一些博主)
// // main.cpp // 作业6 // // Created by yizhihenpidehou on 2020/3/31. // Copyright © 2020 yizhihenpidehou. All rights reserved. // #include <iostream> #include <stdio.h> using namespace std; const int maxen=100; void InsertSort(int n[],int low,int high){ //插入排序 int i,j; for(i=low+1;i<=high;i++){ j=i-1; int tmp=n[i]; while(j>=low&&tmp<n[j]){ n[j+1]=n[j]; j--; } n[j+1]=tmp; } } int FindMid(int n[],int low,int high){ //找出中位数 if(low==high) return n[low]; int i,k; for(i=low;i+4<=high;i+=5){ InsertSort(n, i, i+4); k=i-low; swap(n[low+k/5],n[i+2]); } int cnt=high-i+1; if(cnt>0){ InsertSort(n, i, high); k=i-low; swap(n[low+k/5],n[i+cnt/2]); } k=k/5; if(k==0) return n[low]; return FindMid(n,low,low+k); } int FindMidIndex(int n[],int low,int high,int midd){ //找出中位数的下标 for(int i=low;i<=high;i++){ if(n[i]==midd){ return i; } } return -1; } int Partition(int n[],int low,int high,int index){ //根据求出的中位数进行划分,求出划分后中位数的位置 if(low<=high){ int i=low,j=high; swap(n[index],n[low]); int tmp=n[low]; while(i!=j){ while(i<j&&n[j]>=tmp){ j--;} n[i]=n[j]; while(i<j&&n[i]<=tmp){ i++;} n[j]=n[i]; } n[i]=tmp; return i; } return -1; } int BFPTR(int n[],int low,int high,int k){ int midd=FindMid(n,low,high); int indexx=FindMidIndex(n,low,high,midd); int newIndex=Partition(n,low,high,indexx); int rank=newIndex-low+1; if(rank==k) return newIndex; else if(rank>k) return BFPTR(n,low,newIndex-1,k); return BFPTR(n,newIndex+1,high,k-rank); } int main(int argc, const char * argv[]) { int num[maxen]={-1,12,1,8,10,6,2,5,9,11,3,4,7}; int k; scanf("%d",&k); int low=1; int high=12; int index=BFPTR(num,low,high,k); printf("%d\n",num[index]); for(int i=low;i<high;i++){ printf("%d ",num[i]); } printf("\n"); return 0; }
原文地址:https://www.cnblogs.com/pipihoudewo/p/12629480.html
时间: 2024-10-27 10:47:05