1.堆是什么?
堆是一种特殊的完全二叉树.
其中, 堆又分为最大堆和最小堆.
最大堆: 任一父节点的值都比左右节点的值大.
最小堆: 任一父节点的值都比左右节点的值小.
2. 堆排序的过程:
A. 最小堆升序排序: (最大堆降序排序类似)
建立最小堆->保存根节点的值(或输出)
->把最后一个节点的值保存到根节点
->堆长减 1->调整为最小堆.以此循环.
更好的方法:
B. 最大堆升序排序:(最小堆降序排序类似)
建立最大堆->保存根节点的值->交换根节点和最后一个节点的值
-> 堆长度减1-> 调整.以此循环.
A:
void delete_root_and_sort(int *heap_array, int len)
{
int temp_len = len;
int temp = 0;
int i = 0;
for (i = 1; i < len + 1; i++)
{
temp = heap_array[1];
heap_array[1] = heap_array[temp_len];
temp_len--;
siftdown(heap_array, 1, temp_len);
printf("%d ", temp);
}
printf("\n");
}
B:
void max_delete_root_and_sort(int *heap_array, int len)
{
int temp_len = len;
int temp = 0;
int i = 0;
for (i = 1; i < len + 1; i++)
{
temp = heap_array[1];
heap_array[1] = heap_array[temp_len];
heap_array[temp_len] = temp;
temp_len--;
max_siftdown(heap_array, 1, temp_len);
}
for (i = 1; i < len + 1; i++)
{
printf("%d ", heap_array[i]);
}
printf("\n");
}
向下调整:
进行向下调整的时候, 先比较两次再进行一次交换比每进行一次比较交换一次好.
下面代码中的father = min; 这句十分关键.flag标志是为了看是否需要继续调整. 因为调整是从最后一个父节点开始, 是一个从下往上的过程(此处脑袋浮现完全二叉树) , 所以如果上层不需要调整, 下层也不再需要(因为已经调整过了).
代码如下:
static void siftdown(int *heap_array, int father, int len)
{
int left_child = 0;
int right_child = 0;
int min = 0;
int flag = 0; //是否需要继续往下的标识, 为1不需要.
while (father * 2 <= len && flag == 0)
{
left_child = father * 2;
right_child = father * 2 + 1;
if (left_child <= len) //存在左节点
{
if (heap_array[left_child] < heap_array[father])
{
// swap(heap_array, father, left_child);
min = left_child;
}
else
{
min = father;
}
}
if (right_child <= len)
{
if (heap_array[right_child] < heap_array[min])
{
// swap(heap_array, father, right_child);
min = right_child;
}
}
if (min != father)
{
swap(heap_array, father, min);
father = min; //这句很重要, 相当于递归调用siftdown.
}
else
{
//因为是从下往上操作, 所以当前如果不需要位置改变的话,
//也不需要往下测试, 因为, 下面是已经排序好的了.
flag = 1;
}
}
}
-
注意: 把堆数据放在数组的第[1]位开始会更方便.
源码:
https://github.com/isshe/DataStructure-Algorithm/tree/master/Heap
勿在浮沙筑高台.