波奇学数据结构:树和堆

树:(如上图)

树的基本概念:

  1. 节点的度:一个节点连接子节点的个数。如A节点的度为3,B节点的度为2。

  1. 树的度:树的度为最大节点度,在树中A的节点最大为3,所以树的节点的为3。

  1. 根节点:无父母节点的节点,树的节点是A

  1. 叶节点:节点的度为0的节点,叶节点:E F G H I。

  1. 祖先节点:根节点

  1. 父母节点和子节点:A是B,C,D的父母节点,B,C,D是A的子节点。

  1. 兄弟节点,有同一个父节点。BCD互为兄弟节点。

  1. 树的高度或者深度:树的层数,上图树的高度为3,空树为0,只有根节点为1。

  1. 树的子节点只能用一个父节点,兄弟节点不相连。

  1. 二叉树:只有两个子节点的树。

完全二叉树:

二叉树的每一层从左到右都是满的,二叉树的图片就不是完全二叉树,下面这个才是。

满二叉树:

每一层都没有空节点。

树的存储方式可以用链表:

struct Tree
{
    int val;
    int*brother;
    int*child;
}

child指针连接第一个子节点,兄弟指针连接兄弟节点。

堆是完全二叉树

堆的实现可以用链表,但更简单的方式是用数组。

如图,利用下标间的关系,把树存在数组中

下标从零开始

(子节点下标-1)/2=父节点下标
父节点下标*2+1等于左子节点下标
父节点下标*2+2等于右子节点下标

节点数量和高度关系(等比数列求和)

节点数量范围[2^(h-1),2^h-1]

不同度的节点的关系

N0=N2+1
N1=1或0

分析:满二叉树由等比数列来看N0:2^k-1-(2^(k-1)-1)=2^(k-1)

N2=2^(k-1)-1是对的。

大小根堆:

大根堆,父节点大于或等于子节点

小根堆,父节点大于或等于子节点。

大根堆的实现:

#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
#include<stdio.h>
typedef int HeapDatatype;
typedef HeapDatatype HD;
typedef struct Heap
{
    HD* hp;
    int size;
    int capacity;
}Heap;
void HeapInit(Heap* php);
void HeapDestory(Heap* php);
void HeapPush(Heap* php,HD x);
void HeapPop(Heap* php);
int HeapTop(Heap* php);
Heap* HeapAddspace(Heap* php);
bool HeapEmpty(Heap* php);
bool HeapFull(Heap* php);
void HeapPrint(Heap* php);
#include"Heap.h"
void HeapInit(Heap* php)
{
    assert(php);
    php->hp = (HD*)malloc(sizeof(HD) * 4);
    if (!php->hp)
    {
        perror("malloc error");
        return ;
    }
    php->size = -1;
    php->capacity = 4;
}
void HeapDestory(Heap* php)
{
    assert(php);
    free(php->hp);
    free(php);
}
void swap(HD* p1, HD* p2)
{
    int cmp = *p1;
    *p1 = *p2;
    *p2 = cmp;
}
void adjustup(HD* arr, int child, HD x)
{
    int parent = (child - 1) / 2;
    while (arr[parent] < arr[child])
    {
        swap(&arr[parent], &arr[child]);
        child = parent;
        parent = (child - 1) / 2;
        if (arr[parent] == arr[child])
        {
            break;
        }
    }
}
void HeapPush(Heap* php,HD x)
{
    assert(php);
    if (HeapFull(php))
    {
        php=HeapAddspace(php);
    }
    php->hp[++php->size] = x;
    adjustup(php->hp,php->size,x);
    
}
void adjustdown(HD*arr,int size)
{
    int parent = 0;
    int child = parent * 2 + 1;
    while (child<=size)
    {
        if (child+1<=size&&arr[child] <arr[child + 1])
        {
            child++;
        }
        if (arr[parent] > arr[child])
        {
            break;
        }
        swap(&arr[parent], &arr[child]);
        parent = child;
        child = parent * 2 + 1;
        
    }
    
}
void HeapPop(Heap* php)
{
    assert(php);
    if (HeapEmpty(php))
    {
        return;
    }
    swap(&php->hp[0], &php->hp[php->size]);
    php->size--;
    adjustdown(php->hp,php->size);
}
int HeapTop(Heap* php)
{
    assert(php);
    assert(php->hp);
    return php->hp[0];
}
Heap* HeapAddspace(Heap* php)
{
    assert(php);
    HD* tmp = (HD*)realloc(php->hp, sizeof(HD) * (php->capacity) * 2);
    if (!tmp)
    {
        perror("realloc error");
        return NULL;
    }
    php->hp = tmp;
    php->capacity *= 2;
    return php;

}
bool HeapEmpty(Heap* php)
{
    assert(php);
    return php->size == -1;
}
bool HeapFull(Heap* php)
{
    assert(php);
    return php->size+1 == php->capacity;
}
void HeapPrint(Heap* php)
{
    int count = 0;
    while (count <=php->size)
    {
        printf("%d->", php->hp[count]);
        count++;
    }
    printf("\n");
}

关键在于adjustup()和adjustdown()这两个函数

adjustup()向上调整函数

在push时我们把x放在最新的位置,然后和父节点比较,大于就交换,小于就停止,最极限的情况是x成为新节点,此时child和parent会相同且等于0,跳出循环即可。

adjustdownn()向下调整函数,

在pop掉根节点时,我们把size位置的值x和根节点的值交换,并size--来控制有效数据数量,当x成为根节点时,让他向下移动,找到最大的孩子节点比较,大于x和x交换,小于就不变,循环停止条件是小于或者子节点大于size值。注意比较子节点时child+1不要越界。

仔细想想大小堆有什么用?

大堆可以不断pop出最大值,次大值,次次大值....

可以做到排序的作用而且效率非常高,n个数据找到最大值时间复杂度logN,n个数据排序nlogN.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值