算法笔记-堆相关、堆的定义、大小根堆、算法程序实现、堆的算法题、C#写法

本文详细介绍了堆的定义、数学属性,以及大根堆和小根堆的插入、取元素、形成过程。通过C#代码展示了大根堆和小根堆的算法实现,同时探讨了堆排序的原理。此外,还提供了一道运用堆的算法题及其解题思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

内容概述

1,堆结构就是用数组实现的完全二叉树结构
2,完全二叉树中如果每棵子树的最大值都在顶部就是大根堆
3,完全二叉树中如果每棵子树的最小值都在顶部就是小根堆
4,堆结构的heaplnsert与heapify操作
5,堆结构的增大和减少
6,优先级队列结构,就是堆结构

1. 堆的定义

首先需要明确的是,堆是完全二叉树,完全二叉树不一定是堆(因为堆一定是排好序的【大根或者小跟】,完全二叉树就不一定了,不一定是堆)

这里有一篇文章,对堆描述的非常好【点击此处

我们需要知道的是,堆是有大根堆和小根堆的,只有这两种特殊的完全二叉树才能称为堆

大根堆是指,每个根节点一定比其子节点大;小根堆是指,每个根节点一定比其子节点小
比方:
在这里插入图片描述
这个就是大根堆

根据这个特性,我们可以很快的拿到最大值或者最小值(均在根节点处)

但是,大根堆或者小根堆的数组,不一定是已经有序的,想变成有序的数组,还需要继续堆排序

2. 堆的数学属性

i是数组的某元素下标,现在需要知道该元素在堆中的父叶或者左子叶、右子叶的位置

父叶:parent(i) = (i - 1)/2
左子叶:left(i) = 2i + 1
右子叶:right(i) = 2i + 2

这是用的最多的堆的数学属性

3. 大根堆的插入

如果需要在一个大根堆里插入一个数,让其继续变成大根堆,应该怎么实现呢?
这就是HeapInsert过程

HeapInsert过程
当往一个大根堆里放入数的时候,先通过公式父叶:parent(i) = (i - 1)/2找到该元素对应的父节点,然后将该元素与父叶比较,如果该元素大,则与父元素交换(后面如果又比该父叶的父叶大,则继续交换);如果父元素大,则该元素不掉换位置

程序:

public static void HeapInsert(int[] arr, int index)
        {
   
        //判断插入的元素与其父叶的大小,大则交换
            while (arr[index] > arr[(index - 1) / 2])
            {
   
                Swap(arr, index, (index - 1) / 2);//交换元素的自定义方法
                index = (index - 1) / 2;//下标换为其父叶坐标,继续判定
            }
        }

4. 大根堆的取元素

因为堆的根节点要么最大,要么最小,经常需要取出其元素的值,然后重新排序成大根堆的结构,这个过程叫做Heapify

Heapify过程:
在某个堆中,取出某根节点(父叶),方法是将该元素与堆数组中最后一个元素互换后,比较交换后元素与根节点的左、右节点的最大值比较,叶大,则与叶交换;叶小,则不变

程序:

//取大根堆的某一元素后,把剩下的元素依然组成大根堆
//方法中的参数含义:arr-数组;index-已经交换后的元素下标;size-数组的长度
        public static void Heapity(int[] arr, int index, int size)
        {
   
        	//左子叶的下标
            int left = index * 2 + 1;
            //如果该父叶的左子叶存在,那么继续,不存在就跳出
            while (left < size)
            {
   
            	//右子叶存在,且找出左、右子叶的最大值的下标
                int largest = left + 1 < size && arr[left + 1] > arr[left] ? left + 1 : left;
                //将该下标对应的元素与父子叶对应的元素比较大小,当该下标对应的元素大于父子叶对应的元素时,交换元素
                argest = arr[largest] > arr[index] ? largest : index;
                //当该下标对应的元素小于或者等于父子叶对应的元素时,跳出循环
                if (largest == index)
                {
   
                    break;
                }
                //交换父子叶元素与最大值子叶下标元素的值
                Swap(arr, largest, index);
                //继续判断,此时的index下标变成刚刚的最大的子叶元素下标
                index = largest;
                //重新给左子叶赋值
                left = index * 2 + 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值