一文学会数据结构-堆

一文学会数据结构-堆

什么是堆

在计算机科学中,堆是一个特殊的树状数据结构。堆通常有如下几个特性:

  1. 堆是完全二叉树;
  2. 堆中每个节点的值都大于或等于(小于或等于)其子节点的值,这个取值规则称为堆的“属性”;
  3. 堆顶元素(即根节点)总是为最大值或最小值。

堆的种类

堆分为小根堆和大根堆两种。小根堆要求每个节点的值都不大于其父节点的值,即A[PARENT[i]] <= A[i];大根堆要求每个节点的值都不小于其父节点的值,即A[PARENT[i]] >= A[i]。

优先队列

堆可以用于组成优先队列。优先队列是一种数据结构,其中每个元素有一个“优先级”或“关键值”,优先级高的元素先被处理。当然,堆并不是唯一可以组成优先队列的数据结构,但堆的效率要高得多。

实现堆

堆是通过数组实现的。令i表示二叉树中节点的序号,A[i]表示存储在该节点的元素。

  1. 父节点的位置为 Parent(i) = floor(i/2)
  2. 左子节点的位置为 Left(i) = 2i
  3. 右子节点的位置为 Right(i) = 2i + 1

实现中我们可以使用数组存储堆,这样可以快速寻找到每个节点的父节点和子节点。

堆的操作

下面介绍堆的几个常见操作:

堆化(Heapify)

将i结点以下的堆整体调整成最大堆或最小堆,时间复杂度为O(logN)。

# 以大根堆为例
def heapify(arr, n, i):
    # 初始化最大值位置
    largest = i 
    left = 2 * i + 1
    right = 2 * i + 2

    # 如果左子节点的值大于父节点的值,更新最大值位置
    if left < n and arr[i] < arr[left]:
        largest = left

    # 如果右子节点的值大于最大值位置节点的值,更新最大值位置
    if right < n and arr[largest] < arr[right]:
        largest = right

    # 如果最大值位置不是父节点位置,则交换这两个节点的值,并递归调用heapify
    if largest != i:
        arr[i], arr[largest] = arr[largest], arr[i]
        heapify(arr, n, largest)

建堆

通过对所有元素进行一次heapify操作实现,建堆的时间复杂度为O(n)。

def build_heap(arr, n):
    # 从最后一个非叶子节点开始heapify
    for i in range(int(n / 2) - 1, -1, -1):
        heapify(arr, n, i)

插入(Insertion)

将新元素插入到堆中,保证堆的属性。时间复杂度为O(logN)。

def insert(arr, element):
    arr.append(element)
    i = len(arr) - 1
    p = int((i - 1) / 2)
    while i > 0 and arr[p] < arr[i]:
        arr[p], arr[i] = arr[i], arr[p]
        i = p
        p = int((i - 1) / 2)

删除堆顶元素(Remove)

删除堆顶元素并返回其值,时间复杂度为O(logN)。

def remove(arr):
    n = len(arr)
    # 如果堆为空,则返回None
    if n == 0:
        return None
    # 如果堆中只有一个元素,则直接返回该元素
    if n == 1:
        return arr.pop()
    # 弹出堆顶元素,并将末尾元素移动到堆顶
    top = arr[0]
    arr[0] = arr.pop()
    n = len(arr)
    # 对新的堆顶元素进行一次heapify操作,使得剩余元素保持堆的属性
    heapify(arr, n, 0)
    return top

示例

示例1

给定数组 [3, 2, 1, 6, 5, 4],按升序排列后的结果为 [1, 2, 3, 4, 5, 6]。下面是一个Python实现:

# 堆排序
def heap_sort(arr):
    # 首先将数组构建为最大堆
    build_heap(arr, len(arr))
    # 将最大的元素交换到数组末尾,并缩小堆的范围
    for i in range(len(arr) - 1, 0, -1):
        arr[i], arr[0] = arr[0], arr[i]
        heapify(arr, i, 0)

arr = [3, 2, 1, 6, 5, 4]
heap_sort(arr)
print(arr)

输出: [1, 2, 3, 4, 5, 6]

示例2

使用堆来解决“TOP K 问题”,即在一个无序的整数数组中,找到最大的K个数。下面是一个Python实现:

import heapq

def top_k(arr, k):
    # 取前K个数,建立一个小根堆
    heap = arr[:k]
    heapq.heapify(heap)
    # 对于剩下的元素,如果比堆顶元素大,则弹出堆顶,并将该元素压入堆中
    for element in arr[k:]:
        if element > heap[0]:
            heapq.heappop(heap)
            heapq.heappush(heap, element)
    # 返回堆中的元素,即为前K大的数
    return heap

arr = [4, 3, 6, 5, 9, 8]
print(top_k(arr, 3)) # 输出: [6, 8, 9]

输出 [6, 8, 9],为原数组中最大的三个数。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:一文学会数据结构-堆 - Python技术站

(0)
上一篇 2023年5月17日
下一篇 2023年5月17日

相关文章

  • C语言实题讲解快速掌握单链表上

    C语言实题讲解快速掌握单链表 什么是单链表? 单链表是一种链式存储的线性数据结构,它由一系列称为节点的组成。每个节点都包括两个部分:数据域和指针域。指针域指示了下一个节点的地址,因此,我们可以通过遍历链表的方式访问所有节点。 单链表的操作 创建一个单链表 我们可以通过以下步骤来创建一个单链表:1. 定义单链表的节点结构体,包括数据域和指针域。2. 定义一个指…

    数据结构 2023年5月17日
    00
  • 【ACM算法竞赛日常训练】DAY16【奇♂妙拆分】【区区区间间间】【小AA的数列】数学 | 位运算 | 前缀和

    DAY16共3题: 奇♂妙拆分(简单数学) 区区区间间间(单调栈) 小AA的数列(位运算dp) ? 作者:Eriktse? 简介:19岁,211计算机在读,现役ACM银牌选手?力争以通俗易懂的方式讲解算法!❤️欢迎关注我,一起交流C++/Python算法。(优质好文持续更新中……)?? 阅读原文获得更好阅读体验:https://www.eriktse.com…

    算法与数据结构 2023年4月20日
    00
  • 中国剩余定理(CRT)学习笔记

    约定 \(A\perp B\) 表示 \(\gcd(A,B)=1\)。 \(A\mid B\) 表示 \(B\equiv 0\pmod{A}(A\neq0)\)。 引入 考虑以下这道题: 有物不知其數,三三數之剩二,五五數之剩三,七七數之剩二。 問物幾何?—— 《孫子算經》 也就是说,求出下列关于 \(x\) 方程组的最小整数解: \[\begin{case…

    算法与数据结构 2023年4月30日
    00
  • 详解Java集合中的基本数据结构

    详解Java集合中的基本数据结构 Java语言提供了丰富的集合框架,可以帮助我们高效地管理和操作数据。在这个库中,最基本的数据结构有数组、列表、映射和集合。本文将详细讲解Java集合中的基本数据结构。 数组 数组是Java中最基本的数据结构,它可以存储同一种数据类型的多个元素。在Java中,数组属于对象类型。可以通过以下方式来声明一个数组: int[] ar…

    数据结构 2023年5月17日
    00
  • C++深入分析讲解链表

    C++深入分析讲解链表 链表概述 链表是数据结构中最基本和重要的一种,它的实现可以分为链表的节点和链表的指针。每个节点都记录着链表中的一个元素,并带有一个指向下一个节点的指针,这样就可以通过遍历指针,达到遍历链表的目的。 链表数据结构 在C++中,链表可以通过结构体或者类来实现,比如以下这个结构体实现的单向链表: struct Node { int data…

    数据结构 2023年5月17日
    00
  • python算法与数据结构朋友圈与水杯实验题分析实例

    让我来详细讲解一下“python算法与数据结构朋友圈与水杯实验题分析实例”的完整攻略。 1. 前言 本文将分享两个Python的算法与数据结构问题,即朋友圈和水杯实验题。我们将分别介绍问题的背景、解题思路和代码实现。 2. 朋友圈问题 2.1 背景 给定一个M*N的矩阵,矩阵中的每个元素都是1或0。如果矩阵中的1元素相邻,即水平、垂直或对角线相邻,则将这些元…

    数据结构 2023年5月17日
    00
  • C语言数据结构顺序表中的增删改(尾插尾删)教程示例详解

    C语言数据结构顺序表中的增删改(尾插尾删)教程示例详解 什么是顺序表 顺序表是一种线性表,它通过一块连续的存储空间来存储数据。顺序表中的数据元素排列在物理存储空间上也是连续的,每个元素占用一个固定的位置和大小,并且使用下标来访问。 顺序表的定义 下面是以int类型为例的一个简单顺序表的定义: #define SIZE 50 typedef struct { …

    数据结构 2023年5月17日
    00
  • Java数据结构的十大排序

    Java数据结构的十大排序攻略 简介 在计算机科学中,排序算法是一种将一串数据按照特定顺序进行排列的方法,其中常见的排序算法有很多种,不同的算法适用于不同的数据类型和数据规模。Java是一种常见的编程语言,也提供了很多实现排序算法的类和方法。 本文将介绍Java数据结构的十大排序算法,分别为:插入排序、希尔排序、选择排序、冒泡排序、快速排序、归并排序、堆排序…

    数据结构 2023年5月17日
    00
合作推广
合作推广
分享本页
返回顶部