一.堆排序
1.首先区别于升序打印或者降序打印
(1)升序打印:
void TestHeapSort()
{
// 升序打印 -- 小堆
// 降序打印 -- 大堆
HP hp;
HeapInit(&hp);
int a[] = { 27, 15, 19, 18, 28, 34, 65, 49, 25, 37 };
for (int i = 0; i < sizeof(a) / sizeof(int); ++i)
{
HeapPush(&hp, a[i]);
}
while (!HeapEmpty(&hp))
{
printf("%d ", HeapTop(&hp));
HeapPop(&hp);
}
printf("\n");
int a[] = { 27, 15, 19, 18, 28, 34, 65, 49, 25, 37 };
HeapSort(a, sizeof(a) / sizeof(int));
}
(2)排序
升序排序--建大堆(父节点值大于子节点)
降序排序--建小堆(父节点值小于子节点)
2.堆排序初级版本(不建议使用版本):
//不好/错误方式:
HP hp;//定义个堆类型的结构体
HeapInit(&hp);
for(int i=0;i<n;i++)
{
HeapPush(&hp,a[i]);
}
int i=0;
while(!HeapEmpty(&hp))
{
a[i]=HeapTop(&hp);
HeapPop(&hp);
}
存在问题:
1.内存泄露(小问题)-->添加HeapDestroy
2.要先写一个Hp数据结构,复杂
3.有O(N)空间复杂度
3.优化版本(正确版本):
整体思路:
#堆排序
一、建堆(由数组建堆)(堆排序的前提是有堆)
思路:方式1.直接将 已给的数组的每个元素都 进行向上排序 (没有条件限制)
方式2.向下排序 (parent的左右两边都必须是堆)
二、堆排序
思路:## 升序--大堆--将堆顶最大的元素和最后一个元素交换,放在最后一位,然后size--,每完成一次,堆剩下的数进行一次向下调整,和HeapPop的思路类似。依次将最后一位放最大,倒数第二位放次大,.......依次类推,可以堆进行排序。
(升序--而不是建小堆,因为选出最小放在首位的容易,但选出次小的放在第二位难,之后的都不容易放。只能选一个次小的,再建堆,选次小,建堆,时间复杂度会达到O(N^2),该方法不是不可以,而是效率太差,没有使用到堆的优势 )
//简洁版本
void Swap(int* p1, int* p2)
{
int tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
voidAdjustUp(HPDataType*a,intchild)
{
intparent=(child-1)/2;
//while (parent >= 0)
while(child>0)
{
//if (a[child] < a[parent])
if(a[child]>a[parent])
{
Swap(&a[child],&a[parent]);
child=parent;
parent=(child-1)/2;
}
else
{
break;
}
}
}
void AdjustDwon(int* a, int size, int parent)
{
int child = parent * 2 + 1;
while (child < size)
{
if (child + 1 < size && a[child + 1] > a[child])
{
++child;
}
if (a[child] > a[parent])
{
Swap(&a[child], &a[parent]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
// 降序 -- 建小堆
// 升序 -- 建大堆
void HeapSort(int* a, int n)
{
// 建堆方式1:O(N*logN)
for (int i = 1; i < n; ++i)
{
AdjustUp(a, i);//向上排序
}
// 建堆方式2:O(N)
for (int i = (n - 1 - 1) / 2; i >= 0; --i)
{
AdjustDwon(a, n, i);//向下排序
}
// O(N*logN)
int end = n - 1;
while (end > 0)
{
Swap(&a[0], &a[end]);
AdjustDwon(a, end, 0);
--end;
}
}