在数组A中寻找第k小的元素-最坏情况为线性时间的算法
来源:互联网 发布:淘宝便宜手机优惠券 编辑:程序博客网 时间:2024/04/30 11:53
I : 平均情况下的时间复杂度为:O(n) 期望值(expected); 最坏情况下的时间复杂度为:O(n的平方)即:每次对A划分为(0:n-1)
函数命名为:find_k_th(A, p, q, k) //int value = find_k_th(A, p, q, k): value为从A[p]到A[q]中第k小的值
可以从 random-quicksort 算法中(复杂度分析运用了随机变量指示器:indicator of random variable)将数组A进行划分,随机选取主元pivot,得到一个返回的值r(r为数组A中<=pivot 的索引,即:A[r] = pivot,小于pivot的个数为:num = r-p+1 ):
- num = k, 返回A[r], 即:A[r]为所要找的A中第k小的值;
- num < k, 递归地返回 find_k_th(A, r+1, q, k-num), 即:A的左边有num个小于第k小的值,则第k小的值 = 右边的第 k-num 小的值;
- num > k, 递归地返回 find_k_th(A, p, r-1, k), 即: num > k, 第k小的值在A的左边。
因为第I种算法只有平均情况下T(n)才为线性,不能避免最坏的情况;为了使最坏情况下T(n)也为线性,需要每次选择的主元pivot应该确定地处于A的中间,而非随机选择。
方法:递归的划分输入数组A
步骤:
- 将长度为n的数组A,划分为 n/5 个长度为5的小数组,并且选择对每个数组都取其中值,并储存在temp[ floor(n/5) ]中( 可用插入排序再返回中值,因为长度为固定的5,时间复杂度 = Theta(n) );
int divide5ReturnMedian(int *A, int p){ int B[5]; for(int i = 0; i < 5; i++) B[i] = A[i+p]; for(int i = 0; i < 4; i++){ int j = i+1; int k = i; int temp = B[j]; while( temp < B[k] && k >= 0 ){ B[k+1] = B[k]; k--; } B[k+1] = temp; } return B[2];}
- 递归地寻找temp数组中的中值将其作为x,即:median of the medians ,时间复杂度 = T(n/5);
int sub_n = n/5; if( sub_n > 0) //A的长度 >= 5 { int temp[sub_n]; for(int i = 0; i < sub_n; i++) temp[i] = divide5ReturnMedian(A, p+i*5); x = find_k_th(temp, 0, sub_n-1, sub_n/2); //第一次递归:递归地选择中间值作为pivot } else //A的长度 < 5, 直接使用插入排序得到中间值作为pivot { int B[n]; for(int i = 0; i < n; i++) B[i] = A[p+i]; insertionSort(B, 0, n-1); x = B[n/2]; }
- 将x作为pivot,对A进行划分,此时每次划分都在中间!而非随机!时间复杂度 = O(n);
int r = partition(A, p, q, x);
- 判断num的值(方法与随机选择pivot相同)。
int num = r-p+1; if( num == k ) return A[r]; if( num < k ) return find_k_th(A, r+1, q, k-num); else return find_k_th(A, p, r-1, k);
总的时间复杂度:T(n) = T(n/5) + T(7n/10) + O(n) = O(n) 线性!
代码实现:
int divide5ReturnMedian(int *A, int p);int partition(int *A, int p, int q, int pivot);int find_k_th(int *A, int p, int q, int k);int insertionSort(int *A, int p, int q);int main() { cout << "Hello, World!" << endl; int A[28]; for(int i = 0; i < 28; i++) A[i] = 28-i; cout<<find_k_th(A, 0, 27, 2)<<endl; insertionSort(A, 0, 27); return 0;}int insertionSort(int *A, int p, int q){ if(p < q){ int i = p; for(i = p; i < q+1; i++){ int j = i+1; int k = i; int temp_j = A[j]; while( temp_j < A[k] && k >= 0){ A[k+1] = A[k]; k--; } A[k+1] = temp_j; } } return 0;}int divide5ReturnMedian(int *A, int p){ int B[5]; for(int i = 0; i < 5; i++) B[i] = A[i+p]; for(int i = 0; i < 4; i++){ int j = i+1; int k = i; int temp = B[j]; while( temp < B[k] && k >= 0 ){ B[k+1] = B[k]; k--; } B[k+1] = temp; } return B[2];}int partition(int *A, int p, int q, int pivot){ int k = p; while( A[k] != pivot ){ k++;} A[k] = A[p]; A[p] = pivot; int i = p; for(int j = i+1; j <= q; j++){ if( A[j] < pivot ){ i++; int temp = A[i]; A[i] = A[j]; A[j] = temp; } } A[p] = A[i]; A[i] = pivot; return i;}int find_k_th(int *A, int p, int q, int k){ if(p < q) { int x = 0; //x为pivot int n = q-p+1; int sub_n = n/5; if( sub_n > 0) //A的长度 >= 5 { int temp[sub_n]; for(int i = 0; i < sub_n; i++) temp[i] = divide5ReturnMedian(A, p+i*5); x = find_k_th(temp, 0, sub_n-1, sub_n/2); //第一次递归:递归地选择中间值作为pivot } else //A的长度 < 5, 直接使用插入排序得到中间值作为pivot { int B[n]; for(int i = 0; i < n; i++) B[i] = A[p+i]; insertionSort(B, 0, n-1); x = B[n/2]; } int r = partition(A, p, q, x); int num = r-p+1; if( num == k ) return A[r]; if( num < k ) return find_k_th(A, r+1, q, k-num); else return find_k_th(A, p, r-1, k); } return A[p];}
0 0
- 在数组A中寻找第k小的元素-最坏情况为线性时间的算法
- 第九章中位数和顺序统计学 之 “寻找第i小元素之最坏情况线性时间的选择 最坏运行时间就为O(n)算法”
- 最坏为线性时间的查找第i小元素
- 寻找数组中第k小的数:平均情况下时间复杂度为O(n)的快速选择算法
- 算法导论第9章最坏情况为线性时间的选择算法
- 最坏情况为线性时间的选择算法
- CLRS 9.3最坏情况为线性时间的选择算法
- (p123)最坏情况为线性时间的选择算法
- 最坏情况为线性时间的选择算法
- 找第j小元素(最坏情况为线性时间)
- 算法导论:第9章 中位数和顺序统计量_2最坏情况为线性时间的选择算法
- 已知数组A[1...n] ,确定第K小元素 算法的时间复杂度O(n)
- 算法导论 最坏情况为线性时间的选择算法 9.3-8 9.3-9
- 最坏情况为线性时间的选择算法---算法导论学习笔记(2)
- 寻找数组中第k小元素
- 最坏情况下为O(N)的线性时间选择
- 最坏情况下的线性时间的选择算法
- 最坏情况为线性时间的选择算法之Python实现
- 《Unix内核源码剖析》读书笔记03-进程管理【切换执行进程】
- Hibernate中Criteria的完整用法
- 恐惧会让你成为一个更糟糕的程序员
- Java基础之线程与多线程操作详解
- UVA - 10396 Vampire Numbers
- 在数组A中寻找第k小的元素-最坏情况为线性时间的算法
- 【转】Python之Pickle模块(持久化对象存储)
- Linux 性能监控
- Block 简单用法 和 回调用法
- LeetCode OJ----Reverse Integer
- Java多线程
- 黑马程序员_Java_反射机制总结
- Ubuntu桌面上如何禁用默认的密钥环解锁提示
- 显示图片列表时出现异常java.lang.OutOfMemoryError或android.view.InflateException: Binary XML file line #98: Error