堆-堆排序-TopK

大堆:父节点比左右子孩子大
小堆:父节点比左右子孩子小


大堆向下调整

在这里插入图片描述

向下调整算法

注意结束

  1. 是左右子树超过数组end
  2. 到了合适位置直接break出去

问题:end是数组元素个数还是最后一个元素所在下标?
最后一个元素所在下标

错误代码1、

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

更正代码2

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

最终代码3

//建大堆
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;
        }
                
    }
    
}

大堆向上调整

在这里插入图片描述

向上调整算法

  1. 结束条件:child<=0;
  2. 在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;            
        }
                    
                      
    }
}

建堆-时间复杂度分析

在这里插入图片描述

1、向下建堆

在这里插入图片描述

代码:向下调整算法

 //向下调整
    for(int i=(n-1-1)/2;i>=0;i--)
    {
        AdJustDown(a, n, i);
    }

时间复杂度分析(向下调整)

在这里插入图片描述

2、向上建堆

代码:向上调整算法

 // 向上调整
  for(int i=0;i<sizeof(a)/sizeof(int);i++)
  {
       AdJustUp(a,i);
  }

建堆复杂度分析(向上调整)

在这里插入图片描述


atong知识分享-TopK问题

1、如何在n个数中选出前K大/小的数

2、堆实现

N个数,选出前K大的数(建小堆-小堆堆顶)

分析

建小堆,a[i]大于堆顶,交换向下调整,大的会往下调整到堆底,小数往上冒,当i遍历到N时,堆顶就是第K大的元素

3、时间复杂度分析

  1. 建k个数堆时间复杂度

向下调整建堆K个数:O(K)

  1. 后边数据比较调整

最坏情况,N个数从小到大排,从K+1个数开始,每个数都比堆顶元素大,K个元素有logK层,每个数调整logK次,都调整到堆底时间复杂度为:O((N-K)*logK)

*总体时间复杂度:O(K+(N-K)logK)

4、代码实现

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);
        }
    }
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

芝士就是菜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值