寻找数组中最小的k个数 "最小堆方法"

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;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值