堆的基本概念
1.如果有一个关键码的集合K = {k0,k1, k2,…,kn-1},把它的所有元
素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足:
Ki <= K2i+1 且 Ki<= K2i+2 (Ki >= K2i+1 且 Ki >= K2i+2) i =0,1,2…,则称为小堆(或大堆)。
2.小堆(堆顶元素最小)
3.大堆
堆的实现
- 创建堆
- 申请空间,放置元素
- 调整 堆(大队或者小堆)
元素已经放置好,调整为小堆
即给一串数字,对应画成二叉树,若要从10开始调整,它的左右子树必须是堆
那么如何确定该从哪个结点开始调整呢?从最后一个非叶子节点开始,因为叶子是不需要开始的
最后一个元素的下标 = size-1,则它的双亲parent =最后一个元素的下标-1在除以2,即parent = (size-1-1)/2 ,然后从这个结点开始调整
void Adjust_Small(Heap* hp, DataType parent) //第二个参数为最后一个非叶子节点
{
int child = parent*2 + 1;//默认左孩子较小
while (child < hp->_size){
if (child + 1 < hp->_size && hp->_array[child + 1] < hp->_array[child])//左右孩子找出较小值
{
child = child + 1;
}
if (hp->_array[child]< hp->_array[parent])
{
Swap(&hp->_array[child],&hp->_array[parent]);
parent = child;
child = parent * 2 + 1;
}
}
}
向上调整法
1.
2.
3.
插入的元素不断和双亲比较,然后和双亲不断的换,因为 之前已经是堆了,其他位置都不用动了
//向上调整,针对插入元素时所做的调整
void Adjust_(Heap* hp, DataType child) //第二个参数:插入孩子的下标
{
int parent = (child - 1) / 2;
while(parent >= 0 && hp->_array[child] < hp->_array[parent]) //插入的结点与双亲结点比较,因为它之前已经是堆,所以它的另外一个孩子肯定比它小(或者大)
{
Swap(&hp->_array[child], &hp->_array[parent]);
child = parent;
parent = (child - 1) / 2;
}
}
堆顶的删除
删除堆顶元素(第0为存储位置),删除后重新调整,成为新堆,
void DeletHeap(Heap* hp)//删除堆顶元素(第0为存储位置),删除后重新调整,成为新堆
{
if (EmptyHeap(hp))
return;
//先找最后一个元素代替它
int parent = (hp->_size - 2) / 2;
hp->_array[0] = hp->_array[hp->_size--]; //可以用个Swap();
hp->_size -= 1; //个数减一
//重新调整堆
for (; parent >= 0; --parent)
{
Adjust_Big(hp,parent);
}
}
堆排序
void HeapAdjust(int *arr, int size, int parent) //向下调整法
{
int child = ((parent << 1) + 1);
while (child < size)
{
//找左右孩子较大的孩子大
if (child + 1 < size && arr[child] )
{
child += 1;
}
//检测双亲是否比较大的孩子大
if (arr[child] > arr[parent])
{
Swap(&arr[child], arr[parent]);
parent = child;
child = ((parent << 1) + 1);
}
else
return 0;
}
}
void HeapSort(int * arr,int size) //堆排序
{
//1.建堆(元素从第一个开始,每层放好成二叉树,然后调整即可)
int root = (size - 2)>>1;
for (; root >= 0; root--)
{
HeapAdjust(arr, size, root);
}
//2.堆排序
int end = size - 1;
while ()
{
Swap(arr[0], &arr[end]); //和堆顶位置进行交换
HeapAdjust(arr, end, 0);
--end;
}
}