/*
DJ.W 2013.1.3
算法描述:找出一无序整型数组arr[n]中最小的前k个数
算法思路:为k个元素建一个大顶堆min[k],初始化为数组arr的前k个元素
调整这k个元素使其满足大顶堆性质
此时min[0]为大顶堆中最大的元素,依次用arr[j](k<=j<n)与min[0]相比较
如果arr[j]小于min[0] 则将min[0]换为arr[j] 并调整大顶堆 继续向后比较
最终min[k]即为所求
算法复杂度:初始建立k个元素的大顶堆复杂度O(k) 之后比较和调整复杂度O(n-k+(n-k)*lgk)
即算法复杂度为O(n+(n-k)*lgk)
*/
#include<iostream>
using namespace std;
/*
堆调整算法 从pos出开始向下调整 使得以pos为根的子树满足大顶堆性质
前提是pos的孩子子树已经满足大顶堆性质
*/
void ShiftDown(int*arr, int pos, int maxIndex)
{
//调整算法迭代版
int temp = arr[pos];
for (int child = 2*pos+1; child<=maxIndex; child = child*2+1)
{
//使child指向两个子节点中大的那一个
if (child<maxIndex && arr[child]<arr[child+1])
++child;
//如果子节点比父节点的值大 则交换并继续向下调整
if (arr[child] > temp)
{
arr[pos] = arr[child];
pos = child;
}
else
break;
}
arr[pos] = temp;
//调整算法递归版
/*
int leftchild = 2*pos+1;
int rightchild = 2*pos+2;
int maxchild;
if (leftchild > maxIndex)
return;
//得到值更大的孩子的下标
if (leftchild<maxIndex && arr[leftchild] < arr[rightchild])
maxchild = rightchild;
else
maxchild = leftchild;
//如果孩子中最大的值比pos的值大 则替换并继续调整
if (arr[maxchild] > arr[pos])
{
int temp = arr[maxchild];
arr[maxchild] = arr[pos];
arr[pos] = temp;
ShiftDown(arr, maxchild, maxIndex);
}
*/
}
bool MinK(int* arr, int size, int k, int* &pRet)
{
if (k > size)
return false;
pRet = new int[k];
//初始化堆
for (int i=0; i<k; i++)
pRet[i] = arr[i];
//调整为大顶堆
for (int j=(k-1)/2; j>=0; j--)
ShiftDown(pRet, j, k);
//依次用arr[k...n-1]和堆中最大元素比较
for (i=k; i<size; i++)
{
//如果arr[i]更小 则更新pRet[0] 调整堆
if (arr[i] < pRet[0])
{
pRet[0] = arr[i];
ShiftDown(pRet, 0, k-1);
}
}
return true;
}
int main()
{
int a[6] = {4, 1, 5, 2, 3, 0};
int* pMinK = NULL;
MinK(a, 6, 3, pMinK);
cout<<"原数组为: "<<endl;
for (int i=0; i<6; i++)
cout<<a[i]<<" ";
cout<<endl;
cout<<"最小的3个数为"<<endl;
for (i=0; i<3; i++)
cout<<pMinK[i]<<" ";
cout<<endl;
delete []pMinK;
return 0;
}
找出无序数组中最小的前k个数
最新推荐文章于 2023-04-08 19:43:37 发布