zoukankan      html  css  js  c++  java
  • 一、什么是堆
    1. 定义
    设有n个数据元素组成的序列{a1, a2, ..., an},这些数据元素是一棵完全二叉树中的节点,如果对于所有节点,父节点数据总是大于子节点数据,则称该序列为大根堆(最大堆),反之,若父节点数据总是小于子节点数据,则称为小根堆(最小堆)。
    2. 应用
    一般用于比较快速的取得一个数列的最大或最小值。

    二、 堆的实现
    由于堆的数据是一棵完全二叉树的节点,所以可以很方便的使用数组进行存储,直接利用下标来表示父节点与子节点之间的关系,下标为i的元素的左子节点的下标为2*i+1,右子节点的下标为2*2+2。
    下面是Go语言实现的最小堆的代码,最大堆的实现可以此类推。实现代码的核心部分为向下调整shiftDown()和向上调整shiftUp()两个方法,前者为堆初始化或删除时调用,后者为堆插入时调用。

    /**
    * 最小堆
    * author:JetWu
    * date:2020.02.08
     */
    package minHeap
    
    import (
    	"errors"
    	"fmt"
    )
    
    /**
    * 最小堆结构
    **/
    type MinHeap struct {
    	slice []int
    	size  int //最小堆大小
    }
    
    /**
    * 创建一个空最小堆
    **/
    func NewMinHeap() *MinHeap {
    	return &MinHeap{
    		slice: make([]int, 10),
    		size:  0,
    	}
    }
    
    /**
    * 使用切片创建一个最小堆
    **/
    func MakeMinHeap(slice []int) *MinHeap {
    	mh := &MinHeap{
    		slice: slice,
    		size:  len(slice),
    	}
    	i := (mh.size - 2) / 2 //最后一个拥有子节点的节点
    	for i >= 0 {
    		mh.shiftDown(i)
    		i--
    	}
    	return mh
    }
    
    /**
    * 打印最小堆
    **/
    func (mh *MinHeap) Print() {
    	for i := 0; i < mh.size; i++ {
    		fmt.Print(mh.slice[i], " ")
    	}
    	fmt.Println()
    }
    
    /**
    * 判断最小堆是否为空
    **/
    func (mh *MinHeap) IsEmpty() bool {
    	return mh.size < 1
    }
    
    /**
    * 最小堆容量
    **/
    func (mh *MinHeap) Count() int {
    	return mh.size
    }
    
    /**
    * 向下调整(最小堆初始化、删除时调用)
    **/
    func (mh *MinHeap) shiftDown(start int) {
    	i, j := start, start*2+1 //j为i的左子节点
    	temp := mh.slice[i]
    	for j < mh.size {
    		if j < mh.size-1 && mh.slice[j+1] < mh.slice[j] { //比较获得左右子节点的最小值编号
    			j++
    		}
    		if temp <= mh.slice[j] { //左右子节点都比父节点大
    			break
    		} else { //继续向下比较
    			mh.slice[i] = mh.slice[j]
    			i, j = j, j*2+1
    		}
    	}
    	mh.slice[i] = temp
    }
    
    /**
    * 向上调整(最小堆插入时调用)
    **/
    func (mh *MinHeap) siftUp(start int) {
    	if start > mh.size-1 {
    		return
    	}
    	j, i := start, (start-1)/2 //i为j的父节点
    	temp := mh.slice[j]
    	for j > 0 {
    		if temp >= mh.slice[i] { //子节点大于父节点
    			break
    		} else {
    			mh.slice[j] = mh.slice[i]
    			j, i = i, (i-1)/2
    		}
    	}
    	mh.slice[j] = temp
    }
    
    /**
    * 插入
    **/
    func (mh *MinHeap) Insert(data int) {
    	//将插入元素放置在最后节点
    	mh.size++
    	if mh.size <= len(mh.slice) {
    		mh.slice[mh.size-1] = data
    	} else {
    		mh.slice = append(mh.slice, data)
    	}
    	//向上调整
    	mh.siftUp(mh.size - 1)
    }
    
    /**
    * 删除
    **/
    func (mh *MinHeap) RemoveMin() (int, error) {
    	if mh.size < 1 {
    		return 0, errors.New("最小堆为空")
    	}
    	min := mh.slice[0]
    	mh.size--
    	//使用最后一个节点替换第一个节点
    	mh.slice[0] = mh.slice[mh.size]
    	//向下调整
    	mh.shiftDown(0)
    	return min, nil
    }
    

      

  • 相关阅读:
    mysql主从原理
    mysql锁和事物隔离
    mysql索引查找原理及调优
    MySQL高级查询
    周总结04
    冲刺第六天
    冲刺第五天
    冲刺第四天
    典型用户模板和用户场景模版
    冲刺第三天
  • 原文地址:https://www.cnblogs.com/wujuntian/p/12286502.html
Copyright © 2011-2022 走看看