typedef struct Heap
{
int* a;
int size;
int capcity;
}HP;
堆的结构,要有两个指针,一个头一个尾,数组情况下略显多余,但链表情况必不可少
void heapinit(HP* point)
{
assert(point);
point->a = NULL;
point->size = point->capcity = 0;
}
void heapdestory(HP* point)
{
assert(point);
point->size = point->capcity = 0;
free(point->a);
point->a = NULL;
}
堆的初始化与释放,和栈与队列类似
void heappush(HP* point, int x)
{
assert(point);
if (point->a == NULL)
{
point->a = (int*)malloc(sizeof(int) *5);
point->capcity = 5;
}
point->a[point->size] = x;
point->size++;
adjustup(point, point->size-1);
}
堆元素的插入,首先当堆的状态只为初始化时,需要给指针一段空间,然后将元素放到堆的末尾,然后向上调整
void adjustup(int *a, int child)
{
int parent = (child - 1) / 2;
while (child > 0)
{
if (a[child] > a[parent])
{
int c = a[child];
a[child] = a[parent];
a[parent] = c;
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
向上调整的原理,这是一个大堆,父节点必须比子节点大,如果相反那么交换后仍需检查其他相关节点是否有问题,首先根据满二叉树的性质找到当前子节点的父节点,如果不符合性质则交换,再继续检查。
void heappop(HP* point)
{
assert(point);
assert(point->size != 0);
int c = point->a[0];
point->a[0] = point->a[point->size - 1];
point->a[point->size - 1] = c;
point->size--;
adjustdown(point, point->size);
}
堆的删除:指删除堆顶元素,方法为将堆顶和堆底元素互换,然后让size指针减一,彻底抹除没有必要,然后向上调整
void adjustdown(int *a, int num,int b)//左右子树必须是堆
{
int parent = b;
int child =parent * 2 + 1;
while (child a[child + 1]&&child+1 a[parent])
{
int c = a[child];
a[child] =a[parent];
a[parent] = c;
parent = child;
child = parent * 2 + 1;//继续向下调
}
else
{
break;
}
}
}
向下调整:与向上调整一样,此处为小堆操作,父节点必须大,而此处的关键在于找到左孩子右孩子中的大孩子,如果不符合与父亲交换,否则存在还需寻找一次的风险,由于只交换了两个元素,所以整体二叉树结构不变,而且只要一次符合那么下面的元素就都符合了
bool heapempty(HP* point)
{
assert(point);
return point->size == 0;
}
判空
void heapsort(int* a, int num)
{
HP heap1;
heappinit(&heap1);
for (int i = 0; i < sizeof(a) / sizeof(int); ++i)
{
heappush(&heap1, a[i]);
}
int j = 0;
while (heap1.size != 0)
{
int top1 = heap1.a[0];
a[j++] = top1;
heappop(&heap1);
}
//free(&heap1.a);
//heap1.a = NULL;
//heap1.size = heap1.capcity = 0;
}
堆排序(必须建堆)一:先建堆,然后返回堆顶元素,再删除堆顶元素,直到将整个堆重新排列在目标数组中,完成排序,弊端在于空间复杂度与拷贝数据
void heapsort2(int* a, int n)
{
for (int i = 1; i < n; i++)
{
adjustup(a, i);
}
int end = n - 1;
while (end>0)
{
int c = a[0];
a[0] = a[end];
a[end] = c;
adjustdown(a, end, 0);
end--;
}
}
堆排序二:如果是降序,则建小堆,建完首尾交换,选出最小的放在最后面,然后剩下的元素向下调整选出次小的,然后再首尾交换,以此类推,升序相反