旧街凉风 提交于 2020-02-09 11:49:08

一、什么是堆
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
}

  

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!