您的位置:首页 > 其它

算法记录:堆排序

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 ,一次建堆,一次拆堆.

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: