首页 > 其他分享 >堆结构介绍

堆结构介绍

时间:2024-11-24 20:31:25浏览次数:9  
标签:index arr int 介绍 func data 节点 结构

目录

数据结构概述

  • 堆一般使用二叉树来表示,堆是一棵完全二叉树
  • 堆有两种类型:最大堆和最小堆。最大堆:每个节点的值都大于或等于其左右子节点的值。最小堆:每个节点的值都小于或等于其左右子节点的值。
  • 堆能够快速的获取最大值或最小值。

数据结构适用条件

  • 主要是用实现优先队列。
  • 可以用来实现排序。

算法实现

最大堆的基本操作

package main

type MaxHeap struct {
    data []int // 存储堆元素的切片
}

// NewMaxHeap 创建一个新的最大堆,并对初始元素进行堆化
func NewMaxHeap(elem []int) *MaxHeap {
    n := len(elem)
    // 避免直接修改传入的切片,因为切片可能会在外部被修改
    data := make([]int, n)
    copy(data, elem)

    maxHeap := &MaxHeap{
        data: data,
    }

    // 从最后一个非叶子节点开始,依次向上进行下沉操作,构建最大堆
    for i := parent(n - 1); i >= 0; i-- {
        maxHeap.siftDown(i)
    }
    return maxHeap
}

// IsEmpty 判断堆是否为空
func (h *MaxHeap) IsEmpty() bool {
    return len(h.data) == 0
}

// Size 返回堆中元素的数量
func (h *MaxHeap) Size() int {
    return len(h.data)
}

// parent 返回父节点的索引
func parent(index int) int {
    return (index - 1) / 2
}

// leftChild 返回左子节点的索引
func leftChild(index int) int {
    return 2*index + 1
}

// rightChild 返回右子节点的索引
func rightChild(index int) int {
    return 2*index + 2
}

// Add 向堆中添加一个元素,并保持堆的性质
func (h *MaxHeap) Add(e int) {
    h.data = append(h.data, e)
    h.siftUp(len(h.data) - 1) // 将新添加的元素上浮到正确的位置
}

// siftUp 上浮操作,将索引为 k 的元素上移以维持堆的性质
func (h *MaxHeap) siftUp(k int) {
    for k > 0 && h.data[parent(k)] < h.data[k] {
        // 如果当前节点大于其父节点,交换它们的值
        h.data[parent(k)], h.data[k] = h.data[k], h.data[parent(k)]
        k = parent(k) // 继续向上比较
    }
}

// FindMax 返回堆中的最大元素(即堆顶元素)
func (h *MaxHeap) FindMax() int {
    if h.IsEmpty() {
        panic("Cannot FindMax when heap is empty.")
    }
    return h.data[0]
}

// ExtractMax 取出并返回堆中的最大元素,然后重新调整堆
func (h *MaxHeap) ExtractMax() int {
    max := h.FindMax() // 堆顶元素即为最大值
    n := len(h.data) - 1
    h.data[0] = h.data[n]     // 将最后一个元素移动到堆顶
    h.data = h.data[:n]       // 删除最后一个元素
    h.siftDown(0)             // 从堆顶开始下沉,恢复堆的性质
    return max
}

// siftDown 下沉操作,将索引为 k 的元素下移以维持堆的性质
func (h *MaxHeap) siftDown(k int) {
    n := len(h.data)
    for leftChild(k) < n {
        j := leftChild(k) // 左子节点索引
        // 如果右子节点存在且大于左子节点,则用右子节点进行比较
        if j+1 < n && h.data[j+1] > h.data[j] {
            j = rightChild(k)
        }

        // 如果当前节点大于等于子节点中最大的,堆性质已满足,退出循环
        if h.data[k] >= h.data[j] {
            break
        }
        // 否则,交换当前节点与子节点中较大的一个
        h.data[k], h.data[j] = h.data[j], h.data[k]
        k = j // 继续向下比较
    }
}

最大堆排序

package main

import "fmt"

type MaxHeap struct {
    data []int
}

// Heapify 建立最大堆
func Heapify(arr []int) {
    n := len(arr)
    // 从最后一个非叶子节点开始,依次执行下沉操作
    for i := parent(n - 1); i >= 0; i-- {
        siftDown(arr, n, i)
    }
}

// parent 返回父节点的索引
func parent(index int) int {
    return (index - 1) / 2
}

// leftChild 返回左子节点的索引
func leftChild(index int) int {
    return 2*index + 1
}

// rightChild 返回右子节点的索引
func rightChild(index int) int {
    return 2*index + 2
}

// siftDown 对节点进行下沉操作,维持堆的性质
func siftDown(arr []int, n, k int) {
    for leftChild(k) < n {
        j := leftChild(k)
        // 如果右子节点存在且大于左子节点,使用右子节点
        if j+1 < n && arr[j+1] > arr[j] {
            j = rightChild(k)
        }
        // 如果当前节点大于等于子节点中最大的,结束循环
        if arr[k] >= arr[j] {
            break
        }
        // 交换当前节点与子节点中较大的一个
        arr[k], arr[j] = arr[j], arr[k]
        // 继续向下比较
        k = j
    }
}

// HeapSort 原地堆排序算法
func HeapSort(arr []int) {
    n := len(arr)
    // 建立最大堆
    Heapify(arr)
    // 依次取出堆顶元素(最大值)到数组末尾
    for i := n - 1; i > 0; i-- {
        // 将堆顶元素与当前堆的最后一个元素交换
        arr[0], arr[i] = arr[i], arr[0]
        // 调整堆,使其满足最大堆性质
        siftDown(arr, i, 0) // 注意,此时堆的大小为 i
    }
}

func main() {
    arr := []int{3, 5, 1, 10, 2, 7}
    HeapSort(arr)
    fmt.Println(arr) // 输出: [1 2 3 5 7 10]
}

LeetCode 题目

标签:index,arr,int,介绍,func,data,节点,结构
From: https://blog.csdn.net/Cloud_Mount/article/details/144012961

相关文章

  • Android Studio 介绍
    AndroidStudio是Android应用的开发工具,由谷歌公司在2013年5月推出,AndroidStudio基于IntelliJIDEA演变而来,比Eclipse更加方便易用,运行速度也较快.AndroidStudio出现之前,使用Eclipse开发Android应用.虽然Android基于Linux内核,但是Android手......
  • Python内置数据结构:列表篇:【】,list函数创建。列表创建常见遇到问题,索引,列表增删改查,常
    介绍:列表元组字典集合列表: 方括号【】和list函数是列表最常用的两种定义方式。我们暂且称列表内的东西为元素,列表内的元素以逗号分隔开。列表的初始化:空列表,有数值是列表的两种初始化情况。使用方括号创建列表:【】a=[]#创建了一个空列表并将其赋值给了a我们可以称a为一......
  • MySQL中查看表结构
    1.使用DESCRIBE或DESC命令DESCRIBE(或其简写DESC)是最简单和最直接的方法,可以显示表的列信息。语法:DESCRIBEtable_name;--或者DESCtable_name;示例:假设有一个名为employees的表,可以这样查看其结构:DESCRIBEemployees;--或者DESCemployees;2.使用S......
  • 探索计算机网络体系结构的奥秘
    在当今数字化的时代,计算机网络已成为我们生活和工作中不可或缺的一部分。而理解计算机网络体系结构则是深入掌握这一领域的关键。 计算机网络体系结构是指计算机网络各层及其协议的集合。它为网络通信提供了一种标准化的框架,使得不同的设备和系统能够相互通信和协同工作。......
  • 计算机体系结构 胡伟武 课后习题期末题库重点选集解析Ⅲ(8-12章)
    第8章转移预测第一题转移猜测结构图1.附表8.1是转移猜测的Yeh和Patt分类中根据转移历史表(BHT)和模式历史表(PHT)的不同组合形成的转移猜测种类。PC中用来索引BHT表的位数为低6位,索引PHT表的位数为低8位,BHT表每项9位,请画出SAs转移猜测的结构图,说明其基......
  • 三、jmeter几类线程组介绍
    基本线程组(BasicThreadGroup)特点:这是最常用的线程组类型,它提供了基本的参数设置来模拟用户行为。可以简单直观地设置线程数(即并发用户数)、准备时长(Ramp-UpPeriod)、循环次数和延迟时间。参数含义及应用场景:线程数:用于确定模拟的并发用户数量。例如,在测试......
  • 【数据结构】时间和空间复杂度
    时间和空间复杂度1.如何衡量一个算法的好坏2.算法效率3.时间复杂度3.1时间复杂度的概念3.2大O的渐进表示法3.3推导大O阶方法3.4常见时间复杂度计算举例3.空间复杂度【本节目标】算法效率时间复杂度空间复杂度1.如何衡量一个算法的好坏下面求斐波那契数......
  • HTML学生个人网站作业设计:动漫网站设计——樱桃小丸子(6页) HTML+CSS+JavaScript 简单
    一、......
  • 第54篇 Redis简单介绍
    前言Redis,作为一种开源的、基于内存且支持持久化的键值存储系统,以其卓越的性能、丰富灵活的数据结构和高度可扩展性在全球范围内广受欢迎。Redis不仅提供了一种简单直观的方式来存储和检索数据,更因其支持数据结构如字符串、哈希、列表、集合、有序集合等多种类型,使得其在众多场景......
  • 211.大学生HTML5期末大作业 —【鲸鱼动物介绍精品网页】 Web前端网页制作 html5+css3
    目录一、更多推荐二、网页简介三、网页文件四、网页效果五、代码展示1.html2.CSS六、总结1.简洁实用2.使用方便3.整体性好4.形象突出5.交互式强一、更多推荐欢迎来到我的CSDN主页!您的支持是我创作的动力!Web前端网页制作、网页完整代码、大学生期末大作业案例......