• 数据结构—堆(C语言实现)


    目录

    堆是什么?

    一、大堆

    一、小堆

    如何实现堆?

    代码实现 ?

    一、定义堆的结构体

    二、初始化堆

    三、构建堆

    1.利用向下调整算法

    2.开始构建

    四、插入元素

    1.利用向上调整算法

    五、取出堆顶元素、销毁堆

    六、堆排序

    Extra:TOP K 问题


    堆是什么?

     堆是数据结构的一种,它的逻辑结构是一个完全二叉树,存储结构是一个数组。

    一、大堆

     每个父节点都大于子节点

    一、小堆

    每个父节点都小于子节点

    如何实现堆?

    数组即可,利用完全二叉树的特点。(后面将不断用到)

     

    代码实现 ?

    一、定义堆的结构体

    1. typedef int E;
    2. typedef struct my_heap {
    3. E* _heap;
    4. int _size;
    5. int _capacity;
    6. }my_heap;

    二、初始化堆

    1. void initiaze(my_heap* heap, E* arry, int n) {
    2. assert(arry);
    3. assert(heap);
    4. heap->_heap = (E*)malloc(n * sizeof(E));
    5. assert(heap);
    6. heap->_capacity = n;
    7. heap->_size = n;
    8. memcpy(heap->_heap, arry, n * sizeof(E));//内存拷贝
    9. }

    三、构建堆

    1.利用向下调整算法

    1. //小堆-向下调整算法
    2. void heap_down(my_heap* heap,int root) {
    3. int parent = root;
    4. int child = parent * 2 + 1;
    5. while(child_size){
    6. if (child + 1 _size && heap->_heap[child + 1] < heap->_heap[child]) {
    7. child++;
    8. }
    9. if (heap->_heap[child] < heap->_heap[parent]) {
    10. swap(&(heap->_heap[child]), &(heap->_heap[parent]));
    11. parent = child;
    12. child = child * 2 + 1;
    13. }
    14. else {
    15. break;
    16. }
    17. }
    18. }
    2.开始构建

     会向下调整算法还不够,向下调整算法只能用于左右子树都已经是堆的情况下。

    而如何使每一颗左右子树都是堆,需要从最小不可拆分的节点开始,依次往前递推。

    每次对这些节点使用向下调整算法,

    1. //堆建立-小堆
    2. void com_heap(my_heap* heap) {
    3. assert(heap);
    4. int i =0;
    5. for (i= (heap->_size - 2) / 2; i >= 0; i--) {
    6. heap_down(heap, i);
    7. }
    8. }

    四、插入元素

     

    要保持小堆,除了可以用上面构建堆的方法,重新构建一次,但这样时间复杂度就太高了,这时就需要向上调整算法了。

    1.利用向上调整算法

     

    1. //向上调整算法
    2. void heap_up(my_heap* heap,int child){
    3. assert(heap);
    4. int parent = (child-1)/2;
    5. while(child>0){
    6. if(heap->_heap[child]_heap[parent]){
    7. swap(&(heap->_heap[child]), &(heap->_heap[parent]));
    8. child=parent;
    9. parent=(child-1)/2;
    10. }else{
    11. break;
    12. }
    13. }
    14. }
    15. //往堆中添加元素
    16. void heap_push(my_heap* heap,E ele){
    17. assert(heap);
    18. //如果空间不够扩容,每次扩容为上次容量的两倍
    19. if(heap->_size==heap->_capacity+1){
    20. heap->_capacity *=2;
    21. heap->_heap=realloc(heap,heap->_capacity*(sizeof(E)));
    22. if(!heap)return;
    23. }
    24. heap->_heap[heap->_size++]=ele;
    25. heap_up(heap,heap->_size-1);
    26. }

    五、取出堆顶元素、销毁堆

    1. //从堆中取出元素,取出堆顶元素
    2. E heap_hatch(my_heap* heap) {
    3. assert(heap);
    4. return heap->_heap[0];
    5. }
    1. //堆销毁
    2. void heap_destroy(my_heap* heap) {
    3. assert(heap);
    4. free(heap->_heap);
    5. heap->_heap = NULL;
    6. }

    六、堆排序

    前面我们已经了解了构造堆,插入元素,如果要把这个数组的数从小排到大,能否使用堆来进行呢。

    首先,我们要明白升序要大堆,降序要小堆。(后面解释)

     

     这就是堆排序的思想,不断拿到堆顶元素,放到数组最后,得到最小、第二小、第三小......的数字,实现降序,你也知道了为什么要使用大堆排升序,小堆排降序。

    下面是升序代码:

    1. //堆排序-升序
    2. E* heap_sort(int *arry,int len) {
    3. //建大堆
    4. assert(arry);
    5. if (len == 0)return NULL;
    6. my_heap heap;
    7. initiaze(&heap, arry, len);
    8. com_heap_big(&heap);
    9. //堆建好后,每次把堆最后一个元素与堆顶替换,再将堆大小减一,进行向下调整算法
    10. int start = 0;
    11. int end = len - 1;
    12. while (end) {
    13. swap(heap._heap + end, heap._heap + start);
    14. end--;
    15. heap._size--;
    16. heap_down_big(&heap, 0);
    17. }
    18. memcpy(arry, heap._heap, len*(sizeof(E)));
    19. heap_destroy(&heap);
    20. return arry;
    21. }

    Extra:TOP K 问题

    要求:从N个数中找到最小或最大的前k个数

     

    相信你已经会了,那么要求最小的k个数就需要建立一个k个元素的大堆了。 

    1. //topk问题-最大k个数
    2. int* top_k(int* arry,int len,int k) {
    3. assert(arry);
    4. //选数组前k个数组成k个元素的堆
    5. int* heap_k = (int*)malloc(k * sizeof(int));//因为要把数组传出去,动态开辟
    6. memcpy(heap_k, arry, k * sizeof(int));
    7. //构建堆
    8. my_heap heap;
    9. heap._heap = heap_k;
    10. heap._size = k;
    11. heap._capacity = k;
    12. com_heap(&heap);
    13. //依次拿堆顶元素与数组从k开始的元素进行比较
    14. for (int i = k; i < len; i++) {
    15. if (heap._heap[0] < arry[i]) {
    16. swap(heap._heap + 0, arry + i);
    17. //向下调整
    18. heap_down(&heap, 0);
    19. }
    20. }
    21. //此时heap里面的元素就是最大的k个数了
    22. return heap._heap;
    23. }

     

  • 相关阅读:
    在 SPRING Boot JPA 中调用带有本机查询中的参数的存储过程
    计算机毕业设计JavaWeb网上购书后台管理系统(源码+系统+mysql数据库+lw文档)
    《The Rise and Potential of Large Language Model Based Agents: A Survey》全文翻译
    a-select 下拉列表正常展示
    VHDL基础知识笔记(1)
    Git 恢复已删除的branch
    [模型]拉格朗日插值法
    NPDP产品经理认证怎么报名?考试难度大吗?
    模拟考试题库答题流量主小程序开发
    ES5+ 和 ES6
  • 原文地址:https://blog.csdn.net/weixin_56821642/article/details/133210771