大堆:父节点比左右子孩子大
小堆:父节点比左右子孩子小
注意结束
- 是左右子树超过数组end
- 到了合适位置直接break出去
问题:end是数组元素个数还是最后一个元素所在下标?
最后一个元素所在下标
void AdjustDown(int* a, int n)
{
assert(a);
int parent=0;
int left=2*parent+1;
int right=left+1;
while(left<end)
{
left=2*parent+1;
right=left+1;
if(a[left]>a[right])
{
Swap(&a[parent],&a[left]);
parent=left;
}
else
{
Swap(&a[parent],&a[right]);
parent=right;
}
}
}
void AdjustDown(int* a, int n)
{
assert(a);
int parent=0,left=0,right=0;
while(left<end)
{
left=2*parent+1;
right=left+1;
if(a[left]>a[right])
{
if(a[parent]<a[left])
{
Swap(&a[parent],&a[left]);
parent=left;
}
else
{
break;
}
}
else
{
if(a[parent]<a[right])
{
Swap(&a[parent],&a[right]);
parent=right;
}
else
{
break;
}
}
}
}
//建大堆
void AdjustDown(int* a, int n, int parent)
{
int child=parent*2+1;
while(child<end)
{
if(child+1<n&&a[child+1]>a[child+1])
{
child=child+1;
}
if(a[child]>a[parent])
{
Swap[&a[parent],&a[child]);
parent=child;
child=2*parent+1;
}
else
{
break;
}
}
}
- 结束条件:child<=0;
- 在end处插入一个元素,与父节点向上比较,孩子大就调换,孩子不大于父亲就break
void AdJustUp(int* a, int child)
{
int parent=(child-1)/2;
while(child>0)
{
if(a[child]>a[parent])
{
Swap[&a[child],&a[parent]);
child=parent;
parent=(child-1)/2;
}
else
{
break;
}
}
}
//向下调整
for(int i=(n-1-1)/2;i>=0;i--)
{
AdJustDown(a, n, i);
}
// 向上调整
for(int i=0;i<sizeof(a)/sizeof(int);i++)
{
AdJustUp(a,i);
}
N个数,选出前K大的数(建小堆-小堆堆顶)
建小堆,a[i]大于堆顶,交换向下调整,大的会往下调整到堆底,小数往上冒,当i遍历到N时,堆顶就是第K大的元素
向下调整建堆K个数:O(K)
最坏情况,N个数从小到大排,从K+1个数开始,每个数都比堆顶元素大,K个元素有logK层,每个数调整logK次,都调整到堆底时间复杂度为:O((N-K)*logK)
*总体时间复杂度:O(K+(N-K)logK)
void TestTopK(int* a, int n, int k)
{
//建堆K个数 a[k-1] 它的父亲是(k-1-1)/2 向下调整建堆
for(int i=(k-1-1)/2;i>=0;i--)
{
AdJustDown(a, k, i);
}
/*
若不破坏原数组
int* MinHeap = (int*)malloc(sizeof(int)*k);
assert(MinHeap);
for (int i = 0; i < k; ++i)
{
MinHeap[i] = a[i];
}
for (int i = (k - 1 - 1) / 2; i >= 0; --i)
{
AdjustDwon(kMinHeap, k, i);
}
*/
for(int i=k+1; i<n, i++)
{
if(a[i]>a[0])
{
Swap(&a[0], &a[i]);
AdJustDown(a, k, 0);
}
}
}