堆的概述
堆作为一种树形结构,也是二叉树的一种应用。二叉搜索树是规定了节点之间的大小关系:左孩子<根节点<右孩子。而堆中规定的节点之间的次序是:根节点<左孩子,根节点<右孩子;根节点>左孩子,根节点>右孩子。前者我们称之为小顶堆,后者是大顶堆。不同的逻辑定义,会得到不同的性质。关于堆的一些性质描述,我们在选择排序:堆排序中已详细介绍过。
堆的存储结构
堆是一种特殊的完全二叉树。通常所说的堆,就是指二叉堆。特殊是指它的节点大小次序是有规定的,但其本质还是一棵完全二叉树。而完全二叉树最常用的是顺序存储结构。如下图;
对于完全二叉树这种特殊的情况,节点的层次序列就足以反映整个二叉树的结构。顺序方式是完全二叉树最简单、最节省空间的存储方式。下面给出最小堆的c++实现:
代码
类定义
#include<iostream>
#include<iomanip>
using namespace std;
//默认堆大小
#define DEFAULTSIZE 20
//堆空间每次的增量
#define INCREMENT 10
typedef int ElemType;
class MinHeap
{
private:
//堆数组
ElemType* array;
//堆内存大小
int heapsize;
//堆中元素个数
int elemsize;
//向上调整
void siftUp(int);
//向下调整
void siftDown(int);
public:
//默认构造方法
MinHeap();
//拷贝构造方法
MinHeap(MinHeap&);
//指定数组构造堆
MinHeap(ElemType*, int);
//析构方法
~MinHeap()
{delete[]array;}
//堆清空
void clear()
{elemsize = 0;}
//堆空的判断
bool empty()
{return elemsize == 0;}
//返回堆中元素个数
int heapSize()
{return elemsize;}
//插入新的元素
void insertHeap(ElemType);
//删除元素
bool deleteHeap(int);
//获取堆顶元素
ElemType top();
//遍历堆
void traverse();
//堆排序
void heapSort();
};
类实现
//默认构造方法
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;
}
主函数
//主函数
int main()
{
cout << "******最小堆***by David***" << endl;
//准备工作
int elemsize;
ElemType data;
cout << "输入堆中元素个数 ";
while (cin >> elemsize && elemsize <= 0)
cout << "输入不对!重新输入 ";
ElemType *array = new ElemType[elemsize];
cout << "输入各元素 ";
int i = 0;
while (i < elemsize)
cin >> array[i++];
//建堆
cout << "初始化堆" << endl;
MinHeap heap1(array, elemsize);
//测试各方法,在测试的过程中,不断遍历
cout << "堆空 ";
heap1.empty() ? cout << "Yes!" : cout << "No!";
cout << endl;
cout << "遍历堆" << endl;
heap1.traverse();
cout << "获取堆顶元素 " << heap1.top() << endl;
cout << "堆排序" << endl;
heap1.heapSort();
cout << endl;
int pos;
cout << "删除下标为 ";
cin >> pos;
heap1.deleteHeap(pos) ? cout << "删除成功!" << endl : cout << "删除失败!" << endl;
cout << "遍历堆" << endl;
heap1.traverse();
cout << endl;
cout << "插入元素 " ;
cin >> data;
heap1.insertHeap(data);
cout << "遍历堆" << endl;
heap1.traverse();
cout << endl;
//测试拷贝构造函数
cout << "创建新堆" << endl;
MinHeap heap2;
heap2 = heap1;
cout << "堆空 ";
heap2.empty() ? cout << "Yes!" : cout << "No!";
cout << endl;
cout << "遍历堆" << endl;
heap2.traverse();
cout << "清空堆" << endl;
heap2.clear();
cout << "堆空 ";
heap2.empty() ? cout << "Yes!" << endl: cout << "No!" <<endl;
delete[]array;
cout << endl;
system("pause");
return 0;
}
运行
相同的输入:
小结
堆的用处很多,最常用的有实现堆排序、优先队列……。这里粘贴的是最小堆的代码,只要稍作改变,即可得到最大堆的实现代码。上面的最大堆运行结果,即是修改代码后的结果。
转载请注明出处,本文地址:http://blog.csdn.net/zhangxiangdavaid/article/details/37518641
若有所帮助,顶一个哦!
专栏目录: