1.堆的基本介绍
1.物理结构是一个数组
2.逻辑结构是完全二叉树
3.大堆(树中所有的父亲大于等于孩子) 小堆(树中所有的父亲小于等于孩子)
完全二叉树每一层有2^n个树叉
父子间关系:
leftchild=parent2+1
rightchild=parent2+2
parent=(child-1)/2
2.堆向下调整算法
注意 : 向下调整算法的前提是左右子树必须是堆(小堆/大堆)
建堆,选出左右孩子中小的那一个。
堆分小根堆和大根堆两类
这里我们以小根堆为例。
void AdjustDown(int *a, int n, int parent)
{
int child = parent * 2 + 1;
while (child < n)
{
//选出左右孩子中小的哪一个
if (child+1<n&&a[child + 1] < a[child])
{
++child;
}
if (a[child] < a[parent])
{
Swap(&a[parent], &a[child]);
child = parent * 2 + 1;
}
else
{
break;
}
}
}
3.堆排序
堆排序优于直接选择排序->o(n^2)才有价值
1.建堆o(N)
2.继续选数
如果排升序建小堆,问题在于:选出最小的数放到第一个位置,紧接着要选出次小的,如何选?
如果没搞一个都要通过建堆来选 数,还不如直接遍历比较来选数,堆排序就没有意义了。
所以排升序优先建大堆。
void HeapSort(int *a, int n)
{
for (int i = (n - 1 - 1) / 2; i >= 0; --i)
{
AdjustDown(a, n, i);
}
int end = n - 1;
while (end > 0)
{
Swap(&a[0], &a[end]);
//选出次大的
AdjustDown(a, end, 0);
--end;
}
}
结论:堆排序的时间复杂度o(N*logN).
4.数据结构实现堆
堆的初始化
void HeapInit(HP* php, HPDataType* a, int n)
{
assert(php);
php->a = (HPDataType*)malloc(sizeof(HPDataType)*n);
if (php->a == NULL)
{
printf("malloc fail\n");
exit(-1);
}
memcpy(php->a, a, sizeof((HPDataType)*n);
php->size = n;
php->capacity = n;
}
插入数据
我们将数据插入到堆数组的末尾,在进行向上调整。
void AdjustUp(int* a,int child)
{
int parent = (child - 1) / 2;
while(child > 0)
{
if(a[child] > a[parent])
{
Swap(&a[child],&a[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
void HeapPush(HP* php, HPDataType x)
{
if (php->size == php->capacity)
{
HPDataType* tmp = (HPDataType*)realloc(php->a, php->capacity * 2 * sizeof(HPDataType);
if (tmp == NULL)
{
printf("realloc fail\n");
exit(-1);
}
php->a = tmp;
php->capacity *= 2;
HPDataType[php->size-1] = x;
php->size++;
Adjustup(php->a,php->size-1,x);
}
}
删除数据
和上面堆排序的思想类似,将堆顶的数据和最后一个数据换位,删除最后一个数据,再进行向下调整算法。
void HeapPop(Heap* hp)
{
assert(hp);
assert(hp->_size > 0);
Swap(&hp->_a[0],&hp->_a[hp->_size - 1]);
hp->size--;
AdjustDown(hp->_a,0,hp->size)
}
堆的销毁
void HeapDestroy(Heap* hp)
{
assert(hp);
free(hp->_a);
free(hp);
}
堆的数据个数
int HeapSize(Heap* hp)
{
assert(hp);
return hp->_size;
}
取堆顶的数据
HPDataType HeapTop(Heap* hp)
{
assert(hp);
assert(hp->_size > 0);
return hp->_a[0];
}
堆的判断空
bool HeapEmpty(Heap* hp)
{
assert(hp);
return hp->_size == 0;
}