堆的概述
堆作为一种树形结构,也是二叉树的一种应用。二叉搜索树是规定了节点之间的大小关系:左孩子<根节点<右孩子。而堆中规定的节点之间的次序是:根节点<左孩子,根节点<右孩子;根节点>左孩子,根节点>右孩子。前者我们称之为小顶堆,后者是大顶堆。不同的逻辑定义,会得到不同的性质。关于堆的一些性质描述,我们在选择排序:堆排序中已详细介绍过。
堆的存储结构
堆是一种特殊的完全二叉树。通常所说的堆,就是指二叉堆。特殊是指它的节点大小次序是有规定的,但其本质还是一棵完全二叉树。而完全二叉树最常用的是顺序存储结构。如下图;
//默认构造方法
MinHeap::MinHeap()
{
elemsize = 0;
array = new ElemType[DEFAULTSIZE];
if (!array)
{
cerr << "分配内存失败!" << endl;
exit(0);
}
}
//拷贝构造方法
MinHeap::MinHeap(MinHeap& heap)
{
//若原堆中有元素,则清空
if (array)
delete[]array;
array = new ElemType[heap.heapsize];
if (!array)
{
cerr << "分配内存失败!" << endl;
exit(0);
}
MinHeap(heap.array, heap.elemsize);
}
//指定数组构造堆
MinHeap::MinHeap(ElemType* a, int n)
{
elemsize = n;
heapsize = DEFAULTSIZE;
while (heapsize < n)
heapsize += INCREMENT;
array = new ElemType[heapsize];
if (!array)
{
cerr << "分配内存失败!" << endl;
exit(0);
}
//赋值
memcpy(array, a, n*sizeof(ElemType));
//堆化数组
for (int i = (elemsize - 2) / 2; i >= 0; i--)
siftDown(i);
}
//插入新的元素
void MinHeap::insertHeap(ElemType data)
{
/*
新元素总是先加到最后,再调整堆
所以插入操作总是可以成功的(相对于内存大小)
*/
//若堆内存已用完,则扩充堆内存
if (elemsize >= heapsize)
{
heapsize += INCREMENT;
array = (ElemType*)realloc(array, heapsize);
}
array[elemsize] = data;
siftUp(elemsize);
elemsize++;
}
//删除指定位置元素
bool MinHeap::deleteHeap(int pos)
{
//堆空或位置不对
if (empty() || pos<0 || pos>=elemsize)
return false;
//删除时,总是用最后一个元素填充待删除的位置
array[pos] = array[elemsize - 1];
elemsize--;
//从该位置向下调整堆
siftDown(pos);
}
//获取堆顶元素
ElemType MinHeap::top()
{
if (empty())
return NULL;
return array[0];
}
//向上调整
void MinHeap::siftUp(int pos)
{
int i, j;
//i为j的父亲
j = pos, i = (pos - 1) / 2;
while (i>=0)
{
if (array[j] >= array[i])
break;
swap(array[i], array[j]);
j = i;
i = (j-1) / 2;
}
}
//向下调整
void MinHeap::siftDown(int pos)
{
int i, j;
i = pos, j = 2 * i + 1;
while (j < elemsize)
{
if (j + 1 < elemsize && array[j + 1] < array[j])
j++;
if (array[i] <= array[j])
break;
swap(array[i], array[j]);
i = j;
j = 2 * i + 1;
}
}
//遍历堆
void MinHeap::traverse()
{
if (empty())
return;
for (int i = 0; i < elemsize; i++)
cout << setw(4) << array[i];
cout << endl;
}
//堆排序
void MinHeap::heapSort()
{
if (empty())
return;
ElemType *a = new ElemType[elemsize];
if (!a)
{
cerr << "分配内存失败!" << endl;
exit(0);
}
memcpy(a, array, elemsize*sizeof(ElemType));
int n = elemsize;
while (n >= 1)
{
//把最小的元素调到最后
swap(a[0], a[n - 1]);
n--;
//从堆顶向下调整
int i, j;
i = 0, j = 1;
while (j < n)
{
if (j + 1 < n && a[j + 1] < a[j])
j++;
if (a[i] <= a[j])
break;
swap(a[i], a[j]);
i = j;
j = 2 * i + 1;
}
}
//打印
for (int i = elemsize - 1; i >= 0; i--)
cout << setw(4) << a[i];
cout << endl;
//释放内存
delete[]a;
}