类快排算法
leetcode215
由于只要求找出第k大的数,没必要将数组中所有值都排序。
典型解法:快速排序分组。
在数组中找到第k大的元素 取基准元素,将元素分为两个集合,一个集合元素比基准小,另一个比基准大 ,三种情况。 1.比基准大的元素数目标志位m正好为k-1,基准就是目的元素。 2.比基准大的元素标志位m小于k, 那么就在比基准小的集合里面找第(k-m)大的元素 3.若是比基准大的元素为m大于k,那就继续在该集合里面找第k大的元素。
快排中的partition算法,返回key在数组中的位置的cnt(相对于left的偏移量),如果cnt正好等于k,那么问题则得到解决;如果cnt小于k,去左边找第k个;如果cnt>k,则去右边找第k-cnt个。直到key的位置等于k-1,则找对问题的解。
-
/*快排中的划分算法*/
-
int partition(int* input, int low, int high)
-
{
-
int tmp = input[low]; // 取一个基准元素
-
while (low < high) {
-
while (low < high && input[high] <= tmp) {
-
high--;
-
}
-
input[low] = input[high];
-
while (low < high && input[low] >= tmp) {
-
low++;
-
}
-
input[high] = input[low];
-
}
-
input[low] = tmp;
-
return low;
-
}
-
// 参数left需要小于right
-
int findK(int* array, int left, int right, int k) {
-
//printf("%d %d %d\n", left, right, k);
-
int i = partition(array, left, right);
-
int cnt = i - left + 1;
-
if (k == cnt) {
-
return array[i];
-
} else if (k < cnt) {
-
return findK(array, left, i - 1, k);
-
} else if (k > cnt) {
-
return findK(array, i + 1, right, k-cnt);
-
}
-
return 0;
-
}
此解法的时间复杂度为O(N*lgK),logK次每次O(N),优于排序解法.
测试程序:
-
#include <iostream>
-
#include <vector>
-
using namespace std;
-
/*快排中的划分算法*/
-
int partition(int* input, int low, int high)
-
{
-
int tmp = input[low]; // 取一个基准元素
-
while (low < high) {
-
while (low < high && input[high] <= tmp) {
-
high--;
-
}
-
input[low] = input[high];
-
while (low < high && input[low] >= tmp) {
-
low++;
-
}
-
input[high] = input[low];
-
}
-
input[low] = tmp;
-
return low;
-
}
-
// 这里得到的是第k小,自己n-k转换下即可, 或者改下划分函数
-
int findK(int* array, int left, int right, int k) {
-
//printf("%d %d %d\n", left, right, k);
-
int i = partition(array, left, right);
-
int cnt = i - left + 1;
-
if (k == cnt) {
-
return array[i];
-
}
-
else if (k < cnt) {
-
return findK(array, left, i - 1, k);
-
}
-
else if (k > cnt) {
-
return findK(array, i + 1, right, k - cnt);
-
}
-
return 0;
-
}
-
int main()
-
{
-
vector<int> ilist = {9, 5, 8, 7, 3, 6, 2, 1, 4, 0};
-
int arr[10];
-
int n = ilist.size();
-
std::copy(ilist.begin(), ilist.end(), arr);
-
int k = 3;
-
int num = findK(arr, 0, n-1, k);
-
cout << num << endl;
-
system("pause");
-
return 0;
-
}
快排加二分查找:
-
int a[]={7,9,8,5,6,3,2,4,1,0};
-
const int K=6;
-
//解题思路就是利用快速排序,如果得到快速排序一次中间结果之后其所在位置即在
-
int QSort(int* a,int low,int high)
-
{
-
if(low<high)
-
{
-
int start=low,end=high;
-
int key=a[start];
-
while(start<end)
-
{
-
while(start<end&&a[end]<key)
-
{
-
end--;
-
}
-
a[start]=a[end];
-
while(start<end&&a[start]>key)
-
{
-
start++;
-
}
-
a[end]=a[start];
-
}
-
a[start]=key;
-
return start;
-
}
-
return -1;
-
}
-
int main()
-
{
-
int start=0,end=sizeof(a)/sizeof(int)-1;
-
int index=-2;
-
while(index+1!=K)
-
{
-
index=QSort(a,start,end);
-
if(index<K)
-
{
-
start=index+1;
-
}
-
else if(index>K)
-
{
-
end=index-1;
-
}
-
}
-
cout<<a[index]<<"即为所求\n";
-
}
最小堆解法
构造一个大小为k的最小堆,堆中根节点为最小值。如果数组中最大的几个数均在堆中,那么堆中根节点的值就是问题的解。
可以用STL中的优先队列实现,因为优先队列的内部就是最大堆/最小堆实现的。
此解法的时间复杂度O(NlogK),N次logK。但是相比与类快速排序算法,需要额外的存储空间。
-
#include <iostream>
-
#include <vector>
-
using namespace std;
-
void maxHeapify(int* array, int size, int i) {
-
int left = 2 * i + 1;
-
int right = 2 * i + 2;
-
int small = i;
-
if (left < size) {
-
if (array[small] > array[left]) {
-
small = left;
-
}
-
}
-
if (right < size) {
-
if (array[small] > array[right]) {
-
small = right;
-
}
-
}
-
if (small != i) {
-
int temp = array[small];
-
array[small] = array[i];
-
array[i] = temp;
-
maxHeapify(array, size, small);
-
}
-
}
-
void buildHeap(int* array, int size) {
-
for (int i = size - 1; i >= 0; i--) {
-
maxHeapify(array, size, i);
-
}
-
}
-
int findKByHeap(int* array, int n, int k) {
-
buildHeap(array, k);
-
for (int i = k; i < n; i++) {
-
if (array[i] > array[0]) {
-
int temp = array[i];
-
array[i] = array[0];
-
array[0] = temp;
-
maxHeapify(array, k, 0);
-
}
-
}
-
return array[0];
-
}
-
int main()
-
{
-
vector<int> ilist = {9, 5, 8, 7, 3, 6, 2, 1, 4, 0};
-
int arr[10];
-
int n = ilist.size();
-
std::copy(ilist.begin(), ilist.end(), arr);
-
int k = 5;
-
int num = findKByHeap(arr, n, k);
-
cout << num << endl;
-
system("pause");
-
return 0;
-
}