用堆排序寻找数组中最大的K个数
[cpp]
/***********************************************************************************
堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。
堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:
即子结点的键值或索引总是小于(或者大于)它的父节点。
通常堆是通过一维数组来实现的。在起始数组为 0 的情形中:
父节点i的左子节点在位置 (2*i+1);
父节点i的右子节点在位置 (2*i+2);
子节点i的父节点在位置 floor((i-1)/2);
堆的操作
在堆的数据结构中,堆中的最大值总是位于根节点。堆中定义以下几种操作:
最大堆调整(Min_Heapify):将堆的末端子结点作调整,使得子结点永远小于父结点
创建最大堆(Build_Min_Heap):将堆所有数据重新排序
注:堆排序不是一种稳定排序。
用小根堆得办法寻找最大的K个数
用容量为K的最小堆来存储最大的K个数。最小堆的堆顶元素就是最大K个数中的最小的一个。
每次扫描一个数据X,如果X比堆顶元素Y小,则不需要改变原来的堆。如果X比堆顶元素大,
那么用X替换堆顶元素Y,在替换之后,X可能破坏了最小堆的结构,需要调整堆来维持堆的性质。
调整过程时间复杂度为O(logK)。 全部的时间复杂度为O(N*logK)。
这种方法当数据量比较大的时候,比较方便。因为对所有的数据只会遍历一次,
*************************************************************************************/
#include <cmath>
#include<cstdlib>
#include<time.h>
#include<cstdio>
#include<iostream>
using namespace std;
//产生随机数组
void Random(int a[],int n)
{
int i=0;
srand( (unsigned)time( NULL ) );
while(i<n)
{
a[i++]=rand()/999;
}
}
void print(int a[], int len)
{
int i;
for (i = 0; i < len; i++)
printf("%6d ", a[i]);
printf("\n");
}
int parent(int);
int left(int);
int right(int);
void Min_Heapify(int [], int, int);
void Build_Min_Heap(int A[],int size);
void HeapSort(int [], int);
/*求父亲*/
int parent(int i)
{
return (int)floor((i - 1) / 2);
}
/*求左孩子*/
int left(int i)
{
return (2 * i + 1);
}
/*求右孩子*/
int right(int i)
{
return (2 * i + 2);
}
/*调整堆使其满足堆得性质*/
void Min_Heapify(int A[], int i, int heap_size)
{
int l = left(i);
int r = right(i);
int least;
int temp;
/*找到父亲 左孩子 右孩子 之间的最大值*/
if(l < heap_size && A[l] < A[i])
{
least = l;
}
else
{
least = i;
}
if(r < heap_size && A[r] < A[least])
{
least = r;
}
/*如果父亲不是最大的,则把父亲和两个孩子的较大值交换*/
if(least != i)
{
temp = A[i];
A[i] = A[least];
A[least] = temp;
/*交换之后破坏了较大孩子的堆得性质,对其进行调整*/
Min_Heapify(A, least, heap_size);
}
}
/*简历大顶堆*/
void Build_Min_Heap(int A[],int size)
{
/* 因为数组A[0]要存放数据 所以左孩子为2*i+1 右孩子为 2*i+2 */
/*取最后一个飞叶子节点 即堆顶 根节点
0 1 2 ->mid=1=3/2 n/2
0 1 2 3 ->mid=2=4/2 n/2
0 1 2 3 4 ->mid=2=5/2 n/2
0 1 2 3 4 5 ->mid=3=6/2 n/2 取中间元素偏右的为根节点使其成为完全二叉树
*/
int begin = size/2 ; // 堆顶元素
for(int i = begin; i >= 0; i--)
{
Min_Heapify(A, i, size);
}
}
/*堆排序开始*/
void HeapSort(int A[], int heap_size)
{
Build_Min_Heap(A,heap_size);
//建立大顶堆之后 堆顶已经是所有元素中最大的了
int temp;
//a[0]是数组的第一个元素 a[heap_size - 1]是数组的最后一个元素
/*将堆顶依次和最后一个叶子节点交换*/
for(int i = heap_size - 1; i >= 0; i--)
{
temp = A[0];
A[0] = A[i];
A[i] = temp;
//交换之后破坏了堆得性质 重新调整
Min_Heapify(A, 0, i); //i 是元素个数 每交换依次元素就少一个
}
}
void TopK(int arr[],int n,int K)
{
if(n<K)
{
cout<<"error"<<endl;
return;
}
int *heap=new int[K];
//随机将前K个数装入数组构建小顶堆
for(int i=0;i<K;i++)
{
heap[i]=arr[i];
}
Build_Min_Heap(heap,K);//建立最小堆
//从生下的数中找比小顶堆堆顶大的数并与堆顶交换(直接放在堆顶位置不交换效率更高)
for(int i=K;i<n;i++)
{
if(arr[i]>heap[0])
{
heap[0]=arr[i];
//破坏了最小对的性质 对最小对进行调整
Min_Heapify(heap,0,K);
}
}
 
补充:软件开发 , C++ ,