数据结构与算法(C++)堆,完全二叉树 因为连续所以数组实现 push放入最后向上渗透 pop把最后的放到顶然后向下渗透 放入堆然后取出即可完成排序

1. 数据结构中 堆 的基本概念

内容来自视频 https://www.bilibili.com/video/av31763085?from=search&seid=12254491620082291737

用途: 经常用堆做 优先队列排序(全部插入,全部取出,排序完成)
在这里插入图片描述
完全二叉树:依次排列,1-2-3-4-5-6-7-8-9-10-11-12, 中间都存在节点
不完全二叉树: 依次排列,1-2-3-4-5-6-7-8- * -10-11-12, 中间第9个节点缺失

完全二叉树可以用数组来完成,按照节点顺序依次存储在数组中。
在这里插入图片描述
堆分为大顶堆(最大堆)和小顶堆(最小堆)两种,不分左右子节点,只要都>或<父节点就行
在这里插入图片描述

2. 堆的一些操作, push, pop, top

对于最大堆
  1. 添加新节点(push):先把节点插入到最后,然后向上依次比较,满足则向上冒泡,否则停止。找到父节点的方法,fatherIndex = ( childIndex - 1 ) / 2
  2. 删除根节点(pop):先把最后的节点放到根节点,然后依次和子节点比较,满足则向下冒泡,否则停止。
    在这里插入图片描述
2.1 添加新节点流程(push):

2.1.1添加的是最大的数
在这里插入图片描述
2.1.2 添加的不是最大的数
在这里插入图片描述

2.2 删除根节点的流程(pop)

在这里插入图片描述

3. 代码

max_heap.h
#ifndef __MAX_HEAP_H
#define  __MAX_HEAP_H

// 数据结构中的堆, 完全二叉树结构,用数组实现
// 这里以最大堆为例, 实现push 和 pop 和 top 三个操作
/*
==  <--- top
==  
==  <--- current 
==
*/
template<typename T>
void swap(T& a, T& b)
{
    T t = b;
    b = a;
    a = t;
}

template<class T>
class maxHeap
{
public:
    maxHeap(const int maxsize = 20)
    : arryHeap(new T[maxsize]), maxSize(maxsize), current(0) 
    { }
    ~maxHeap() { delete[] arryHeap; }
    void Push(const T item); // 添加节点
    void Pop();              // 删除根节点
    T Top() const;
    void show() const;
private:
    void bubUp();   // 向上冒泡, 在插入节点时依次和 父节点比较
    void bubDown(); // 向下冒泡, 在删除节点时依次和 子节点比较
    T* arryHeap;
    int maxSize;
    int current;
};
template<class T>
void maxHeap<T>::Push(const T item)
{
    if(current == maxSize) { std::cerr << "Heap has fulled.\n"; return; }
    arryHeap[current] = item; // 先把数据放到最后
    if(current) // 如果不是空的 才开始向上冒泡 
    {
        bubUp();
    }
    current++;  // 只要添加了节点就要++ 
}
template<class T>
void maxHeap<T>::bubUp()
{
    int positin = current;            // 从最末尾开始向上冒泡
    int fatherP = (positin - 1) >> 1; // 获取父节点位置 position为1时fatherP为0  position为0时fatherP为-1
    // 在当前节点不是根节点的前提下, 只要当前节点比父节点大 都要交换, 否则就停止,返回
    while(fatherP >= 0 && arryHeap[positin] > arryHeap[fatherP]) 
    {
        swap(arryHeap[positin], arryHeap[fatherP]);
        positin = fatherP;            // 刷新 当前位置
        fatherP = (positin - 1) >> 1; // 刷新 父节点位置
    }
}
template<class T>
void maxHeap<T>::Pop()
{
    if(!current) { std::cerr << "Heap is empty.\n"; return; }
    // 如果完全二叉树不为空
    arryHeap[0] = arryHeap[--current]; // 先把最后的节点 赋给 根节点, 然后丢弃根节点, ***current-1才是最后节点的数据***
    bubDown(); 

}
template<class T>
void maxHeap<T>::bubDown()
{
    int position = 0;
    int lchild = (position << 1) + 1;
    int rchild = lchild + 1;
    while(lchild < current) // 只要存在左节点,  当只有根节点时不操作
    {   
        // 如果比 左右子节点都小, 比较两个子节点大小, 然后跟大的交换  
        // (就算右节点不存在了,通过Top找不到,但是数据还算存在的,所以在比较时不会出错)
        if(arryHeap[position] < arryHeap[lchild] && arryHeap[position] < arryHeap[rchild]) 
        {
            if(arryHeap[lchild] > arryHeap[rchild])
            {
                swap(arryHeap[position], arryHeap[lchild]);
                position = lchild; // 记录向下冒泡的位置
            }    
            else
            {
                swap(arryHeap[position], arryHeap[rchild]);
                position = rchild; // 记录向下冒泡的位置
            }
        }    
        else if(arryHeap[position] < arryHeap[lchild]) // 只比左子节点的小
        {
            swap(arryHeap[position], arryHeap[lchild]);
            position = lchild;
        }
        else if(arryHeap[position] < arryHeap[rchild]) // 只比右子节点小
        {
            swap(arryHeap[position], arryHeap[rchild]);
            position = rchild;
        }
        else return;                                   // 既不比左子节点小 也不必右小, 完成, 结束
            
        lchild = (position << 1) + 1; // 继续查找
        rchild = lchild + 1;          // 继续查找 ***** rchild - lchild == 1 *******
    }
}
template<class T>
T maxHeap<T>::Top() const // 返回根节点
{
    if(!current)
    {
        std::cerr << "Heap is empty.\n";
        return 9999;
    } 
    return arryHeap[0];
}
template<class T>
void maxHeap<T>::show() const
{
    int i = 0;
    std::cout << "--------------------------\n";
    while(i < current) std::cout << arryHeap[i++] << " ";
    std::cout << "nums:" << current << std::endl;
    std::cout << "--------------------------\n";
}


#endif
main.cpp
#include <iostream>
#include "max_heap.h"

using namespace std;

int main()
{
    maxHeap<int> heap(30);
    heap.Push(10); 
    heap.Push(5);    // cout << heap.Top() << endl;
    heap.Push(21);   // cout << heap.Top() << endl;
    heap.Push(55);
    heap.Push(7);
    heap.show();

    heap.Pop();  heap.show();
    heap.Pop();  heap.show();
    heap.Pop();  heap.show();
    heap.Pop();  heap.show();
    heap.Pop();   

    // 用堆来 排序
    maxHeap<int> heap1(100);
    int a[10] = {2, 33, 44, 1, 3, 12, 54, -5, 22, 0};
    for(int i = 0; i < 10; i++) heap1.Push(a[i]); // 压入堆  
    for(int i = 0; i < 10; i++) 
    {
        a[i] = heap1.Top(); // 取出
        heap1.Pop();        // 删除
    }
    for(int i = 0; i < 10; i++) cout << a[i] << " ";
    cout << endl;

/* output:
    --------------------------
    55 21 10 5 7 nums:5
    --------------------------
    --------------------------
    21 7 10 5 nums:4
    --------------------------
    --------------------------
    10 7 5 nums:3
    --------------------------
    --------------------------
    7 5 nums:2
    --------------------------
    --------------------------
    5 nums:1
    --------------------------
    54 44 33 22 12 3 2 1 0 -5 
*/
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值