欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 金融 > 二叉树中堆的实现

二叉树中堆的实现

2025/3/18 20:35:21 来源:https://blog.csdn.net/2401_88043113/article/details/146165850  浏览:    关键词:二叉树中堆的实现

1 堆的声明和定义

typedef int HPDateType;
typedef struct Heap {HPDateType* arr;int size;int capcity;
}HP;

与顺序表相似,我们需要一个数组,有效空间大小,有效元素个数

2 堆的初始化

void HPInit(HP*php)
{assert(php);php->arr = NULL;php->size = php->capcity = 0;
}

把数组置空,有效元素个数和有效空间大小置为0

3 堆的销毁

void HPDestroy(HP* php)
{assert(php);if (php->arr)free(php->arr);php->arr = NULL;php->capcity = php->size = 0;
}

传递的参数当然不能为空,用assert断言,接着把arr的空间释放掉,让size,capcity为0

4 入堆

这里我们需要先讲解思路

首先,堆是用数组储存起来的,如果直接插到数组最后一位是不合理的 

如图所示,可能空间是满的,这里就需要们重新开辟空间

 同时,为了保证堆为一个有效堆(保证为大堆或者小堆),我们需要重新调整堆的排序

空间开辟

if (php->size == php->capcity)
{int newcapcity = php->capcity == 0 ? 4 : 2 * php->capcity;HPDateType* tmp = (HPDateType*)realloc(php->arr, newcapcity * sizeof(HPDateType));if (tmp == NULL){perror("realloc fail");exit(1);}php->capcity = newcapcity;php->arr = tmp;
}

利用realloc开辟,最后给capcity和arr赋值

堆调整--向上调整--小堆

void AdjustUp(HPDateType* arr, int child)//向上调整
{while (child > 0){int parent = (child - 1) / 2;// <: 小堆// >: 大堆if (arr[child] < arr[parent]){swap(&arr[child], &arr[parent]);//swap函数的形参是两个指针,需要传地址child = parent;parent = (child - 1) / 2;}else {break;}}
}

调整原理:将该入堆元素(child)插到末尾,顺着其父母结点(parent)往上调整,在堆为小堆的条件下,如果该元素比他的父母结点小就交换二者,再让其父母结点成为新的孩子结点,循环往复,直到新的孩子结点跳出,或者直白点说就是下标<0就跳出循环

注意,因为当child走到根结点时也需要比较之后判断是否要交换,所以不能只是parent走到空,必须要child走到空

完整入堆操作的实现

void HPPush(HP* php, HPDateType x)
{assert(php);//判断空间是否足够	if (php->size == php->capcity){int newcapcity = php->capcity == 0 ? 4 : 2 * php->capcity;HPDateType* tmp = (HPDateType*)realloc(php->arr, newcapcity * sizeof(HPDateType));if (tmp == NULL){perror("realloc fail");exit(1);}php->capcity = newcapcity;php->arr = tmp;}php->arr[php->size] = x;AdjustUp(php->arr, php->size);//向上调整++php->size;
}

如果是大堆的调整就把向上调整的" < "改为" > " 

最后还需要让最大元素个数+1

5 出堆

思路讲解这里出堆出的通常是堆顶元素,如果要出堆尾元素只需要让size--即可,意义不大,如果是出堆顶元素,那么这里我们一定不能用顺序表的向前覆盖来写,这样会让整个堆的结构混乱,我们不妨另辟蹊径,继续沿用交换操作,让根结点和最后一个结点交换,再出堆尾让size--,这时候我们关注交换到堆顶的元素,利用向下调整算法,让其成为有效堆

堆调整--向下调整--大堆

void AdjustDown(HPDateType*arr,int parent,int n)
{int child = parent * 2 + 1;while (child<n){// 大堆:<// 小堆:>if (child+1<n&&arr[child] < arr[child + 1]){child++;}if (arr[child] > arr[parent]){swap(&arr[child], &arr[parent]);parent = child;child=parent * 2 + 1;}else {break;}}}

调整原理从堆顶开始,此时的堆顶设为初始parent,我们取child结点中较大的一个作为比较对象,如过child>parent就交换,再让child成为新的parent,直到调整完成跳出循环,或者child走到最后一个结点

这里我们还需要注意child+1在调整的时候是否越界,以防出现非法访问

 完整出堆操作的实现

void HPPop(HP* php) 
{assert(!HPEmpty(php));swap(&php->arr[0], &php->arr[php->size - 1]);--php->size;AdjustDown(php->arr, 0, php->size);
}

其中判空函数

bool HPEmpty(HP* php)
{assert(php);return php->size == 0;
}

6 借助数据结构堆来实现的堆排序

先来写取堆顶元素的实现

HPDateType HPTop(HP* php)
{assert(!HPEmpty(php));return php->arr[0];
}
void HeapSort01(int* arr, int n)
{HP hp;HPInit(&hp);for (int i = 0; i < n; i++){HPPush(&hp,arr[i]);}int i = 0;while (!HPEmpty(&hp)){int top = HPTop(&hp);arr[i++] = top;HPPop(&hp);//删除之后会重新排列}HPDestroy(&hp);
}

这种堆排序借助了入堆和出堆时的堆调整,因为每次出堆我们都获取了堆中最小或者最大的元素,所以最终得到了一个有序序列

7 常规堆排序

思路讲解:首先利用向下堆调整让待排序的数组建堆,接着将堆顶元素和最后一个元素交换,接着再进行堆调整直到end<0,实质上还是堆顶元素一定为最大(小)的出堆操作的运用

有如下示例帮助理解

这里我们实现了把最大元素一个个放到末尾 ,最终实现堆排序

void HeapSort(int* arr,int n)
{//向下调整建堆for (int i = (n - 2) / 2; i>=0;i--){AdjustDown(arr, i, n);//i是最后一个节点的parent节点}int end = n - 1;while (end>0){swap(&arr[0], &arr[end]);AdjustDown(arr, 0, end);end--;}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词