这几天准备把三种比较重要的数据结构整理下,分别是堆,AVL树,红黑树。今天谈谈堆吧。
简介:
https://baike.baidu.com/item/堆/20606834?fr=aladdin
简单的介绍百度百科上就有,他是一种二叉树形式的数据结构,主要是用来维护数据中的最小和最大值,且插入和删除操作的复杂度都为 O ( l o g n ) O(logn) O(logn). 二叉树相信大家都知道吧(不知道的朋友请先百度一下二叉树)。一个堆其实就是一颗二叉树,而且是平衡二叉树,这也就保证了插入和删除的复杂度。
堆分为最小堆和最大堆,以最小堆来阐述,最小堆满足一个特性,那就是父结点的值要比其左右子结点的来得小 ,最大堆同理。为了维护在对堆的插入和删除操作后破坏堆的特性,引入了两个调整的过程,分为向下调整和向上调整。具体一点的可以参考代码。(代码有点儿多,如有错误还请指出,谢谢)

C++代码实现

//  小学生一发的刷题之路
//  数据结构-堆
//  手动实现下最小堆;
//
//

#pragma comment(linker, "/STACK:1024000000,1024000000")     //解决爆栈,手动加栈;
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#include <queue>
#include <deque>                //双向队列;
#include <cmath>
#include <set>
#include <stack>
#include <map>
#include <vector>
#include <cstdlib>
#include <iomanip>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const double PI=acos(-1.0);
const double eps=1e-10;
const int maxn=1e2+5;
const int maxm=1e3+5;
const ll mod=1e9+7;
const int INF=1e9;
const ll llINF=1e18;
template<class T>
inline void read(T &ret){       //快速输入模版;
    ret=0;
    int f=1;
    char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-') f=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9'){
        ret=ret*10+c-'0';
        c=getchar();
    }
    ret*=f;
}
template <class T>
inline void out(T ret){     //快速输出模版;
    if(ret>9)
    {
        out(ret/10);
    }
    putchar(ret%10+'0');
}

template<class T>
class heap{
public:
    heap();           //无参构造函数;
    heap(int n);        //带参构造函数;
    T top()const{ return arr[0];};          //取堆顶元素;
    void pop();         //删除堆顶元素;
    void push(T x);   //插入元素;
    int size()const{ return CurrentSize;};         //返回堆的元素个数;
    bool empty()const{ return CurrentSize==0?true:false;};       //判断堆是否为空;
    void down(int start,int end);        //向下调整;
    void up(int start,int end);          //向上调整;
    void print();       //打印堆里面的元素;
private:
    int MaxSize;         //堆的最大容量;
    int Currentpos;      //当前的位置;
    int CurrentSize;     //当前的位置;
    T arr[maxn];
};

template<class T>
heap<T>::heap(){
    MaxSize=maxn;
    CurrentSize=0;
}
template<class T>
heap<T>::heap(int n){
    MaxSize=maxn;
    CurrentSize=n;
    for(int i=0;i<n;i++){
        cin>>arr[i];
    }
    Currentpos=(CurrentSize-2)/2;       //找到调整结点;
    while(Currentpos>=0){               //调整整棵树;
        down(Currentpos,n-1);
        Currentpos--;
    }
}

template<class T>
void heap<T>::up(int start,int end){
    //向上调整;
    int i=start,j=(start-1)/2;      //j为i的父结点;
    while(j>=end){
        if(i==0){       //避免出现死循环;
            break;
        }
        if(arr[i]<arr[j]){
            swap(arr[i],arr[j]);
        }
        i=j;
        j=(i-1)/2;
    }
}
template<class T>
void heap<T>::down(int start,int end){
    //向下调整;
    int i=start,j=2*start+1;        //j为i左子结点;
    while(j<=end){
        if(j<end&&arr[j]>arr[j+1]){     //找到左右字数最小的点;
            j++;
        }
        if(arr[j]<arr[i]){              //子结点的值小于父结点的值;
            swap(arr[j],arr[i]);
        }
        i=j;
        j=2*i+1;
    }
}
template<class T>
void heap<T>::pop(){
    if(CurrentSize==0){             //堆里面没有元素;
        return;
    }
    arr[0]=arr[CurrentSize-1];      //把堆顶元素用最后一个元素代替;
    CurrentSize--;
    down(0,CurrentSize-1);            //向下调整整棵树;
}

template<class T>
void heap<T>::push(T x){
    if(CurrentSize==MaxSize){       //堆已满;
        cout<<"堆已满,插入元素失败"<<endl;
        return;
    }
    arr[CurrentSize]=x;               //把元素插入到最后一个位置;
    CurrentSize++;
    up(CurrentSize-1,0);     //向上调整整棵树;
}
template<class T>
void heap<T>::print(){         //打印堆里面的元素;
    for(int i=0;i<CurrentSize;i++){
        cout<<arr[i]<<endl;
    }
}

int main()
{
    //测试堆的各个功能;
    heap<int> node;
    for(int i=1;i<=10;i++){
        int x=rand();
        node.push(x);
    }
    
    while(!node.empty()){
        cout<<node.top()<<endl;
        node.pop();
    }
    return 0;
}

新的开始,每天都要快乐哈!
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值