堆的基本操作

简介: 堆的基本操作

1。堆的创建,及声明相关函数

#pragma once
#include"stdio.h"
#include"stdlib.h"
#include"assert.h"
#include"stdbool.h"
typedef int HPDataType;
typedef struct Heap{
    HPDataType *a;
    int size;
    int capacity;
}HP;
void Swap(HPDataType*ps,HPDataType*py);   //交换避免冗余
void HeapInit(HP*hp);                     //初始化
void HeapDestroy(HP*hp);                  //销毁
void HeapPush(HP*hp,HPDataType X);        //插入X
void HeapPop(HP*hp);                      //删除
void HeapPrint(HP*hp);                    //打印
bool HeapEmpty(HP*hp);                    //检测是否为空
int HeapSize(HP*hp);                      //看有多少个

堆和顺序表是很像的,但是要注意他们的逻辑结构是不一样的,要表达的东西也不同

另外补充一句:assert断言是用来检测不该发生的情况,也就是传入数据可能失败等等。

2.堆的初始化与其销毁

//初始化
void HeapInit(HP*hp){                        
    assert(hp);
    hp->a=NULL;
    hp->size=hp->capacity=0;
}
//销毁
void HeapDestroy(HP*hp){
    assert(hp);
    free(hp->a);
    hp->capacity=hp->size=0;
}

3.向上调整及插入X元素 (此时默认堆是大堆

void AdjustUp(int *a,int child){            //向上调整下面还是详解,注意的是他这个实际本质还是拿数组存
    assert(a);
    int parent=(child-1)/2;
    while(child>0){
        if(a[child]>a[parent]){
            Swap(&a[child],&a[parent]);
            child=parent;
            parent=(child-1)/2;
        }
        else break;
    }
}
void HeapPush(HP*hp,HPDataType x){             //HeapPush要求,插入一个X保证原有的堆,原来大堆插入后还得是大堆
    assert(hp);
    if(hp->size==hp->capacity){
        size_t newCapacity=hp->capacity==0?4:hp->capacity*2;  //由于开始时capacity有可能是0
        HPDataType*tmp=realloc(hp->a,sizeof(HPDataType)*newCapacity);//后面放realloc用法的细节
        if(tmp==NULL){
            printf("realloc fail\n");
            exit(-1);
        }
        hp->a=tmp;
        hp->capacity=newCapacity;
    }
    hp->a[hp->size]=x;
    hp->size++;
    AdjustUp(hp->a,hp->size-1);
}

在插入的时候,不能破坏他的堆结构,如原来是大堆也就是要求,插入末尾元素之后,要与其调整,插入的时候只影响画圈的那一列,所以需要判断插入的X与56,70相比,让他依然保持父亲大,儿子小的结构

向上调整

这里要了解一个知识  parent=(child-1)/2。  可以带入一下试试,不管左右节点都行,毕竟下标是整数

看尾元素和他的父节点比较,然后是交换值与下标

4.返回堆元素的个数

int HeapSize(HP*hp){
    assert(hp);
    return hp->size;
}

5.判断是不是空堆

bool HeapEmpty(HP*hp){
    assert(hp);
    return hp->size==0;
}

6.移除堆顶元素,以及向下调整(默认是小堆的情况,大堆就改变找大的)

void AdjustDown(int *a,int n,int parent){
    int child=parent*2+1;
    while(child<n){         //左孩子是否到了叶节点也就是底
        //选择左右孩子哪个才是最小的
        if(child+1<n&&a[child+1]<a[child]){           //child+1是右孩子,右孩子可能不存在,所以也要判断一下。
            ++child;
        }
  //如果最小的孩子小于父亲,交换,并且接着向下面调整,否则推出
        if(a[child]<a[parent]){
            Swap(&a[child],&a[parent]);            //换值
            parent=child;                          //换下标
            child=parent*2+1;
        }
        else{
            break;
        }
    }
}
//删除堆顶数据(删除树的根,也就是找最值)
void HeapPop(HP*hp){
    assert(hp); 
    assert(!HeapEmpty(hp));                        //看hp有没有值是不是空
    Swap(&hp->a[0],&hp->a[hp->size-1]);            //堆顶和最后的交换位置
    hp->size--;                                    //删除堆顶
    AdjustDown(hp->a,hp->size,0);
}

如果是大堆就是要找两边最大的

一些杂碎的知识

1.realloc函数是将数组扩容的一个函数

看是否申请成功 要是成功则realloc函数会调用,否则realloc会调用malloc函数申请开辟下一个数组空间,要是开辟新的数组空间成功,将原数组中的数据拷贝在新的数组中,释放掉原数组,并返回一个数组首地址,需要用一个指针来接。

2.堆的逻辑结构是完全二叉树,因此用数组基本不会空间浪费。

注:数据结构的栈和堆与操作系统的不同

 


相关文章
|
7月前
|
存储 算法
【堆】数据结构堆的实现(万字详解)
【堆】数据结构堆的实现(万字详解)
251 0
|
算法 C语言
【数据结构】堆的创建
文章目录 一、基于大堆的上下调整 1.向上调整 (1)解决措施: (2)代码实现 (3)测试 2.向下调整 (1)解决措施: (2)代码实现
|
6月前
|
存储
数据结构学习记录——堆的插入(堆的结构类型定义、最大堆的创建、堆的插入:堆的插入的三种情况、哨兵元素)
数据结构学习记录——堆的插入(堆的结构类型定义、最大堆的创建、堆的插入:堆的插入的三种情况、哨兵元素)
45 2
|
6月前
|
存储
数据结构学习记录——什么是堆(优先队列、堆的概念、最大堆最小堆、优先队列的完全二叉树表示、堆的特性、堆的抽象数据类型描述)
数据结构学习记录——什么是堆(优先队列、堆的概念、最大堆最小堆、优先队列的完全二叉树表示、堆的特性、堆的抽象数据类型描述)
165 2
【数据结构】 优先级队列(堆)与堆的建立
【数据结构】 优先级队列(堆)与堆的建立
栈的基本操作
栈的基本操作
202 0
【数据结构——堆】堆的基本功能和堆排序
一、堆的定义 堆的本质是一个数组,但是这个数组被看作成一棵完全二叉树。 堆分为两种,大根堆和小根堆 1.大根堆 大根堆是每一个节点的值都大于它左右孩子节点的值。 如下图所示,这就是一个大根堆:每个父亲都大于它的孩子。
了解数据结构的栈和线性表基本操作的对比
栈(stack):是只允许在一端进行插入或者删除操作的线性表
121 0
|
存储 C语言
【数据结构】什么是堆,如何使用无序数组生成一个堆?
一、堆的概念及其介绍 堆(Heap)是计算机科学中一类特殊的数据结构的统称,堆通常是一个可以被看做一棵完全二叉树的数组对象。如果有一个关键码的集合K = { , , ,…, },把它的所有元素按完全二叉树的顺序存储方式存储 在一个一维数组中,并满足: <= 且 <= ( >= 且 >= ) i = 0,1, 2…,则称为小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。