堆结构和堆排序原理及python实现

news/2024/5/19 5:10:42 标签: 数据结构, 排序算法, 堆排序

堆结构

堆结构是一个完全二叉树,将数组中的数字在二叉树从上到下,从左到右进行排列。
若每个父节点的值大于子节点的值则为大顶堆,若每个父节点的值小于子节点的值则为小顶堆。

属性:
  1. 对任意一个node为idx (idx=0为根节点)
    父节点:(idx-1)//2,左节点:(2idx + 1),右节点:(2idx + 2)
  2. 父节点 >=子节点,根节点最大(大顶堆),反之小顶堆

堆排序

堆排序分为建堆和堆调整两个过程。建堆的时间复杂度为O(n),堆调整的时间复杂度为log(n),所以堆排序的时间复杂度为nlog(n)。

建堆过程:
以大顶堆为例,利用数组将元素从上到下, 从左到右依次排列到二叉树中, 此时只是排列还并不堆结构。从最后一个节点的父节点开始调整,直到调整到根节点。调整过程中从当前节点和子节点中选择最大值放到当前节点位置,然后看子节点还需不需要调整,如果需要继续调整子节点到自己的位置。

堆排序过程:
在建立好的大顶堆中,将根节点与最后一个节点进行交换,此时最后一个节点为最大值,然后将根节点的值进行堆调整heapify到自己的位置,此时根节点为第二大值。继续将根节点与倒数第二个节点的值进行交换,在对根节点进行heapify。依次操作下去便可获得堆排序

堆结构python实现

class Heap:

    def __init__(self):
        self.data = []
    
    def __len__(self):
        return len(self.data)
    
    def is_empty(self):
        return len(self.data) == 0
    
    def add(self, item):
        self.data.append(item)
        self.upheap(len(self.data)-1)
    
    def get_max(self):
        if self.is_empty():
            return None
        return self.data[0]
    
    def remove_min(self):
        if self.is_empty():
            return None
        self.swap(0, len(self.data)-1)
        item = self.data.pop()
        self.downheap(0)
        return item
    
    def _parent(self, idx):
        return (idx-1) // 2
    
    def _left(self, idx):
        return (2*idx) + 1
    
    def _right(self, idx):
        return (2*idx) + 2
    
    def swap(self, i, j):
        self.data[i], self.data[j] = self.data[j], self.data[i]
    
    def upheap(self, idx):
        parent = (idx-1) // 2
        if idx > 0 and self.data[idx] > self.data[parent]:
            self.swap(idx, parent)
            self.upheap(parent)
        
    def downheap(self, idx):
        left = 2*idx + 1
        right = 2*idx + 2
        if left < len(self.data) and self.data[left] > self.data[idx]:  # 左节点存在
            large = left
        if right < len(self.data) and self.data[right] > self.data[large]: # 右节点存在
                large = right
        if large != idx:
            self.swap(large, idx)
            self.downheap(large)

堆排序python实现

def heapify(arr, heap_size, idx):
    '''对idx个节点进行heapify, 大顶堆'''
    left = 2*idx + 1
    right = 2*idx + 2
    large = idx
    if left < heap_size and arr[left] > arr[idx]:  # 存在左节点
        large = left
    if right < heap_size and arr[right] > arr[large]:   # 存在右节点
        large = right
    if large != idx:
        arr[large], arr[idx] = arr[idx], arr[large]
        heapify(arr, heap_size, large)


def build_heap(arr):
    '''从最后一个节点的父节点开始,只到根节点'''
    heap_size = len(arr)
    for i in range((heap_size-2)//2, -1, -1):   
        heapify(arr, heap_size, i)

def heap_sort(arr):
    build_heap(arr)  # 构建大顶堆
    for i in range(len(arr)-1, -1, -1):
        arr[0], arr[i] = arr[i], arr[0]  # 交换第一个和最后一个节点,最大值换到最后
        heapify(arr, i, 0)
    return arr

        
if __name__ =='__main__':
    arr = [3, 6, 8, 1, 2, 3, 9, 0, 12, 7]
    print(heap_sort(arr))


http://www.niftyadmin.cn/n/892475.html

相关文章

Java 内存分配浅析

Java程序运行在JVM(Java Virtual Machine&#xff0c;Java虚拟机)上&#xff0c;可以把JVM理解成Java程序和操作系统之间的桥梁&#xff0c;JVM实现了Java的平台无关性&#xff0c;由此可见JVM的重要性。所以在学习Java内存分配原理的时候一定要牢记这一切都是在JVM中进行的&am…

图邻接表,BFS和DFS的python实现

图的邻接表实现 class V:def __init__(self, item):self.id itemself.nbrs {}self.visited Falsedef add_nbr(self, nbr, weight0):self.nbrs[nbr] weightdef get_nbrs(self):return self.nbrs.keys()def get_idx(self):return self.iddef get_weight(self, nbr):return s…

探索设计模式之----适配器模式

适配器模式特点&#xff1a;适配器模式主要解决的问题就是我们要调用的接口类型&#xff0c;无法满足我们新系统的使用需求&#xff0c;这时候&#xff0c;我们需要将旧系统的接口&#xff0c;通过适配器进行转配&#xff0c;达到支持新接口调用的目的。对于这样的要求&#xf…

文件的复制python

import shutil shutil.copy(src_path, tgt_path)src_path: 原文件路径 tgt_path: 目标文件路径

探索设计模式之----代理模式

代理模式是一种非常重要的设计模式&#xff0c;在Java语言中有着广泛的应用&#xff0c;包括Spring AOP的核心设计思想&#xff0c;都和代理模式有密切关系。 代理模式主要分两种&#xff1a;一种是静态代理&#xff0c;一种是动态代理。两种代理方式的实现有着本质的差异。 …

bert预训练模型使用demo

下面是huggingface的bert文件API的调用及简单的使用demo&#xff0c;具体bert文本分类使用可以参考 https://github.com/lyj157175/nlp_projects from pytorch_pretrained import BertModel, BertTokenizer import torch import torch.nn as nn# 加载本地预训练模型文件&#…

美团实习生电面之谈(成功拿到offer)

3月底进行了美团的一次实习生面试&#xff08;Java研发工程师&#xff09;&#xff0c;当时顺利的通过一面&#xff0c;下面是我的一面&#xff1a; 1、CPU由哪些部分组成 2、线程和进程的区别 3、Java类加载机制 4、如何实现一个字符串的反转&#xff08;如abcdef转换成fe…

nn.LSTM层出来的out和hn的关系

import torch import torch.nn as nn单层lstm lstm nn.LSTM(input_size100, hidden_size200, bidirectionalTrue, batch_firstTrue) a torch.randn(32, 512, 100) out, (h, c) lstm(a) print(out.shape) # 32, 512, 400 print(h.shape) # 2, 32, 400 print(out[0, -1, …