• 二叉树——堆(C语言实现)


    小堆的结构与初始化

    小堆的结构是子节点不小于父节点,兄弟结点没有顺序,并且总是完全二叉树。
    逻辑结构是这样的:
    在这里插入图片描述
    物理储存我们用顺序表来储存:
    首先从结点的祖先10开始,放进顺序表中,然后是他的子节点15和20,再往下访问也是访问15和20的子节点,分别是30,20,25,90,按照这个规律放进顺序表中就可以了。

    [10,15,20,30,20,25,90,40,30,70];

    首先创建一个顺序表的结构体

    typedef int SD;//方便以后更改数组的数据类型
    typedef struct pile
    {
    	SD* a;//数组
    	int size;//数组有效值的长度
    	int capacity;//数组容量大小
    }pile;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    初始化

    void initialize(pile* hp)//初始化
    {
    	hp->a = NULL;
    	hp->capacity = hp->size = 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    堆的销毁,空判定,打印

    销毁

    void HeapDestory(pile* hp)//销毁
    {
    	free(hp->a);
    	hp->a = NULL;
    	hp->capacity = hp->size = 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    判断是否为空
    空返回0,非空返回非0.

    int HeapEmpty(pile* hp)//判断空
    {
    	return hp->size;
    }
    
    • 1
    • 2
    • 3
    • 4

    打印
    这里只打印整理后的数组:

    void Pintf(pile* hp)//打印
    {
    	assert(hp);
    	int i = 0;
    	for (i = 0; i < hp->size; i++)
    	{
    		printf("%d ", hp->a[i]);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    插入,删除

    插入
    物理结构是在顺序表中末尾插入一个数据。
    比如说我们插入一个5.
    在这里插入图片描述
    但是如果插入之后就不是小堆的结构了,祖先不小于等于新增元素,所以我们需要将5向上调整。(红线是调整顺序)
    在这里插入图片描述
    调成之后是这样的:
    在这里插入图片描述

    void swap(SD* p1,SD* p2)//交换数据
    {
    	SD p = *p1;
    	*p1 = *p2;
    	*p2 = p;
    }
    void HeapPush(pile* hp, SD x)//插入
    {
    	assert(hp);
    	if (hp->capacity == hp->size)
    	{
    		int sum = hp->capacity == 0 ? 4 : hp->capacity * 2;
    		SD* p = (SD* )realloc(hp->a, sum * sizeof(SD));
    		if (p == NULL)
    		{
    			perror("realloc fail");
    			exit(-1);
    		}
    		hp->a = p;
    		hp->capacity = sum;
    	}
    	hp->a[hp->size] = x;//插入数据
    	hp->size++;//记录数组的有效长度
    	int child = hp->size - 1;//新插入的元素,元素的下标
    	int parent = (child - 1) / 2;//新插入的元素的父节点,父节点的下标
    	while (child > 0)//孩子的下标如果等于0就说明到堆顶了
    	{
    		if (hp->a[child] < hp->a[parent])//如果孩子比父节点小就交换
    		{
    			swap(&(hp->a[child]), &(hp->a[parent]));//交换
    			child = parent;
    			parent = (child - 1) / 2;
    		}
    		else
    		{
    			break;//如果不成立就说明已经是小堆了
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    删除
    删除第一个元素。
    在这里插入图片描述
    因为要保持原来小堆的形态,所以要让10到删除的那个位置,20不行,然后是15补刀10的位置,以此类推。(向下调整算法)
    在这里插入图片描述
    最后变成了这样:
    在这里插入图片描述
    代码是这个操作我们需要将头和尾先交换一下,然后删除尾再向下调整。

    void HeapPop(pile* hp)//删除
    {
    	assert(hp);
    	assert(HeapEmpty(hp));//判断是否为空
    	swap(&hp->a[hp->size - 1], &hp->a[0]);//交换首尾的位置
    	hp->size-- ;//删掉末尾的数
    	int parent = 0;//父结点下标
    	int minchild = 2 * parent + 1;//表示最小的孩子,第一次先假设左孩子最小
    	while (minchild < hp->size)//防止数组越界
    	{
    		if (minchild+1 < hp->size && hp->a[minchild + 1] < hp->a[minchild])//防止右孩子出界
    		{
    			minchild = minchild++;//如果右孩子比左孩子小就让右孩子等于最小
    		}
    		if (hp->a[minchild] < hp->a[parent])//判断是否需要向下调整
    		{
    			swap(&hp->a[minchild], &hp->a[parent]);
    			parent = minchild;
    			minchild = 2 * parent + 1;
    		}
    		else
    		{
    			break;
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
  • 相关阅读:
    《C++ primer plus》:第五章 循环和关系表达式
    #1全职独立开发两周总结
    【Python基础教程】类的定义和使用
    基于C++ Qt的积分抽奖系统源码,实现了用户注册、商品购买、积分抽奖等功能
    2022年10月31日-11月6日(ue5 pak收尾)
    freemarker+yml介绍 以及freemarker与JSP的区别
    进程和线程(要关注哦)
    MATLAB | 那些你不得不知道的MATLAB小技巧(三)
    企业如何建立全链路数字化体系,才能让卖货更容易?
    HTML5编写旅游网页
  • 原文地址:https://blog.csdn.net/qq_63580639/article/details/126740189