堆是一种二叉树,通常是一棵完全二叉树,其中所有节点均满足如下性质: 任意一个节点的值都大于等于其任意一个子节点的值.又称大根堆, 小根堆则是任意一个节点的值都小于等于其任意一个子节点的值。
堆的表示
可以用链表或者数组表示堆,要保证堆的平衡,用数组表示,如果将序列{k1,k2,.....kn}表示为一维数组A[n],则序列中元素的下表与数组中下标一致。即数组中下标为0的位置不存放数据元素,此时堆是一棵完全二叉树,节点k[j]对应的子节点分别是k[2*j]与k[2*j+1],除叶子节点外,任意节点都有左右子节点,即使没有值
堆的初始化
给定一个数组A[n],生成堆
- 插入法:依次调用堆的插入算法插入数组中的每一个元素
- 调整法:将数组视为一棵完全二叉树,从最后一个有子节点的节点到根节点依次执行下沉操作。根节点调整完后整棵树就变成了一个堆. 最后一个有子节点的节点是 A[n/2], 它的子节点是A[n],A[n/2]后的所有节点都是子节点

![clipboard[1] clipboard[1]](https://images2015.cnblogs.com/blog/670764/201604/670764-20160416195848035-1860294252.png)
![clipboard[2] clipboard[2]](https://images2015.cnblogs.com/blog/670764/201604/670764-20160416195853582-573776643.png)
堆中删除最大值的算法
根据堆的性质,堆中最大值的节点是根节点A[1],因此总是删除根节点。接下来是如何调整堆.
- 删除叶子节点A[n],然后把它的值x放到原先根节点的位置。
- 不断的将x向树的下方移动,直到它到达某棵子树或叶子节点,这棵子树种x是最大值,这样整棵树便满足了堆的性质
- 移动的方式是,将x与左右子节点的最大值比较,x小于最大值则与该节点交换
最大比较次数是2lbn
删除堆中任意值也是同理:
![clipboard[3] clipboard[3]](https://images2015.cnblogs.com/blog/670764/201604/670764-20160416195858707-613110950.png)
堆中插入元素
- 首先将数组增大1,在数组最后插入新值,作为新的叶子节点
- 比较这个新的叶子节点及其父节点,如果大于父节点的值则交换两个节点。
- 直到它的值小于父节点或者到达根节点结束
最大比较次数是lbn,恰好是树的高度
![clipboard[4] clipboard[4]](https://images2015.cnblogs.com/blog/670764/201604/670764-20160416195900613-1348785025.png)
堆排序
基本思想:
- 将初始待排序关键字序列(R1,R2....Rn)构建成大根堆,此堆对应的数组为无序状态
- 将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,......Rn-1)和新的有序区(Rn),且满足R[1,2...n-1]<=R[n];
- 由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,......Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2....Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成

源代码 public class BigHeap
{
private int[] nodes;
public BigHeap(int[] arr)
{
nodes = new int[arr.Length + 1];
nodes[0] = int.MinValue;
Init(arr);
}
public int Count
{
get
{
return nodes.Length - 1;
}
}
private void Init(int[] arr)
{
for (int index = 1; index <= Count; index++)
{
nodes[index] = arr[index - 1];
int child = index;
while (child > 1)
{
int parent = child / 2;
if (nodes[child] < nodes[parent])
{
break;
}
else
{
Swap(ref nodes[child], ref nodes[parent]);
child /= 2;
}
}
}
}
public override string ToString()
{
return Tree(1);
}
//after sort, nodes isnot a heap format
public void Sort()
{
//nodes number is Count, need run Count-1 times to sort
for (int i = 1; i < Count; i++)
{
Swap(ref nodes[1], ref nodes[Count - i + 1]);
Adjust(1, Count - i);
}
}
public void Remove(int value)
{
int index = Find(value);
if(index >0 && index <=Count)
{
nodes[index] = nodes[Count];
nodes[Count] = int.MinValue;
Adjust(index, Count - 1);
}
}
private int Find(int value)
{
for (int i = 1; i <= Count; i++)
{
if (nodes[i] == value)
{
return i;
}
}
return -1;
}
//adjust the tree start from begin with count numbers
private void Adjust(int begin, int count)
{
int max = begin;
if (begin <= count / 2)
{
int lchild = 2 * begin;
int rchild = 2 * begin + 1;
if (lchild <= count && nodes[lchild] > nodes[max])
{
max = lchild;
}
if (rchild <= count && nodes[rchild] > nodes[max])
{
max = rchild;
}
if (max != begin)
{
Swap(ref nodes[begin], ref nodes[max]);
Adjust(max, count);
}
}
}
private string Tree(int index)
{
if (index <= Count)
{
string value = string.Empty;
if (nodes[index] != int.MinValue)
{
value = nodes[index].ToString();
}
string leftChild = Tree(index * 2);
string rightChild = Tree(index * 2 + 1);
if (!string.IsNullOrEmpty(leftChild) || !string.IsNullOrEmpty(rightChild))
{
return string.Format("{0}({1},{2})", value, leftChild, rightChild);
}
else
{
return value;
}
}
return string.Empty;
}
public static void Swap(ref int x, ref int y)
{
int temp = x;
x = y;
y = temp;
}
}