由于第一次写博客的狼狈(写了一堆话,忘了保存,导致重写),接下来写准备以(题目-分析-代码)的形式去写。
题目一:寻找一组数据中第K大的数
分析:
题目描述很简单,完全可以将所有的数据从大到小进行排序,选取第K个数,便可以解决我们的问题,这样的话,时间复杂度就将取决于我们排序算法的时间复杂度。排序里,快排和堆排都是不错的选择,时间复杂度o(NlogN)
但是其实题目一并没有要求我们要把所有数据有序啊,直接粗暴对所有数据进行排肯定效率不是最佳。
既然只找第K大的数,我们只需找到最大的K个数中最小的数!
K个节点的小根堆的根结点,正好符合我们的要求。
至于如何确最大K个数,我们可以直接选取,给的数据的前K个数,建一个小根堆,从K+1个元素开始到最后一个元素,将它与前面排序最小的元素进行比较,如果小于,不做处理,大于的话,把它与最小的元素交换,重新排序。当所有元素处理过后,我们便得到一个有最大K个的小根堆,选取他们的最小值(根结点),题目便解决了。
按照我们上边的方法,我最多执行(N-K+1)次K个元素的堆排,时间复杂度o((N-K+1)logK),当N>>K的时候近似o(NlogK)
代码
- 建堆
//调整堆
template<typename ElemType> void AdjustHeap(ElemType *array,const int &index,int end)
{
bool flag = true;
int temp;
int begin = index;
while (index-1+(begin-index+1)* 2 <= end&&flag)
{
if (array[begin] > array[begin * 2])
{
temp = begin * 2;
}
else
{
temp = begin;
}
if (begin * 2 + 1 <= end)
{
if (array[begin * 2 + 1] <array[begin * 2])
{
temp = begin * 2 + 1;
}
}
if (begin == temp)
{
flag = false;
}
else
{
swap(array,begin, temp);
begin = temp;
}
}
}
//建堆
template<typename ElemType> void CreateHeap(ElemType *array,const int &begin,const int &end)
{
int distance = end - begin;
for (int i = begin + distance / 2+1; i >= begin; i--)
{
AdjustHeap(array,i,end);
}
}
//交换数据
template<typename ElemType> void swap(ElemType *array, const int index1, const int index2)
{
array[index1] = array[index1] ^ array[index2];
array[index2] = array[index1] ^ array[index2];
array[index1] = array[index1] ^ array[index2];
}
2.选取第K大的数
#include "HeapSort2.0.h"
#include <iostream>
#include <cstdlib>
/// 选取数据中第K大的数
/// @param elem 储存数据的数据指针
/// @param n 数据量
/// @param k 选取的第K大的数
/// @param begin 数据储存开始的索引
/// @return 第K大的数
template<typename ElemType> ElemType SelectKMaxNum(ElemType *elem,int n,int k,int begin)
{
CreateHeap(elem, begin, k+begin-1);
for (int i = k + 1; i <= n; i++)
{
if (elem[begin] < elem[i])
swap(elem, begin, i);
AdjustHeap(elem, begin, k);
}
return elem[begin];
}
int main()
{
//数据开始的索引为1
int elem[11] = { 0,12,15,89,3,64,8,9,6,3,2 };
std::cout <<SelectKMaxNum(elem,10,3,1)<< std::endl;
std::system("pause");
}
运行结果:
: