概述
堆是一种完全二叉树,高度为(高度为O(lgN))这种树结构的效率很高,多用于我们常说的堆排序以及优先队列,例如先入先出队列(FIFO)。
堆排序的时间复杂度为O(NlgN)。
ps:
完全二叉树的定义,若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,说白了,完全二叉树就是一棵数层数为h,则它的第1至h-1层没有空节点,第h层(也就是叶子结点层)有可能有空节点,节点的生成顺序是从左边开始,空节点始终在右边出现。
堆的分类
堆分为大顶堆和小顶堆。
大顶堆的特点是二叉树的父节点均大于它的左右孩子节点,堆排序之后得到的是升序数列。
小顶堆的特点与之相反,为二叉树的父节点均小于它的左右孩子节点,堆排序之后得到的是降序数列。
堆支持的操作
- 去顶(deleteTop)
- 堆排序(sort)
- 优先出列(pop)
- 堆的元素数量(size)
约定
我们用数组来表示堆中的数据,这里根据堆为完全二叉树的概念,我们认为下标为i的节点的父节点下标为 (i-1)/2,其左节点为下标2*i,右节点下标为2*i+1。
(以上i表示为数组的下标)
演示
接下来是代码实现堆的一系列操作(以大顶堆为例,C# in Unity)
- Heap类
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
/// <summary>
/// 堆
/// 大顶堆
/// 2017/6/1
/// </summary>
public class Heap{
public List<int> items;
public Heap(){
items = new List<int>();
}
/// <summary>
/// 新增节点
/// </summary>
/// <param name="t"></param>
public void Add(int t) {
items.Add(t);
Moveup(items.Count - 1);//下标
}
/// <summary>
/// 去顶
/// </summary>
public void Deletetop() {
if (items == null || items.Count == 0)
{
return;
}
int deepitem = items[items.Count - 1];
items.RemoveAt(items.Count - 1);
items[0] = deepitem;
Shiftdown(0,items.Count - 1);
Debug.Log("删除顶节点");
}
/// <summary>
/// 上移操作
/// </summary>
/// <param name="index">上移的节点下标</param>
private void Moveup(int index) {
int item = items[index];
while (index > 0)
{
int parentIndex = (index - 1) / 2;
if (parentIndex < 0)
{
break;
}
int parent = items[parentIndex];
if (item > parent)
{
items[index] = parent;
index = parentIndex;
}
else
{
break;
}
}
items[index] = item;
}
/// <summary>
/// 下沉操作
/// </summary>
/// <param name="index">下沉的节点下标</param>
/// <param name="aimIndex">下沉截止节点下标</param>
private void Shiftdown(int index,int aimIndex) {//0 9
int item = items[index];
while (index < aimIndex)
{
int preIndex = 2 * index + 1;
if (preIndex >= aimIndex)
{
break;
}
if (preIndex + 1 < aimIndex && items[preIndex + 1] > items[preIndex])//找出孩子中最大的
{
preIndex++;
}
if (items[preIndex] < item)
{
break;
}
items[index] = items[preIndex];
index = preIndex;
}
items[index] = item;
}
/// <summary>
/// 优先出列
/// </summary>
/// <returns></returns>
public int Pop()
{
if (items == null || items.Count == 0)
{
return default(int);
}
return items[0];
}
public bool isEmpty() {
return items == null || items.Count == 0;
}
/// <summary>
/// 堆排序
/// </summary>
public void HeapSort()
{
Debug.Log("---堆排序---");
for (int i = items.Count - 1; i > 0;i-- )
{
Swap(i,0);
Shiftdown(0,i);
}
}
/// <summary>
/// 输出
/// </summary>
public void OutPut() {
string str = "";
for (int i = 0; i < items.Count;i++ )
{
str += items[i] + ",";
}
Debug.Log("OutPut(当前数列): " + str);
}
private void Swap(int i,int j) {
int preNum = items[i];
items[i] = items[j];
items[j] = preNum;
}
}
- 入口
void Start()
{
Heap heap = new Heap();
string str = "";
for (int i = 0; i < 11;i++ )
{
int random = UnityEngine.Random.Range(0,100);
heap.Add(random);
str += (random + ",");
}
print("初始化用的数列:"+str);
heap.OutPut();
print("优先节点:" + heap.Pop());
heap.Deletetop();
heap.OutPut();
heap.HeapSort();
heap.OutPut();
}