最大(小)堆的创建、插入与删除

本文深入讲解了堆数据结构,包括最大堆和最小堆的概念,详细演示了如何通过数组实现堆的创建、插入元素和删除最小元素的过程。同时,介绍了堆排序的原理及其实现,分析了其时间复杂度为O(nlogn)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

①定义
最大堆:对于任意二叉树节点,左右孩子节点的值都小于父亲节点的值。即根节点的值最大
最小堆:同理
②最大(小)堆的创建
接下来演示最小堆的创建,最大堆同理
堆的结构体如下:(由结构体可以看出,该树是由数组来进行保存树)

typedef struct Node *heap;
struct Node{
    int* data;   //用来存储数据的数组
    int size;   //当前堆含有几个元素
};

创建一个空的堆:

heap create_empty_heap(int n){
    heap h = (heap)malloc(sizeof(struct Node));    
    h->data = (int *)malloc(sizeof(int) * (n+1));    
    h->size = 0;    
    h->data[0] = -9999; //创建最小堆的哨兵,进行上移的截止点,保证该data值一定最小    
    return h;
}

向最小堆中插入元素:

步骤:1.首先将size+1,并且直接将该元素直接插到最后一个节点,即完全二叉树
2.然后以此和父节点进行比较,若该节点比父节点小,则直接交换位置

void Insert(heap h,int x){
    int i = ++h->size;    
    for (;h->data[i/2] > x; i = i/2){        
        h->data[i] = h->data[i/2];    
    }    
    h->data[i] = x;
}

获取当前最小堆中最小元素,即根节点元素,data[1]
操作步骤:1.返回值就是直接返回根节点元素
2.然后将最后一个节点元素,即data[h->size] 默认放到根节点
3.然后维护该最小堆,从根节点Parent = 1,向下找两个儿子child节点中最小的节点
4.将该根节点值与两个儿子结点的值进行比较,如比两个儿子节点的值都大,则完成最小堆排序
否则,将该根节点与儿子节点交换位置,在循环该儿子节点为根节点进行排序最小堆

int delete_minheap(heap h){
    int x = h->data[h->size--];    
    int ans = h->data[1];    
    int child,parent;    
    for (parent = 1; parent * 2 <= h->size; parent = child){
            child = parent * 2;        
            if (child + 1 <= h->size && h->data[child+ 1] < h->data[parent])
                    child++;        
            if(h->data[child] > x)
                    break;
            h->data[parent] = h->data[child];
     }    
     h->data[parent] = x;    
     return ans;
}

③堆排序
堆排序的时间复杂度为nlogn ,因为遍历n个节点,每次获取最小值的时间复杂度为Logn(原因是每次获取最小值后,重构最小堆的时间复杂度为Logn,即为树的深度)
下面为堆排序的演示代码:

#include<time.h>
#include<stdio.h>
#include<iostream>
#include<vector>
#include<cstring>
#include<algorithm>
#include<set>
#include<stack>
using namespace std;
typedef struct Node *heap;
struct Node{
    int* data;    
    int size;
};
heap create_empty_heap(int n){
    heap h = (heap)malloc(sizeof(struct Node));    
    h->data = (int *)malloc(sizeof(int) * (n+1));    
    h->size = 0;    
    h->data[0] = -9999; //创建最小堆的哨兵,进行上移的截止点,保证该data值一定最小    
    return h;
}
void Insert(heap h,int x){
    int i = ++h->size;    
    for(;h->data[i/2] > x; i = i/2){
        h->data[i] = h->data[i/2];    
    }    
    h->data[i] = x;}int delete_minheap(heap h){
        int x = h->data[h->size--];    
        int ans = h->data[1];    
        int child,parent;    
        for (parent = 1; parent * 2 <= h->size; parent = child){
                child = parent * 2;
        if (child + 1 <= h->size && h->data[child+ 1] < h->data[parent])                 
                child++;        
        if(h->data[child] > x)
                break;        
        h->data[parent] = h->data[child];
     }    
     h->data[parent] = x;    
     return ans;
}
int main(){
    int n,data;    
    heap h;    
    cin >> n;    
    h = create_empty_heap(n);    
    for (int i = 1; i<=n; i++){        
        cin>>data;        
        Insert(h, data);
    }    
    for (int i = 1; i<=n; i++){
        cout << delete_minheap(h) << " ";
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值