线性时间选择问题
来源:互联网 发布:关于人工智能英语作文 编辑:程序博客网 时间:2024/06/04 17:57
1、问题描述
给定的线性集中n个元素和一个正整数k(1≤k≤n),要求在线性时间内(即时间复杂度为O(n))找出这n个元素中第k小的元素。
2、算法设计思想
将n个元素划分成n/5组,每组5个元素,只可能有一组不是5个元素。再用冒泡排序法,将每组内的五个元素排好序,取出其中位数,共n/5个。
然后递归调用Select方法找出这n/5个数中的中位数。若n/5是偶数,就找其最大的数。以这个元素作为划分标准。判断k与n的位置,再进行下一步的划分。
3、算法过程描述
以[8,31,60,33,17,4,51,57,49,35,11,43,37,3,13,52,6,19,25,32,54,
16,5,41,7,23,22,46,29]为例查找这29个元素中的第18个元素:
(1)把这29个元素分成6组:
(8,31,60,33,17),(4,51,57,49,35),(11,43,37,3,13),(52,6,19,25,32),(54,16,5,41,7),(23,22,46,29)
(2)取出每一组的中位数,为31,49,13,25,16
(3)递归出的中值为25
(4)根据25将29个元素划分为3个子数组:
P = {8,4,11,17,3,13,6,19,16,5,7,23,22}
Q = {25}
L = {31,60,33,51,57,49,35,43,37,52,32,54,41,46,29}
(5)因为|p| = 13,|Q| = 1,18>13 +1,所以第18个元素在L区域,找第18-13-1=4个元素,对L递归;
(6)将L划分成3组:
{31,60,33,51,57}{49,35,43,37,52}{32,54,41,46,29}
(7)取出每一组的中位数,为51,43,41递归出的中值为43
(8)根据43将L组划分为3个子数组:
{31,33,35,37,32,41,29}
{43}
{60,51,57,49,52,54,41,46}
(9)因为第一个子数组中的元素的个数大于4,所以第18个元素在第一个子数组中,对第一个子数组递归;
(10)将第一个子数组分成了1组:
{31,33,35,37,32}
(11)取出中位数为33;
(12)根据33将第一个子数组分成3个子数组:
{31,32,29}
{33}
{35,3,41}
(13)因为第一个,第二个子数组的元素的个数之和为4,所以33即为所求的第18个元素。
4、算法实现及运行结果
(一)代码实现:
#include <stdio.h>#define SIZE (29) //主函数 int main (void); //递归分组 int Select(int array[],int left,int right,int ith); //寻找中位数 int Findmiddata(int array[],int left,int right);//排序取中位数下标 int InsertSort(int array[],int a,int b);//分组,以中位数为界,将比中位数小的放在左边,比中位数大的放在右边int Partition(int array[],int left,int right,int mid);//交换 void swap (int array[],int a,int b);int main(void){ //数组 int array[SIZE] = {8,31,60,33,17,4,51,57,49,35,11,43,37,3,13,52,6,19,25,32,54,16,5,41,7,23,22,46,29} ; int size = SIZE ; int ith = 18 ; for(int i = 0;i < size;i++){ printf("%d ",array[i]); } printf("\n"); printf("该数组的第%d位的元素是:%d\n",ith,Select(array,0,size - 1,ith)); }//递归分组 int Select(int array[],int left,int right,int ith){ int findMiddateMid = Findmiddata(array,left,right); int PartitionMid = Partition(array,left,right,findMiddateMid); if(PartitionMid == ith - 1){ return array[PartitionMid]; } if(PartitionMid < ith - 1){ Select(array,PartitionMid + 1,right,ith); }else{ Select(array,left,PartitionMid - 1,ith); }}//寻找中位数 int Findmiddata(int array[],int left,int right){ int i,mid; for(i = 0;i <= (right - left)/5;i++){ if((left + i * 5 + 4) < right){ mid = InsertSort(array,left + i * 5, left + i * 5 + 4); } swap(array,i,mid); } mid = InsertSort(array,0,(right - left) / 5); return mid;}//排序取中位数下标 int InsertSort(int array[],int a,int b){ int i,j; //冒泡排序 for(i = a; i < b - 1; i++){ for(j = i + 1; j < b;j++){ if(array[i] > array[j]){ swap(array,i,j); } } } //取中位数的下标 if((b - a + 1) % 2 == 0){ return (b + a) / 2 + 1; }else{ return (b + a) / 2; }}//分组,以中位数为界,将比中位数小的放在左边,比中位数大的放在右边 int Partition(int array[],int left,int right,int mid){ int value = array[mid]; int i = left; int j = right; int size = SIZE ; while(1){ while (array[i] < value){ i++; } while (array[j] > value){ j--; } if (i < j) swap(array,i,j) ; else break ; } for(int k = 0; k < size;k++){ if(array[k] == value){ mid = k; } } return mid;}//交换 void swap (int array[],int a,int b){ int temp ; temp = array[a]; array[a] = array[b] ; array[b] = temp ; }
(二)运行结果:
**
5、算法复杂度分析
**
(1)时间复杂度
上述算法中,设n = r - p + 1,即n为输入数组的长度,算法的递归调用只有在n>=75时执行。因此,当n<75时,算法Select所用的计算时间不超过一个常数,找到中位数的中位数x后,算法Select以x为划分基准调用函数Partition对数组进行划分,这需要O(n)时间。算法Select的循环共执行n/5次,每一次要O(1)时间,因此,共需O(n)时间。
设对n个元素的数组调用Select需要T(n)时间,那么找中位数的中位数x至少要T(n/5)时间。先以证明,按照算法所选的基准x进行划分所得的两个子数组分别至多有3n/4个元素,所以无论对哪个子数组调用Select都至多用T
(3n/4)时间。
所以算法的时间复杂度为
T(n) ≤
由此可得T(n)=O( n ).
(2)空间复杂度
算法在归并过程中,共需要n个辅助存储空间来临时保存合并的结果。所以空间复杂度S(n)= O(n)
- 线性时间选择问题
- 选择问题的线性期望时间算法
- 线性期望时间选择问题C语言
- 线性期望时间选择问题C语言
- 选择问题(线性时间复杂度)
- 算法探究:线性时间选择问题
- 线性时间选择
- 线性时间选择
- 线性时间选择
- 期望线性时间选择
- 线性时间选择
- 线性时间选择
- 线性时间选择
- 线性时间选择
- 线性时间选择
- 线性时间选择
- 线性时间选择
- 线性时间选择
- sysu-17C06签到
- Compile L3.0.35_4.1.0 on Ubuntu 14.04 64bit OS
- spring aop学习2:切面表达式(Pointcut express)
- python行与缩进
- ns3之PCAP tracing文件命名格式
- 线性时间选择问题
- 人机大战历程————思考与反思
- HDFS基本操作
- Java学习心得之JDK环境搭建
- fit_transform,transform
- XML的四种解析器(dom,sax,jdom,dom4j)原理及性能比较
- Xv6安装踩坑记
- string类型转换int类型
- 人工智能-超越经典搜索