算法记录:堆排序
2008-02-20 01:41
176 查看
这次给出堆排序,这东西也比较干净,就是把数组当成一颗二叉树来处理,现在假设数组索引是从1开始的(注意,违反C的惯例),那么其子节点就是1*2和1*2 + 1,某个节点的父节点就是node_idx/2; 索引1所在的节点未根节点.
/*注意,我这个函数是向下修正函数,为了make heap方便,我用的是当索引起始为1来编写的,不要有任何疑虑,下面你
就可以看到为什么是可行的. 这个函数的功能是向下修正某个节点的正确性,保证其子节点小于它*/
static void rx_fix_down(void *arr, size_t count, size_t idx, size_t element_size, rx_cmp_func cmp_f, rx_swap_func swap_f)
{
RX_ASSERT(arr != NULL && count > 0 && idx > 0 && idx <= count && element_size > 0 && cmp_f != NULL && swap_f != NULL );
while(2 * idx <= count) //向下修正,当idx * 2 > count时候,证明其没有子节点了
{
size_t i = 2 *idx; //这里的i现在是其左节点
if(i < count && (cmp_f(RX_GET_ELEM(arr, element_size, i), RX_GET_ELEM(arr, element_size, i + 1)) < 0)) i++;//如果其存在右节点切右节点大于左节点,则i++;
if(cmp_f(RX_GET_ELEM(arr, element_size, idx), RX_GET_ELEM(arr, element_size, i)) >= 0) break;//如果当前节点大于子节点,则退出循环,否则交换.
swap_f(RX_GET_ELEM(arr, element_size, idx), RX_GET_ELEM(arr, element_size, i));
idx = i;
}
}
/*
这个是排序函数
*/
void rx_heap_sort(void *arr, size_t count, size_t element_size, rx_cmp_func cmp_f, rx_swap_func swap_f)
{
RX_ASSERT(arr != NULL && count > 0 && element_size > 0 && cmp_f != NULL && swap_f != NULL );
{
void *arr_tmp = ((rx_byte*)arr) - element_size;//严重注意,这里为了适应fix_down,已经将此数组调整成1为起始点的数组了
size_t k = count/2;
for(; k >= 1; k--) rx_fix_down(arr_tmp, count, k,element_size, cmp_f, swap_f);//建堆,因为count/2开始的都是父节点,到最后会保证此堆是正确的最大堆
while(count > 1)
{
swap_f(RX_GET_ELEM(arr_tmp, element_size, 1), RX_GET_ELEM(arr_tmp, element_size, count)); //把最大值和数组末尾交换
rx_fix_down(arr_tmp, --count, 1, element_size, cmp_f, swap_f); //重新修正堆,注意,这里末尾已经是确定的了,因此最终得到的数组也是有序的.
}
}
}
堆排序的最坏的时间复杂度是N + 2N*LogN ,一次建堆,一次拆堆.
/*注意,我这个函数是向下修正函数,为了make heap方便,我用的是当索引起始为1来编写的,不要有任何疑虑,下面你
就可以看到为什么是可行的. 这个函数的功能是向下修正某个节点的正确性,保证其子节点小于它*/
static void rx_fix_down(void *arr, size_t count, size_t idx, size_t element_size, rx_cmp_func cmp_f, rx_swap_func swap_f)
{
RX_ASSERT(arr != NULL && count > 0 && idx > 0 && idx <= count && element_size > 0 && cmp_f != NULL && swap_f != NULL );
while(2 * idx <= count) //向下修正,当idx * 2 > count时候,证明其没有子节点了
{
size_t i = 2 *idx; //这里的i现在是其左节点
if(i < count && (cmp_f(RX_GET_ELEM(arr, element_size, i), RX_GET_ELEM(arr, element_size, i + 1)) < 0)) i++;//如果其存在右节点切右节点大于左节点,则i++;
if(cmp_f(RX_GET_ELEM(arr, element_size, idx), RX_GET_ELEM(arr, element_size, i)) >= 0) break;//如果当前节点大于子节点,则退出循环,否则交换.
swap_f(RX_GET_ELEM(arr, element_size, idx), RX_GET_ELEM(arr, element_size, i));
idx = i;
}
}
/*
这个是排序函数
*/
void rx_heap_sort(void *arr, size_t count, size_t element_size, rx_cmp_func cmp_f, rx_swap_func swap_f)
{
RX_ASSERT(arr != NULL && count > 0 && element_size > 0 && cmp_f != NULL && swap_f != NULL );
{
void *arr_tmp = ((rx_byte*)arr) - element_size;//严重注意,这里为了适应fix_down,已经将此数组调整成1为起始点的数组了
size_t k = count/2;
for(; k >= 1; k--) rx_fix_down(arr_tmp, count, k,element_size, cmp_f, swap_f);//建堆,因为count/2开始的都是父节点,到最后会保证此堆是正确的最大堆
while(count > 1)
{
swap_f(RX_GET_ELEM(arr_tmp, element_size, 1), RX_GET_ELEM(arr_tmp, element_size, count)); //把最大值和数组末尾交换
rx_fix_down(arr_tmp, --count, 1, element_size, cmp_f, swap_f); //重新修正堆,注意,这里末尾已经是确定的了,因此最终得到的数组也是有序的.
}
}
}
堆排序的最坏的时间复杂度是N + 2N*LogN ,一次建堆,一次拆堆.
相关文章推荐
- 算法学习记录-排序——堆排序
- 堆排序(最大堆进阶)--【算法导论】
- 赵志勇记录下的算法+程序
- 3.11 第一次做伪代码的记录(最基础的算法)
- 算法之堆排序
- 白话经典算法系列之七 堆与堆排序
- 白话经典算法系列之七 堆与堆排序
- 算法の堆排序
- 【算法分析】排序算法:希尔、归并、快速、堆排序
- 【算法导论 第6章 堆排序】
- 算法-排序-选择排序(直接选择和堆排序)
- 【数据结构&&算法】堆排序
- C语言对堆排序一个算法思路和实现代码
- jvm学习记录--04 垃圾回收概念与垃圾回收算法
- 堆排序详细分析(算法导论第六章)
- 最小生成树之算法记录【prime算法+Kruskal算法】【模板】
- 算法入门--堆排序2(建立最小堆,从大到小)
- 算法学习记录-查找——平衡二叉树(AVL)
- 算法的威力:法国人用单台台式机打破由超级计算机创造的圆周率运算世界记录
- 算法-->堆排序