✨链接1:【数据结构】顺序表
✨链接2:【数据结构】单链表
✨链接3:【数据结构】双向带头循环链表
✨链接4:【数据结构】栈和队列
百度百科的解释:树是一种非线性的数据结构,它是由n(n≥0)个有限节点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。
注意:
树型结构中,子树之间不能有交集,否则就不是树型结构。
以上树的概念都适用于二叉树,但是二叉树在树的基础上添加了一些条件。
百度百科的解释:堆(Heap)是计算机科学中一类特殊的数据结构,是最高效的优先级队列。堆通常是一个可以被看作一棵完全二叉树的数组对象。
小根堆: 每一个父节点的值总是小于等于子节点。
大根堆: 每一个父节点的值总是大于等于子节点。
注:
堆在物理存储结构上数组的形式,在逻辑结构上是二叉树。
AdjustUp
实现思路: 向上调整算法通常在堆 push
的时候使用向上调整算法来继续维护当前是一个堆的结构。当堆添加数据的时候,如果是小根堆要满足父节点的数据要小于等于子节点的数据,大根堆同理。其实堆在 push
数据的时候,不会影响到兄弟节点,只会影响到其父节点,所以通过二叉树的性质来计算出父节点在与当前子节点比较,若子节点小于父节点则交换。
AdjustUp
实现(小根堆为例):
// 向上调整
void AdjustUp(HeapDataType* data, int child) {
assert(data);
// 计算父节点位置
int parentNode = (child - 1) / 2;
while (child > 0) {
if (data[child] < data[parentNode]) {
// 交换
Swap(&data[child] , &data[parentNode]);
// 继续向上搜索
child = parentNode;
parentNode = (child - 1) / 2;
}
else {
break;
}
}
}
AdjustDown
实现思路:向下调整算法通常在 pop
堆顶数据后来继续维护当前是一个堆的结构,这里采用了一个很巧妙的方法把堆顶元素与最后一个下标元素进行交换,而堆在物理上又是一个顺序表只需要 --size
即可删除最后一个元素,在通过向下调整算法也就是将下标为 0
的元素 ( parent节点
) 和左右孩子中较小的那个进行比较,若较小的孩子要小于当前的 parent
节点,则交换。
AdjustUp
实现(小根堆为例):
void AdjustDown(HeapDataType* data, int size, int parent) {
assert(data);
// 默认左孩子最小
int child = parent * 2 + 1;
while (child < size) {
// 判断左孩子和右孩子谁更小
// 若右孩子小则改变child 右孩子不能越界
if ( (child + 1 < size) && (data[child + 1] < data[child]) ) {
child++;
}
// 最小的孩子是否比父节点小
if (data[child] < data[parent]) {
// 交换
Swap(&data[child] , &data[parent]);
// 迭代
parent = child;
child = parent * 2 + 1;
}
else {
// 父节点 <= 最小的孩子节点
break;
}
}
}
堆的结构定义与接口
#pragma once
#include
#include
#include
#include
typedef int HeapDataType;
// 逻辑结构 完全二叉树
// 内存结构 顺序表
typedef struct Heap {
HeapDataType* data;
int size;
int capacity;
}Heap;
void AdjustDown(HeapDataType* data, int size, int parent);
void AdjustUp(HeapDataType* data, int child);
void HeapPrint(Heap* hp);
void Swap(HeapDataType* value1 , HeapDataType* value2);
void HeapInit(Heap * hp);
void HeapDestroy(Heap * hp);
void HeapPush(Heap * hp , HeapDataType value);
void HeapPop(Heap * hp);
HeapDataType HeapTop(Heap * hp);
bool HeapIsEmpty(Heap* hp);
int HeapSize(Heap * hp);
HeapInit
实现:
void HeapInit(Heap* hp) {
assert(hp);
hp->data = NULL;
hp->size = 0;
hp->capacity = 0;
}
HeapDestroy
实现:
void HeapDestroy(Heap* hp) {
assert(hp);
free(hp->data);
hp->capacity = hp->size = 0;
}
HeapPrint
实现:
void HeapPrint(Heap* hp) {
assert(hp);
for (int i = 0; i < hp->size; i++) {
printf("%d " , hp->data[i]);
}
printf("\n");
}
HeapPush
实现:
void HeapPush(Heap* hp, HeapDataType value) {
assert(hp);
// 检查容量
if (hp->size == hp->capacity) {
int newCapacity = hp->capacity == 0 ? 4 : hp->capacity * 2;
HeapDataType* newData = (HeapDataType*)realloc(hp->data , sizeof(HeapDataType) * newCapacity);
assert(newData);
hp->data = newData;
hp->capacity = newCapacity;
}
hp->data[hp->size] = value;
hp->size++;
// 向上调整
AdjustUp(hp->data , hp->size - 1);
}
HeapPop
实现:
// 删除堆顶的数据 堆顶选数小堆最小数
void HeapPop(Heap* hp) {
assert(hp);
// 堆不为空
assert(!HeapIsEmpty(hp));
// 交换
Swap(&hp->data[0] , &hp->data[hp->size - 1]);
hp->size--;
// 向下调整
AdjustDown(hp->data , hp->size , 0);
}
HeapTop
实现:
HeapDataType HeapTop(Heap* hp) {
assert(hp);
// 堆不为空
assert(!HeapIsEmpty(hp));
return hp->data[0];
}
HeapIsEmpty
实现:
bool HeapIsEmpty(Heap* hp) {
assert(hp);
return hp->size == 0;
}
HeapSize
实现:
int HeapSize(Heap* hp) {
assert(hp);
return hp->size;
}
Swap
实现:
void Swap(HeapDataType* value1, HeapDataType* value2) {
assert(value1 && value2);
HeapDataType temp = *value1;
*value1 = *value2;
*value2 = temp;
}
注:
小根堆还是大根堆是由 AdjustUp
和 AdjustDown
来控制的。