赞
踩
一棵二叉树是结点的一个有限集合,该集合:
如果有一个关键码的集合K = { k0, k1, k2,…,kn-1 },把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中。并满足:Ki <= K2i+1 且 Ki <= K2i+2 ( Ki >= K2i+1 且 Ki >= K2i+2 ) i = 0,1,2…,则称为小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆
堆的性质
基本了解堆的概念后,我们来看看琢磨一下什么是大根堆和小根堆
void Adjust_UP(Hp* hp, int child)
int parent = (child - 1) / 2;
if (hp->a[child] > hp->a[parent])
swap(&hp->a[child], &hp->a[parent]); //交换孩子和父亲,逐渐变为大根堆
那么什么时候不用交换了呢?要么循环过程中,父节点不再比孩子节点小,要么孩子节点已经到达下标为0(也就是祖宗节点)也可以说是堆顶
//while (parent >= 0) 这样写不好,程序会非正常结束
while (child > 0)
{
if (hp->a[child] > hp->a[parent])
{
swap(&hp->a[child], &hp->a[parent]); //交换孩子和父亲,逐渐变为大根堆
//迭代 —— 交替更新孩子和父亲
child = parent;
parent = (child - 1) / 2;
}
else {
break; //若是比较无需交换,则退出循环
}
}
以下整体代码:
/*交换函数*/
void swap(HpDataType* x1, HpDataType* x2)
{
HpDataType t = *x1;
*x1 = *x2;
*x2 = t;
}
/*向上调整算法*/ void Adjust_UP(Hp* hp, int child) { int parent = (child - 1) / 2; //while (parent >= 0) 这样写不好,程序会非正常结束 while (child > 0) { if (hp->a[child] > hp->a[parent]) { swap(&hp->a[child], &hp->a[parent]); //交换孩子和父亲,逐渐变为大根堆 //迭代 —— 交替更新孩子和父亲 child = parent; parent = (child - 1) / 2; } else { break; //若是比较无需交换,则退出循环 } } }
对于向下调整算法,前提很重要就是保证他的左子树和右子树是大堆或者小堆,才能从堆顶进行向下调整。
此时就需要使用到这个【向下调整算法】,当然我这个是大堆的调整,小堆的话刚好相反。原理:找出当前结点的两个孩子结点中教大的那一个换上来,将这个【18】换下去,但是呢此时还不构成大堆,因此我们还需要再去进行一个调整,一样是上面的找法,然后直到这个【18】的孩子结点到达【n - 1】就不作交换了,因为【n - 1】就相当于是位于数组下标的最后一个值
void Adjust_Down(int* a, int n, int parent)
//判断是否存在右孩子,防止越界访问
if (child + 1 < n && a[child + 1] > a[child])
{
++child; //若右孩子来的大,则转化为右孩子
}
if (a[child] > a[parent])
{
swap(&a[child], &a[parent]);
parent = child;
child = parent * 2 + 1;
}
else {
break;
}
下面是全部代码
/*向下调整算法*/ void Adjust_Down(int* a, int n, int parent) { int child = parent * 2 + 1; //默认左孩子来得大 while (child < n) { //判断是否存在右孩子,防止越界访问 if (child + 1 < n && a[child + 1] > a[child]) { ++child; //若右孩子来的大,则转化为右孩子 } if (a[child] > a[parent]) { swap(&a[child], &a[parent]); parent = child; child = parent * 2 + 1; } else { break; }
typedef int HpDataType;
typedef struct Heap {
HpDataType* a;
int size;
int capacity;
}Hp;
/*初始化堆*/
void HeapInit(Hp* hp)
{
assert(hp);
hp->a = NULL;
hp->size = hp->capacity = 0;
}
/*销毁堆*/
void HeapDestroy(Hp* hp)
{
assert(hp);
if(hp->a)
{
free(hp->a);
hp->a = NULL;
hp->size = hp->capacity = 0;
}
}
/*堆的插入*/ void HeapPush(Hp* hp, HpDataType x) { assert(hp); //扩容逻辑 if (hp->size == hp->capacity) { int newCapacity = hp->capacity == 0 ? 4 : hp->capacity * 2; HpDataType* tmp = (HpDataType*)realloc(hp->a, newCapacity * sizeof(HpDataType)); if (tmp == NULL) { perror("fail realloc"); exit(-1); } hp->a = tmp; hp->capacity = newCapacity; } hp->a[hp->size] = x; hp->size++; Adjust_UP(hp, hp->size - 1); }
数据
/*堆的删除*/
void HeapPop(Hp* hp)
{
assert(hp);
assert(hp->size > 0);
//首先交换堆顶和树的最后一个结点 —— 易于删除数据,保护堆的结构不被破坏
swap(&hp->a[0], &hp->a[hp->size - 1]);
hp->size--; //去除最后一个数据
Adjust_Down(hp->a, hp->size, 0);
}
改写族谱,关系紊乱
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。