数据结构之二叉树中的堆

树的概念

节点的度,一个节点的度是这个节点有多少个直属子节点。

如图中A的度为2.

叶节点||终端节点,是最末端的节点如H,I,E,F,J,K;

非终端节点,除叶节点外的所有节点

双亲节点,如A是父节点,BC是A的子节点,是相对的。

兄弟节点链接在同一双亲节点下的节点如BC

树的度是最大的度

节点的层,从根开始为第一层

树的高度,最大的层

堂兄弟,双亲节点在同一层上如H,JK

子孙,任意节点的子节点,如图中除A以外的节点都是A的子孙

森林,由多棵互不相交的树组成。

任何一棵的树节点不能相交,它是非线性节点。

二叉树

它是一个有限的集合,每个节点只能有最多两个节点向下延申。

满二叉树,每一层都是满的。

完全二叉树,前n-1层是满的。

大堆和小堆必须是完全二叉树。根可以是最大值和最小值

小堆,每一给父亲的值<=儿子的值

大堆,每一个父亲的值>=儿子的值

小堆二叉树的实现

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>包含的头文件
typedef int fish;
typedef struct tree {
    fish* a;//可变数组
    int size;//元素个数
    int space;//空间大小
}tree;

void cs(tree* pst);//初始化

cpp 复制代码
void cs(tree* pst) {
    assert(pst);
    pst->a = NULL;
    pst->size = pst->space = 0;
}

void xh(tree* pst);//销毁

cpp 复制代码
void xh(tree* pst){
    assert(pst);
    free(pst->a);
    pst->size = 0;
    pst->space = 0;
}

void push(tree* pst, fish x);//插入

cpp 复制代码
void push(tree* pst, fish x) {
    assert(pst);
    if (pst->space == pst->size) {//判断容量够不够
        int n = pst->space == 0 ? 4 : pst->space * 2;
        fish* cur = (fish*)realloc(pst->a,sizeof(fish) * n);
        if (cur == NULL) {
            perror("malloc fail");
            return;
        }
        pst->space = n;
        pst->a = cur;
    }
    pst->a[pst->size] = x;//插入数据
    just(pst->a, pst->size);//调整为小堆结构
    pst->size++;
}

void just(fish* a, int chile);

cpp 复制代码
void just(fish* a, int chile) {//传入数组和最后输入的数据
    int parent = (chile - 1) / 2;//上一层的数据
    while (chile > 0) {//不是最顶的数据
        if (a[chile] < a[parent]) {//如果数据小,向上交换;
            sw(&a[chile], &a[parent]);
            chile = parent;//更新上一层
            parent = (chile - 1) / 2;
        }
        else {
            break;
        }
    }
}

void pop(tree* pst);//删除堆顶;、

cpp 复制代码
void pop(tree* pst) {
    assert(pst);
    assert(pst->size > 0);
    sw(&(pst->a[pst->size - 1]), &pst->a[0]);//交换头和尾,保持除头以外还是小堆结构
    pst->size--;//删除尾
    xiatiao(pst->a, pst->size, 0);
}

void xiatiao(fish*a,int n,int parent)

cpp 复制代码
void sw(fish* p1, fish* p2) {
        int t = *p1;
        *p1 = *p2;
        *p2 = t;
}

void xiatiao(fish*a,int n,int parent) {
    int child = parent * 2 + 1;//下一层的节点
    while (child < n) {//不超过最后一层的数据范围
        if ( child+1<n && a[child + 1]<a[child]) {//取较小的节点
            ++child;
        }
        if (a[child] < a[parent]) {//比较节点,小的在上
            sw(&a[child], &a[parent]);
            parent = child;
            child = parent * 2 + 1;//下移一层
        }
        else {
            break;
        }
    }
}

取堆顶和判空

cpp 复制代码
fish top(tree* pst) {//返回堆顶数据
    return pst->a[0];
}
bool emp(tree* pst) {//判空
    assert(pst);
    if (pst->size == 0)
        return true;
    return false;
}

大堆

改变just的语法

void just(fish* a, int chile);

cpp 复制代码
void just(fish* a, int chile) {//传入数组和最后输入的数据
    int parent = (chile - 1) / 2;//上一层的数据
    while (chile > 0) {//不是最顶的数据
        if (a[chile] >a[parent]) {//如果数据大,向上交换;
            sw(&a[chile], &a[parent]);
            chile = parent;//更新上一层
            parent = (chile - 1) / 2;
        }
        else {
            break;
        }
    }
}

void pop(tree* pst);//删除堆顶;、

void xiatiao(fish*a,int n,int parent)

cpp 复制代码
void xiatiao(fish*a,int n,int parent) {
    int child = parent * 2 + 1;//下一层的节点
    while (child < n) {//不超过最后一层的数据范围
        if ( child+1<n && a[child + 1]>a[child]) {da的节点
            ++child;
        }
        if (a[child] < a[parent]) {//比较节点,小的在上
            sw(&a[child], &a[parent]);
            parent = child;
            child = parent * 2 + 1;//下移一层
        }
        else {
            break;
        }
    }
}

其他相同

just函数可以直接把一个数组变成堆并进行堆排序

堆排序的时间复杂度分析

对于满二叉树来说。

设节点个数总数为N,层为H;

N=2^0+2^1+2^2.....2^(h-1)=2^(h)-1

H=log2(N+1)

向下堆排时间从倒数第二层开始排

T= 2^(h-2)*1 + 2^(h-3)*2......2^1*(h-2)+2^0*(h-1)

2T=2^(h-1)*1+ 2^(h-2)*2 +2^(h-3)*3......2^1*(h-1)

T=2^(h-1)*1+2^(h-2)+2^(h-3)....2^1-h-1;

T=2^(h)-h-1

T=N+1-log2(N+1)-1

O(N);

向下调整是多乘小

向上调整是多乘多

T=2^1*1+2^2*2...2^(h-1)*(h-1)

T=(h−2)⋅2^h+2

T=(log[N+1]-2)*(N+1)+2

O(N*log[N])

堆的使用

取最大的k个数,建一个有k个数小堆,把后进来的数和堆顶进行比较,相当于把k个数中最小的去除,后再拿出一个最小的放在第一位。

相关推荐
Jayden_Ruan1 天前
C++分解质因数
数据结构·c++·算法
bubiyoushang8881 天前
MATLAB实现雷达恒虚警检测
数据结构·算法·matlab
wu_asia1 天前
编程技巧:如何高效输出特定倍数数列
c语言·数据结构·算法
星火开发设计1 天前
C++ queue 全面解析与实战指南
java·开发语言·数据结构·c++·学习·知识·队列
橘颂TA1 天前
【剑斩OFFER】算法的暴力美学——力扣 394 题:字符串解码
数据结构·c++·结构与算法
栈与堆1 天前
LeetCode 19 - 删除链表的倒数第N个节点
java·开发语言·数据结构·python·算法·leetcode·链表
-森屿安年-1 天前
unordered_map 和 unordered_set 的实现
数据结构·c++·散列表
txinyu的博客1 天前
map和unordered_map的性能对比
开发语言·数据结构·c++·算法·哈希算法·散列表
im_AMBER1 天前
Leetcode 101 对链表进行插入排序
数据结构·笔记·学习·算法·leetcode·排序算法
予枫的编程笔记1 天前
【Java集合】深入浅出 Java HashMap:从链表到红黑树的“进化”之路
java·开发语言·数据结构·人工智能·链表·哈希算法