1、堆的概念及结构
大堆:树中一个树及子树中,任何一个父亲都大于等于孩子。
小堆:树中一个树及子树中,任何一个父亲都小于等于孩子。
堆的作用:
1、堆排序。
2、TopK问题。在N隔数种,找出最大或者最小的的前K个数。
堆的逻辑结构:完全二叉树
堆的物理结构:数组。
父亲和孩子的关系:parent=(child-1)/2;
2、堆的实现:
因为堆的实际存储结构是数组,所以堆得实现类似于顺序表,这里不再详细介绍,重点介绍一下堆的插入和删除。
1、堆的插入
假设我们要实现的是大堆,即每一个父亲节点都大于孩子节点。
假设有一个现成的堆,准备插入一个数据。
先通过孩子节点的下标算出父亲的下标,接着比较大小,当孩子大于父亲时,就要交换孩子与父亲的值,然后继续比较,直到孩子小于父亲。所以该过程放在while循环中进行,当孩子为根时,或者孩子小于父亲时,循环停止。
这里要注意,如果以父亲的坐标为停止循环的条件,那么父亲是一直大于0的,导致程序没有从正缺的方向走出去。
2、堆的删除
堆的删除不是直接删除数据的最后一个,而是要删除最大或者最小的那一个,也就是堆顶的数据。
但是不能破坏堆原有的结构。
步骤:
1、先将堆顶元素与最后一个元素进行交换。
2、删除堆中最后一个元素。
3、将堆顶元素向下调整直到满足堆的特性。
向下调整步骤:
跟左右孩子中最小的孩子交换。
结束条件:父亲小于等于孩子或者调整到最后,即成为叶子节点。
调整后:
附:堆实现的代码
typedef int HeapDataType;
typedef struct Heap
{
HeapDataType* a;
int size;
int capacity;
}HP;
void HeapInit(HP* hp);
void HeapDestroy(HP* hp);
void HeapPush(HP* hp, HeapDataType x);
void Swap(HeapDataType* px, HeapDataType* py);
void HeapPop(HP* hp);
void HeapInit(HP* hp)
{
assert(hp);
hp->a = NULL;
hp->capacity = 0;
hp->size = 0;
}
void HeapDestroy(HP* hp)
{
assert(hp);
free(hp->a);
hp->capacity = 0;
hp->size = 0;
}
void Swap(HeapDataType* px, HeapDataType* py)
{
HeapDataType temp = *px;
*px = *py;
*py = temp;
}
void Adjust(HeapDataType* a, int childl) //走的大堆
{
int parent = (childl - 1) / 2;
while (childl>0)
{
if (a[childl] < a[parent])
{
Swap(&a[childl], &a[parent]);
childl = parent;
parent = (childl - 1) / 2;
}
else
{
break;
}
}
}
void HeapPush(HP* hp, HeapDataType x)
{
assert(hp);
if (hp->capacity == hp->size)
{
int newcapacity = hp->capacity == 0 ? 4 : 2 * hp->capacity;
HeapDataType* temp = (HeapDataType*)realloc(hp->a,sizeof(HeapDataType) * newcapacity);
if (temp == NULL)
{
printf("realloc is fail");
exit(-1);
}
hp->a = temp;
hp->capacity = newcapacity;
}
hp->a[hp->size]=x;
Adjust(hp->a, hp->size);
hp->size++;
}
void AdjustDown(int* a, int size, int parent) //调得小堆
{
int child = 2 * parent + 1;
while (child < size)
{
//先找孩子中最小的那一个
if (child+1<size && a[child + 1]< a[child])//因为这个地方child+1可能不存在
{
child++;
}
if ( a[child]< a[parent])
{
Swap(&a[parent], &a[child]);
parent = child;
child = 2 * parent + 1;
}
else
{
break;
}
}
}
//删除堆顶的数据
void HeapPop(HP* hp)
{
assert(hp);
assert(!HeapEmpty(hp));
Swap(&hp->a[hp->size-1], &hp->a[0]);
hp->size--;
AdjustDown(hp->a, hp->size, 0);
}
bool HeapEmpty(HP* hp)
{
return hp->size == 0;
}
void PrintHeap(HP* hp)
{
int i = 0;
for (i = 0; i < hp->size; ++i)
{
printf("%d ", hp->a[i]);
}
printf("\n");
}