1.树
1.1 树的结构与概念
树是一种非线性结构的,他是由n(n>0)个结点组成一个具有层次关系的集合。把他叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,⽽叶朝下的。如图
树形结构中,字树不能由交集,否则就不是树形结构
如图下
1:子树是不相交的
2:除了根结点,每个结点都有一个父结点
3:一个N结点的树有N-1个边
1.2树相关术语
父节点/双亲结点:若一个结点有子结点,这个节点就称为其子结点的父结点如图A就是B结点的父节点
子结点/孩子结点:一个结点含有的子树根结点称为子结点:如图B就是A的子节点
结点的度:一个结点有几个子结点就度就为多少 如图A 的度为6 E的度为2 K德度为0;
树的度:一棵树中,最大结点的度称为树的度如图树结点就为6
typedef int HeDataType;
typedef struct Heap {
HeDataType* arr;
int size;
int capacity;
}Hp;
这个定义其实是和顺序表一样的因为我们要用顺序表来实现二叉树
//初始化
void initia(Hp* ps)
{
assert(ps);
ps->arr = NULL;
ps->size = ps->capacity = 0;
}
和顺序表初始化时一样的首先我们要将这个数组指向空然后让里面的有效数据和大小都为0;
//销毁
void hpdestory(Hp* ps)
{
if (ps->arr)
free(ps->arr);
ps->arr = NULL;
ps->capacity = ps->size = 0;
}
这个也跟顺序表一样的不懂得可以去看一下我前面的顺序表首先如果数组不为空就直接free然后记住要让他指向空然后容量和大小都变成0
//堆插入
//堆插入
void inserthp(Hp* ps,HeDataType x)
{
assert(ps);
if (ps->capacity == ps->size)
{
HeDataType newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
HeDataType* tmp = (HeDataType*)realloc(ps->arr, sizeof(HeDataType)* newcapacity);
if (tmp == NULL)
{
perror("realloc fail");
exit(1);
}
ps->arr = tmp;
ps->capacity = newcapacity;
}
ps->arr[ps->size] = x;
Adjustup(ps->arr,ps->size);
ps->size++;
}
先插入之前我们还是老样子判断是否为空如果为空的情况下我们就要申请空间根顺序表的申请空间操作时一样的然后我们要分析一下二叉树我们是要建一个大堆还是小堆,如果建一个大堆我们的根节点是最值而且每个根节点的值要大于子结点,建小堆则相反所以我们要另外写一个函数来实现如下向上调整
//调整
//调整
void Adjustup(HeDataType* arr, int child)
{
int parent = (child - 1) / 2;
while (child > 0)
{
if (arr[child] > arr[parent])
{
Swap(&arr[child], &arr[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
第一个结点的时候就是根节点,后面陆续插入的时候如果我们要建大堆就需要判断根结点和子结点谁比较大大的放到前面所以我们要写一个交换的函数Swap这个函数就相当简单在这就不写了,然后让父结点走到子结点的位置,根据二叉树的性质可得知当子节点等于i的时候那么他的父节点就是(i-1)/2,反之我们知道父节点就可以求出子节点子节点就是2i+1,让父节点大于子节点那就没有必要交换所以直接break;
//堆删除
void pophp(Hp* ps)
{
assert(!emptyh(ps));
Swap(&ps->arr[0], &ps->arr[ps->size-1]);
ps->size--;
Adjustdown(ps->arr, 0, ps->size);
}
我们删除要删除数据如果直接删除第一个数据再去调整的话这样的代价是很大的,所以我们可以首先可以让第一个数据和最后一个交换然后直接让收效数据减减这样就可以删除数据然后再去因为根的数变了所以我们需要向下调整所以就要另外写一个函数向下调整如下
//向下调整
void Adjustdown(HeDataType *a,int parent,int x)
{
int child = parent * 2 + 1;
while (child a[parent])
{
Swap(&a[child], &a[parent]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
因为我们要从头开始向下调整我们拿到的是头结点的位置我们要首先判断左右结点那个比较大然后再去根头结点比较如果子节点大于父结点就叫交换然后让父节点走到子结点的位置然后子结点进行向下走。
//判断是否为空
//判断是否为空
bool emptyh(Hp* ps)
{
assert(ps);
return ps->size == 0;
}
判断是否为空就只需要判断里面的有效数据。
//取堆顶
HeDataType hptop(Hp* ps)
{
assert(!emptyh(ps));
return ps->arr[0];
}
取堆顶就只需要取到数组第一个数
下面是总体代码分为三个部分
Heap.h
#pragma once
#include
#include
#include
#include
typedef int HeDataType;
typedef struct Heap {
HeDataType* arr;
int size;
int capacity;
}Hp;
void initia(Hp* ps);
void hpdestory(Hp* ps);
//堆插入
void inserthp(Hp* ps,HeDataType x);
//堆删除
void pophp(Hp* ps);
//判断是否为空
bool emptyh(Hp* ps);
//取堆顶
HeDataType hptop(Hp* ps);
Heap.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"Heap.h"
//初始化
void initia(Hp* ps)
{
assert(ps);
ps->arr = NULL;
ps->size = ps->capacity = 0;
}
//销毁
void hpdestory(Hp* ps)
{
if (ps->arr)
free(ps->arr);
ps->arr = NULL;
ps->capacity = ps->size = 0;
}
//判断是否为空
bool emptyh(Hp* ps)
{
assert(ps);
return ps->size == 0;
}
//交换
void Swap(int *x,int *y)
{
int n = *x;
*x = *y;
*y = n;
}
//调整
void Adjustup(HeDataType* arr, int child)
{
int parent = (child - 1) / 2;
while (child > 0)
{
if (arr[child] > arr[parent])
{
Swap(&arr[child], &arr[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
//堆插入
void inserthp(Hp* ps,HeDataType x)
{
assert(ps);
if (ps->capacity == ps->size)
{
HeDataType newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
HeDataType* tmp = (HeDataType*)realloc(ps->arr, sizeof(HeDataType)* newcapacity);
if (tmp == NULL)
{
perror("realloc fail");
exit(1);
}
ps->arr = tmp;
ps->capacity = newcapacity;
}
ps->arr[ps->size] = x;
Adjustup(ps->arr,ps->size);
ps->size++;
}
void Adjustdown(HeDataType *a,int parent,int x)
{
int child = parent * 2 + 1;
while (child a[parent])
{
Swap(&a[child], &a[parent]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
//堆删除
void pophp(Hp* ps)
{
assert(!emptyh(ps));
Swap(&ps->arr[0], &ps->arr[ps->size-1]);
ps->size--;
Adjustdown(ps->arr, 0, ps->size);
}
//取堆顶
HeDataType hptop(Hp* ps)
{
assert(!emptyh(ps));
return ps->arr[0];
}
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"Heap.h"
void test()
{
Hp hp;
initia(&hp);
inserthp(&hp, 4);
inserthp(&hp, 3);
inserthp(&hp, 6);
inserthp(&hp, 8);
pophp(&hp);
pophp(&hp);
pophp(&hp);
pophp(&hp);
while (!emptyh(&hp))
{
printf("%d ", hptop(&hp));
pophp(&hp);
}
hpdestory(&hp);
}
int main()
{
int arr[] = { 23,1,4,56,43,60 };
int sz = sizeof(arr) / sizeof(arr[0]);
test();
/*test1(arr,sz);*/
phsort(arr, sz);
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
}
如何用链表实现请关注下一期内容