1. 最小堆的调整,插入和删除
一个最小堆,也是完全二叉树,用按层遍历数组表示
(1) 求节点a[n]的子节点的访问方式
(2) 插入一节点的程序 void add_element(int *a, int size, int val);
(3) 删除最小节点的程序
按照数组下标,下标为n的结点,它的子结点下标位2*n+1和2*n+2;
插入结点时,先插入到最后,然后再调整堆;
删除最小结点即删除根结点,先将根结点和最后一个结点交换,再调整对。
#include "stdafx.h"
#include <iostream>
using namespace std;
//往最小堆中插入元素,先插在数组的最后,然后类似于插入排序找到合适位置.
void MinHeapAdd(int *a, int n, int number)
{
a[n] = number;
int i = n;
int j = (i-1)/2;
int tmp = a[i];
while(j>0)
{
if(a[j]<tmp)
break;
else
{
a[i] = a[j];
i = j;
j = (i-1)/2;
}
}
a[i] = tmp;
}
//从第m个开始调整,n为结点总数,类似于插入排序
void MinHeapFixDown(int *a, int m, int n)
{
int i = m;
int j = 2*i+1;
int tmp = a[i];
while(j<n)
{
if((j+1<n)&&a[j]>a[j+1])
j++;
if(a[j]>=tmp)
break;
else
{
a[i] = a[j];
i = j;
j = a*i+1;
}
}
a[i] = tmp;
}
//删除最小结点
void MinHeapDelete(int *a, int n)
{
a[0] = a[n-1];
MinHeapFixDown(a,0,n-1);
}
//初始建堆
void MakeMinHeap(int *a, int n)
{
for(int i=n/2-1; i>=0; --i) //注意
MinHeapFixDown(a,i,n);
}
//堆排序
void HeapSort(int *a, int n)
{
MakeMinHeap(a,n);
for(int i=n-1; i>=1; i--)
{
int tmp = a[0];
a[0] = a[i];
a[i] = tmp;
MinHeapFixDown(a,0,i);
}
}
void main()
{
int a[10] = {36,30,18,40,32,45,22,50};
HeapSort(a,8);
for(int i=0; i<8; ++i)
cout << a[i] << " ";
cout << endl;
int aa[10] = {36,30,18,40,32,45,22,50};
MakeMinHeap(aa,8);
for(int i=0; i<8; ++i)
cout << aa[i] << " ";
cout << endl;
MinHeapAdd(aa,8,35);
for(int i=0; i<9; ++i)
cout << aa[i] << " ";
cout << endl;
MinHeapDelete(aa,9);
for(int i=0; i<8; i++)
cout << aa[i] << " ";
cout << endl;
}
/*
利用堆结构找到数组中最小的k个元素
n个元素的最小堆中,可以先取出堆顶元素得到第1小元素,然后把堆中最后一个元素(较大的元素)上移至堆顶
,成为新的堆顶元素;
对新的堆顶元素逐步下移,下移k次之后,此时堆顶元素已经是我们要找的第2小的元素;
然后,取出这个第2小的元素(堆顶元素),再次把堆中的最后一个元素送到堆顶,又经过k-1次下移之后
(此后下移次数逐步减少,k-2,k-3,...,k=0后算法中断),如此重复k-1趟操作,不断取出的堆顶元素即是
我们要找的最小的k个数.
虽然上述算法中断后整个堆已经不是最小堆了,但是求得的k个最小元素已经满足题目要求了,就是说已经
找到了最小的k个数.
*/
//先对元素数组原地建最小堆,O(n).然后提取k次,但是每次提取时,
//换到顶部的元素只需要下移顶多k次就足够了,下移次数逐次减少.此种方法的复杂度为O(n+k^2)
#include <stdio.h>
#include <stdlib.h>
#define MAXLEN 123456
#define K 100
void HeapAdjust(int array[], int i, int Length)
{
int child, temp;
for(temp=array[i];2*i+1<Length;i=child)
{
child = 2*i+1;
if(child<Length-1 && array[child+1]<array[child])
child++;
if(temp>array[child])
array[i] = array[child];
else
break;
array[child] = temp;
}
}
void Swap(int *a, int *b)
{
*a = *a^*b;
*b = *a^*b;
*a = *a^*b;
}
int GetMin(int array[], int Length, int k)
{
int min = array[0];
Swap(&array[0],&array[Length-1]);
int child,temp;
int i=0, j=k-1;
for(temp=array[0]; j>0 && 2*i+1<Length; --j,i=child)
{
child = 2*i+1;
if(child<Length-1 && array[child+1]<array[child])
child++;
if(temp>array[child])
array[i] = array[child];
else break;
array[child] = temp;
}
return min;
}
void Kmin(int array[], int Lenght, int k)
{
//初始建堆,时间复杂度为O(n)
for(int i=Lenght/2-1; i>0; --i)
HeapAdjust(array,i,Length);
int j=Length;
for(i=k; i>0; --i,--j)
//k次循环,每次循环的复杂度最多为k次交换,复杂度为O(k^2)
{
int min = GetMin(array,j,i);
printf("%d",min);
}
}
int main()
{
int array[MAXLEN];
for(int i=MAXLEN; i>0; --i)
array[MAXLEN-i] = i;
Kmin(array,MAXLEN,K);
return 0;
}