赞
踩
目录
(11)✳删除堆顶数据(拿最大堆举例,即:删除后仍保持是大堆)
因为堆是一棵完全二叉树,所以使用数组结构,不会浪费空间。
所以,使用数组结构实现堆。
代码以大堆,作为插入堆、删除根节点为例子,后续不再说明:
可以看到,堆的结构定义和顺序表类似
- typedef int HPDataType;
- typedef struct Heap
- {
- HPDataType* a;
- int size;
- int capacity;
- }HP;
- //初始化堆
- void HeapInit(HP* hp)
- {
- assert(hp);
- hp->a = NULL;
- hp->size = hp->capacity = 0;
- }
- //交换父子结点数据
- void Swap(HPDataType* px, HPDataType* py)
- {
- HPDataType tmp = *px;
- *px = *py;
- *py = tmp;
- }
- //打印堆内数据
- void HeapPrint(HP* hp)
- {
- for (int i = 0; i < hp->size; ++i)
- {
- printf("%d ", hp->a[i]);
- }
- printf("\n");
- }
- //堆为空
- bool HeapEmpty(HP* hp)
- {
- assert(hp);
-
- return hp->size == 0;
- }
- //获取堆顶数据
- HPDataType HeapTop(HP* hp)
- {
- assert(hp);
- assert(!HeapEmpty(hp));
-
- return hp->a[0];
- }
- //销毁堆
- void HeapDestroy(HP* hp)
- {
- assert(hp);
- free(hp->a);
- hp->capacity = hp->size = 0;
- }
插入堆如何实现呢?
注意:插入数据后,还要保证堆依旧是大堆(此处以大堆为列)
分析:
所以,需要向上调整。
向上调整的执行逻辑:
- //向上调整(大堆)
- void AdjustUp(int* a, int child)
- {
- assert(a);
-
- int parent = (child - 1) / 2;
- //while (parent >= 0) //这样写有Bug!
- while (child > 0)
- {
- if (a[child] > a[parent])
- {
- /*HPDataType tmp = a[child];
- a[child] = a[parent];
- a[parent] = tmp;*/
- Swap(&a[child], &a[parent]);
-
- child = parent;
- parent = (child - 1) / 2;
- }
- else
- {
- break;
- }
- }
- }
- //往堆插入数据
- void HeapPush(HP* hp, HPDataType x)
- {
- assert(hp);
- //不够就扩容
- if (hp->size == hp->capacity)
- {
- int newcapacity = hp->capacity == 0 ? 4 : hp->capacity * 2;
- HPDataType* tmp = realloc(hp->a, sizeof(HPDataType) * newcapacity);
- if (tmp == NULL)
- {
- printf("realloc fail!\n");
- exit(-1);
- }
-
- hp->a = tmp;
- hp->capacity = newcapacity;
- }
-
- hp->a[hp->size] = x;
- hp->size++;
-
- AdjustUp(hp->a, hp->size - 1);
- }
区别:
最大堆向上调整,插入后的结点数据,要不改变最大堆(ps:定义 最大堆是每个节点的数据值都大于等于其子树数据值),影响了插入节点到根节点那段路径上的结点( 产生变化!):
- 将插入结点作为child,与其父亲parent比较,如果a[child] > a[parent],就交换节点数据值,直到child是根节点,才截至!
最小堆向上调整,插入后的结点数据,要不改变最小堆(ps:定义 最小堆是每个节点的数据值都小于等于其子树数据值),影响了插入节点到根节点那段路径上的结点( 产生变化!):
- 将插入结点作为child,与其父亲parent比较,如果a[child] < a[parent],就交换节点数据值,直到child是根节点,才截至!
分析:
删除堆顶数据,还要依旧保持是大堆,则需要向下调整:
向下调整过程:
注意:向下调整的循环结束条件:(大堆为例!)
- //向下调整(大堆)
- void AdjustDown(int* a, int n, int parent)
- {
- assert(a);
-
- int child = parent * 2 + 1;//左孩子
- while (child < n)
- {
- //选出大孩子
- if (child + 1 < n && a[child + 1] > a[child])
- child++;
-
- //交换 并 迭代 parent 和 child
- if (a[parent] < a[child])
- {
- Swap(&a[parent], &a[child]);
- parent = child;
- child = parent * 2 + 1;
- }
- else
- {
- break;
- }
- }
- }
- //删除堆顶数据
- void HeapPop(HP* hp)
- {
- assert(hp);
- assert(!HeapEmpty(&hp));
-
- Swap(&hp->a[0], &hp->a[hp->size - 1]);//堆顶数据与末尾数据交换
- hp->size--;
-
- AdjustDown(hp->a, hp->size, 0);
- }
需要注意的是,根节点,也就是堆顶结点,我们直接删除是不行的!!
需要将最后一个结点与根节点位置互换,因为我们删除尾结点(堆本质上是数组嘛~~~~~)是方便的!!!
然后再进行“ 根结点 ” 向下调整...................
区别:
最大堆删除堆顶数据,看是否此时还仍然符合最大堆的要求,若不符合,那么就需要向下调整,调成符合最大堆的形式。
考虑到完全二叉树中,任意一个父亲节点左孩子存在,而右孩子不一定存在(细品!!!),所以我们需要判断,避免造成非法访问数组元素。如果右孩子存在,即:child + 1 < n ,右孩子大于左孩子,即:a[child + 1] > a[ child ](选出大孩子)。那么就child指向右孩子。
(即:该代码段是用child指向左右孩子中较大孩子)
如果说,a[child] > a[parent],那么就交换父子结点,然后继续向下调整。
最小堆删除堆顶数据,看是否此时还仍然符合最小堆的要求,若不符合,那么就需要向下调整,调成符合最小堆的形式。
考虑到完全二叉树中,任意一个父亲节点左孩子存在,而右孩子不一定存在(细品!!!),所以我们需要判断,避免造成非法访问数组元素。如果右孩子存在,即:child + 1 < n ,右孩子小于左孩子,即:a[child + 1] < a[ child ](选出小孩子)。那么就child指向右孩子。
(即:该代码段是用child指向左右孩子中较小孩子)
如果说,a[child] < a[parent],那么就交换父子结点,然后继续向下调整。
测试 【插入、删除大根堆】 的效果:
所以,向上向下调整都需要调整树的高度h次,即:时间复杂度为:O(log2_N)
堆的实现总代码:
- //Heap.h文件
- #pragma once
- #include<stdio.h>
- #include<stdlib.h>
- #include<assert.h>
- #include<stdbool.h>
-
- //实现大堆
- typedef int HPDataType;
- //定义堆
- typedef struct Heap
- {
- HPDataType* a;
- int size;
- int capacity;
- }HP;
-
-
- //初始化堆
- void HeapInit(HP* hp);
-
- //交换父子结点数据
- void Swap(HPDataType* px, HPDataType* py);
-
- //打印堆内数据
- void HeapPrint(HP* hp);
-
- //堆为空
- bool HeapEmpty(HP* hp);
-
- //销毁堆
- void HeapDestroy(HP* hp);
-
- //数据插入堆
- void HeapPush(HP* hp, HPDataType x);
-
- //向上调整
- void AdjustUp(int* a, int child);
-
- //删除堆顶数据
- void HeapPop(HP* hp);
-
- //向下调整
- void AdjustDown(int* a, int n, int parent);
-
- //获取堆顶数据
- HPDataType HeapTop(HP* hp);
- //Heap.c文件
- #define _CRT_SECURE_NO_WARNINGS
- #include"Heap.h"
-
- //初始化堆
- void HeapInit(HP* hp)
- {
- assert(hp);
-
- hp->a = NULL;
- hp->size = hp->capacity = 0;
- }
- //销毁堆
- void HeapDestroy(HP* hp)
- {
- assert(hp);
- free(hp->a);
- hp->capacity = hp->size = 0;
- }
- //交换父子结点数据
- void Swap(HPDataType* px, HPDataType* py)
- {
- HPDataType tmp = *px;
- *px = *py;
- *py = tmp;
- }
- //获取堆顶数据
- HPDataType HeapTop(HP* hp)
- {
- assert(hp);
- assert(!HeapEmpty(hp));
-
- return hp->a[0];
- }
- 向上调整(大堆)
- //void AdjustUp(int* a, int child)
- //{
- // assert(a);
- //
- // int parent = (child - 1) / 2;
- // //while (parent >= 0)
- // while (child > 0)
- // {
- // if (a[child] > a[parent])
- // {
- // /*HPDataType tmp = a[child];
- // a[child] = a[parent];
- // a[parent] = tmp;*/
- // Swap(&a[child], &a[parent]);
- //
- // child = parent;
- // parent = (child - 1) / 2;
- // }
- // else
- // {
- // break;
- // }
- // }
- //}
- //向上调整(小堆)
- void AdjustUp(int* a, int child)
- {
- assert(a);
-
- int parent = (child - 1) / 2;
- //while (parent >= 0)
- while (child > 0)
- {
- if (a[child] < a[parent])
- {
- /*HPDataType tmp = a[child];
- a[child] = a[parent];
- a[parent] = tmp;*/
- Swap(&a[child], &a[parent]);
-
- child = parent;
- parent = (child - 1) / 2;
- }
- else
- {
- break;
- }
- }
- }
- //往堆插入数据
- void HeapPush(HP* hp, HPDataType x)
- {
- assert(hp);
- //不够就扩容
- if (hp->size == hp->capacity)
- {
- int newcapacity = hp->capacity == 0 ? 4 : hp->capacity * 2;
- HPDataType* tmp = realloc(hp->a, sizeof(HPDataType) * newcapacity);
- if (tmp == NULL)
- {
- printf("realloc fail!\n");
- exit(-1);
- }
-
- hp->a = tmp;
- hp->capacity = newcapacity;
- }
-
- hp->a[hp->size] = x;
- hp->size++;
-
- AdjustUp(hp->a, hp->size - 1);
- }
- //判断堆是否为空
- bool HeapEmpty(HP* hp)
- {
- assert(hp);
-
- return hp->size == 0;
- }
- //堆的数据个数
- int HeapSize(HP* hp)
- {
- assert(hp);
-
- return hp->size;
- }
- //打印堆内数据
- void HeapPrint(HP* hp)
- {
- for (int i = 0; i < hp->size; ++i)
- {
- printf("%d ", hp->a[i]);
- }
- printf("\n");
- }
- 向下调整(大堆)
- //void AdjustDown(int* a, int n, int parent)
- //{
- // assert(a);
- //
- // int child = parent * 2 + 1;//左孩子
- // while (child < n)
- // {
- // //选出大孩子
- // if (child + 1 < n && a[child + 1] > a[child])
- // child++;
- //
- // //交换 并 迭代 parent 和 child
- // if (a[parent] < a[child])
- // {
- // Swap(&a[parent], &a[child]);
- // parent = child;
- // child = parent * 2 + 1;
- // }
- // else
- // {
- // break;
- // }
- // }
- //}
- //向下调整(小堆)
- void AdjustDown(int* a, int n, int parent)
- {
- assert(a);
-
- int child = parent * 2 + 1;//左孩子
- while (child < n)
- {
- //选出小孩子
- if (child + 1 < n && a[child + 1] < a[child])
- child++;
-
- //交换 并 迭代 parent 和 child
- if (a[parent] > a[child])
- {
- Swap(&a[parent], &a[child]);
- parent = child;
- child = parent * 2 + 1;
- }
- else
- {
- break;
- }
- }
- }
- //删除堆顶数据
- void HeapPop(HP* hp)
- {
- assert(hp);
- assert(!HeapEmpty(&hp));
-
- Swap(&hp->a[0], &hp->a[hp->size - 1]);//堆顶数据与末尾数据交换
- hp->size--;
-
- AdjustDown(hp->a, hp->size, 0);
- }
- //Test.c文件
- #define _CRT_SECURE_NO_WARNINGS
- #include"Heap.h"
-
- //在N个数中找出最大的前K个最大值 (或者最小的前K个最小值)
-
- int main()
- {
- int a[] = { 70,56,30,25,15,10,75 };
- HP hp;
- HeapInit(&hp);
- for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++)
- {
- HeapPush(&hp, a[i]);
- }
- HeapPrint(&hp);
-
- HeapPop(&hp);
- HeapPrint(&hp);
-
- HeapPop(&hp);
- HeapPrint(&hp);
-
- //销毁堆
- HeapDestroy(&hp);
-
- return 0;
- }
首先想想为什么要用堆实现Topk问题?在N非常大的时候,其他算法为什么不行?
以选最大的K个数为例,建立小堆。
建立K个数的小堆,最终达到选出N个数中最大的K个数,在这个过程中需要注意的是:
TopK算法(Test.c文件)
- //Test.c文件
- #define _CRT_SECURE_NO_WARNINGS
- #include"Heap.h"
-
- //从N个数中,选出K个最大的数
- //(只有建立 【小堆】 一种办法,大堆不行)
- void PrintTopK(int* a, int n, int k)
- {
- HP hp;
- HeapInit(&hp);
- // 1. 建堆--用a中的K个数创建一个小堆
- for (int i = 0; i < k; ++i)
- {
- HeapPush(&hp, a[i]);//小堆的HeapPush
- }
-
- // 2. 将剩余N-K个元素依次与堆顶数据比较,比他大,就替换他,进堆
- for (int i = k; i < n; ++i)
- {
- if (a[i] > HeapTop(&hp))
- {
- //方法1
- //HeapPop(&hp);//小堆的HeapPop
- //HeapPush(&hp, a[i]);
-
- //方法2
- hp.a[0] = a[i];
- AdjustDown(hp.a, hp.size, 0);//==>为了保持是小堆
- }
- }
- HeapPrint(&hp);
-
- //HeapDestroy(&hp);
- }
- void TestTopk()
- {
- int n = 10000;
- int* a = (int*)malloc(sizeof(int) * n);
- srand(time(0));
- for (int i = 0; i < n; ++i)
- {
- //随机生成数字,%100w就保证了数字小于100w
- a[i] = rand() % 1000000;
- }
- //手动设置10个大于100w的数字( 即:要选出的K个最大数 )
- a[5] = 1000000 + 1;
- a[1231] = 1000000 + 2;
- a[531] = 1000000 + 3;
- a[5121] = 1000000 + 4;
- a[115] = 1000000 + 5;
- a[2335] = 1000000 + 6;
- a[9999] = 1000000 + 7;
- a[76] = 1000000 + 8;
- a[423] = 1000000 + 9;
- a[3144] = 1000000 + 10;
- PrintTopK(a, n, 10);
- }
- int main()
- {
- TestTopk();
-
- return 0;
- }
- //Heap.h文件
- #pragma once
- #include<stdio.h>
- #include<stdlib.h>
- #include<assert.h>
- #include<stdbool.h>
-
- //实现大堆
- typedef int HPDataType;
- //定义堆
- typedef struct Heap
- {
- HPDataType* a;
- int size;
- int capacity;
- }HP;
-
-
- //初始化堆
- void HeapInit(HP* hp);
-
- //交换父子结点数据
- void Swap(HPDataType* px, HPDataType* py);
-
- //打印堆内数据
- void HeapPrint(HP* hp);
-
- //堆为空
- bool HeapEmpty(HP* hp);
-
- //销毁堆
- void HeapDestroy(HP* hp);
-
- //数据插入堆
- void HeapPush(HP* hp, HPDataType x);
-
- //向上调整
- void AdjustUp(int* a, int child);
-
- //删除堆顶数据
- void HeapPop(HP* hp);
-
- //向下调整
- void AdjustDown(int* a, int n, int parent);
-
- //获取堆顶数据
- HPDataType HeapTop(HP* hp);
- //Heap.c文件
- #define _CRT_SECURE_NO_WARNINGS
- #include"Heap.h"
-
- //初始化堆
- void HeapInit(HP* hp)
- {
- assert(hp);
-
- hp->a = NULL;
- hp->size = hp->capacity = 0;
- }
- //销毁堆
- void HeapDestroy(HP* hp)
- {
- assert(hp);
- free(hp->a);
- hp->capacity = hp->size = 0;
- }
- //交换父子结点数据
- void Swap(HPDataType* px, HPDataType* py)
- {
- HPDataType tmp = *px;
- *px = *py;
- *py = tmp;
- }
- //获取堆顶数据
- HPDataType HeapTop(HP* hp)
- {
- assert(hp);
- assert(!HeapEmpty(hp));
-
- return hp->a[0];
- }
- //向上调整(小堆)
- void AdjustUp(int* a, int child)
- {
- assert(a);
-
- int parent = (child - 1) / 2;
- //while (parent >= 0)
- while (child > 0)
- {
- if (a[child] < a[parent])
- {
- /*HPDataType tmp = a[child];
- a[child] = a[parent];
- a[parent] = tmp;*/
- Swap(&a[child], &a[parent]);
-
- child = parent;
- parent = (child - 1) / 2;
- }
- else
- {
- break;
- }
- }
- }
- //往堆插入数据
- void HeapPush(HP* hp, HPDataType x)
- {
- assert(hp);
- //不够就扩容
- if (hp->size == hp->capacity)
- {
- int newcapacity = hp->capacity == 0 ? 4 : hp->capacity * 2;
- HPDataType* tmp = realloc(hp->a, sizeof(HPDataType) * newcapacity);
- if (tmp == NULL)
- {
- printf("realloc fail!\n");
- exit(-1);
- }
-
- hp->a = tmp;
- hp->capacity = newcapacity;
- }
-
- hp->a[hp->size] = x;
- hp->size++;
-
- AdjustUp(hp->a, hp->size - 1);
- }
- //判断堆是否为空
- bool HeapEmpty(HP* hp)
- {
- assert(hp);
-
- return hp->size == 0;
- }
- //堆的数据个数
- int HeapSize(HP* hp)
- {
- assert(hp);
-
- return hp->size;
- }
- //打印堆内数据
- void HeapPrint(HP* hp)
- {
- for (int i = 0; i < hp->size; ++i)
- {
- printf("%d ", hp->a[i]);
- }
- printf("\n");
- }
- //向下调整(小堆)
- void AdjustDown(int* a, int n, int parent)
- {
- assert(a);
-
- int child = parent * 2 + 1;//左孩子
- while (child < n)
- {
- //选出小孩子
- if (child + 1 < n && a[child + 1] < a[child])
- child++;
-
- //交换 并 迭代 parent 和 child
- if (a[parent] > a[child])
- {
- Swap(&a[parent], &a[child]);
- parent = child;
- child = parent * 2 + 1;
- }
- else
- {
- break;
- }
- }
- }
- //删除堆顶数据
- void HeapPop(HP* hp)
- {
- assert(hp);
- assert(!HeapEmpty(&hp));
-
- Swap(&hp->a[0], &hp->a[hp->size - 1]);//堆顶数据与末尾数据交换
- hp->size--;
-
- AdjustDown(hp->a, hp->size, 0);
- }
测试效果
堆排序 - 升序 - 空间复杂度为O(N)的写法 (不推荐)
堆排序算法(Test.c文件)
该算法是建立小堆,并且用了HeapPush等建堆操作;所以是额外开辟使用了空间,并且还得事先实现堆以及堆的操作才能做。
而堆本身就是数组,那么能否直接对数组a进行构建堆?(不用堆的任何相关操作~)
- //Test.c文件
- #define _CRT_SECURE_NO_WARNINGS
- #include"Heap.h"
-
- //堆排序 - 升序 - 空间复杂度( O(N) )
- //降序同理,Push、Pop小堆变大堆即可
- void HeapSort(int* a, int n)
- {
- HP hp;
- HeapInit(&hp);
- //建立一个小堆
- for (int i = 0; i < n; ++i)
- {
- HeapPush(&hp, a[i]);//小堆的HeapPush
- }
-
- //Pop N 次
- for (int i = 0; i < n; ++i)
- {
- a[i] = HeapTop(&hp);
- HeapPop(&hp);//小堆的HeapPop
- }
- //HeapDestroy(&hp);
- }
- int main()
- {
- int a[] = { 70,56,30,25,15,10,75 };
- for (int i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
- {
- printf("%d ", a[i]);
- }
- printf("\n");
-
- HeapSort(a, sizeof(a) / sizeof(a[0]));
-
- for (int i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
- {
- printf("%d ", a[i]);
- }
- printf("\n");
- return 0;
- }
该程序空间复杂度是O(N),那么能否优化到O(1)呢?
(即:不能用Heap避免了HeapPush开辟新空间,直接对数组a进行操作)
堆排序 - 升序 - 空间复杂度为 O(1) 的写法 (推荐!)
考虑到原来使用了HeapPush建堆,新开辟了N个空间。所以空间复杂度是O(N),而优化到O(1)即优化建堆的操作。
所以,优化建堆的操作就是对数组a直接操作,不开辟新空间。其有两种方式:
那么建堆完成后,如何实现升序呢?
所以,排升序,用大堆+向下调整建堆方式
堆排序:
*注释:大小堆,在堆排序中的区别就体现在AdjustDown函数实现的是大堆还是小堆
- void HeapSort(int* a, int n)
- {
- //把a构建成堆(向下调整)
- //注意:需要找到 [最后一个节点] 的 [父亲节点] ,从那开始,向下调整
-
- int end = n - 1;//最后一个节点
- for (int i = (end - 1) / 2; i >= 0; i--)
- {
- AdjustDown(a, n, i);
- }
-
- //实现升序
- end = n - 1;//最后一个数
- for (int i = end; i > 0; i--)
- {
- Swap(&a[i], &a[0]);
- AdjustDown(a, i, 0);
- }
- }
- //向下调整(大堆)
- void AdjustDown(int* a, int n, int parent);
- //堆排序 - 升序 -(向下调整建大堆+大堆)
- void HeapSort(int* a, int n)
- {
- //把a构建成堆(向下调整)
- //注意:需要找到 [最后一个节点] 的 [父亲节点] ,从那开始,向下调整
-
- int end = n - 1;//最后一个节点
- for (int i = (end - 1) / 2; i >= 0; i--)
- {
- AdjustDown(a, n, i);
- }
-
- //实现升序
- end = n - 1;//最后一个数
- for (int i = end; i > 0; i--)
- {
- Swap(&a[i], &a[0]);
- AdjustDown(a, i, 0);
- }
- }
- //向下调整(大堆)
- void AdjustDown(int* a, int n, int parent)
- {
- assert(a);
-
- int child = parent * 2 + 1;//左孩子
- while (child < n)
- {
- //选出大孩子
- if (child + 1 < n && a[child + 1] > a[child])
- child++;
-
- //交换 并 迭代 parent 和 child
- if (a[parent] < a[child])
- {
- Swap(&a[parent], &a[child]);
- parent = child;
- child = parent * 2 + 1;
- }
- else
- {
- break;
- }
- }
- }
整体代码
- //堆排序 - 升序 -(向下调整建大堆+大堆)
- void HeapSort(int* a, int n)
- {
- //建堆操作:
- //方法1:
- //把a构建成堆(向上调整)
- /*for (int i = 0; i < n; i++)
- {
- AdjustUp(a, i);
- }
- */
-
- //方法2:
- //把a构建成堆(向下调整)
- //注意:需要找到 [最后一个节点] 的 [父亲节点] ,从那开始,向下调整
-
- int end = n - 1;//最后一个节点
- for (int i = (end - 1) / 2; i >= 0; i--)
- {
- AdjustDown(a, n, i);
- }
-
- //实现升序
- end = n - 1;//最后一个数
- for (int i = end; i > 0; i--)
- {
- Swap(&a[i], &a[0]);
- AdjustDown(a, i, 0);
- }
- }
- int main()
- {
- int a[] = { 70,56,30,25,15,10,75,33,50,69 };
- for (int i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
- {
- printf("%d ", a[i]);
- }
- printf("\n");
-
- HeapSort(a, sizeof(a) / sizeof(a[0]));
-
- for (int i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
- {
- printf("%d ", a[i]);
- }
- printf("\n");
- return 0;
- }
同理,堆排序 - 排降序是建立小堆
- //向下调整(小堆)
- void AdjustDown(int* a, int n, int parent);
- //堆排序 - 降序
- void HeapSort(int* a, int n)
- {
- //把a构建成堆(向下调整)
- //注意:需要找到 [最后一个节点] 的 [父亲节点] ,从那开始,向下调整
-
- int end = n - 1;//最后一个节点
- for (int i = (end - 1) / 2; i >= 0; i--)
- {
- AdjustDown(a, n, i);
- }
-
- //实现降序
- end = n - 1;//最后一个数
- for (int i = end; i > 0; i--)
- {
- Swap(&a[i], &a[0]);
- AdjustDown(a, i, 0);
- }
- }
- //向下调整(小堆)
- void AdjustDown(int* a, int n, int parent)
- {
- assert(a);
-
- int child = parent * 2 + 1;//左孩子
- while (child < n)
- {
- //选出小孩子
- if (child + 1 < n && a[child + 1] < a[child])
- child++;
-
- //交换 并 迭代 parent 和 child
- if (a[parent] > a[child])
- {
- Swap(&a[parent], &a[child]);
- parent = child;
- child = parent * 2 + 1;
- }
- else
- {
- break;
- }
- }
- }
整体代码:
- //堆排序 - 降序
- void HeapSort(int* a, int n)
- {
- //建堆操作:
- //方法1:
- //把a构建成堆(向上调整)
- /*for (int i = 0; i < n; i++)
- {
- AdjustUp(a, i);
- }
- */
-
- //方法2:
- //把a构建成堆(向下调整)
- //注意:需要找到 [最后一个节点] 的 [父亲节点] ,从那开始,向下调整
-
- int end = n - 1;//最后一个节点
- for (int i = (end - 1) / 2; i >= 0; i--)
- {
- AdjustDown(a, n, i);
- }
-
- //实现降序
- end = n - 1;//最后一个数
- for (int i = end; i > 0; i--)
- {
- Swap(&a[i], &a[0]);
- AdjustDown(a, i, 0);
- }
- }
- int main()
- {
- int a[] = { 70,56,30,25,15,10,75,33,50,69 };
- for (int i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
- {
- printf("%d ", a[i]);
- }
- printf("\n");
-
- HeapSort(a, sizeof(a) / sizeof(a[0]));
-
- for (int i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
- {
- printf("%d ", a[i]);
- }
- printf("\n");
- return 0;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。