堆排序也能做到算法复杂度为O(nlgn),但是不占用空间
堆:有点像二叉树,它有left孩子和right孩子
对任意节点i,它的left的值的下标为2*i + 1,right下标为2*i + 2
比如0,它的left是1,right是2.
parent的下标值是i/2 - 1
最大堆特点:
parent总比child大。但是不是二叉树哦,因为left和right之间没有大小关系
最小堆特点:
parent总比child小
维护堆函数:对index进行最大堆维护,如果发现孩子更大,就交换,如果交换了,那么孩子也变了,也需要再交换
int left(int index)
{
return index * 2 + 1;
}
int right(int index )
{
return index * 2 + 2;
}
void MaxHeapify(int* ptr_data, int index, int len)
{
int left_index = left(index);
int right_index = right(index);
int large_index = index;
if (left_index < len && ptr_data[left_index] > ptr_data[large_index])
{
large_index = left_index;
}
if (right_index < len && ptr_data[right_index] > ptr_data[large_index])
{
large_index = right_index;
}
if (large_index != index)
{
int temp = ptr_data[index];
ptr_data[index] = ptr_data[large_index];
ptr_data[large_index] = temp;
MaxHeapify(ptr_data, large_index, len);
}
}
以上只是维护堆,但是并没有对整个数组进行建堆,建堆从最下面往上建立即可(上面依赖于下面的值,所以从下网上建堆)
最下面叶子节点不存在建堆概念。
void BuildMaxHeap(int* ptr_data, int len)
{
int i = len / 2;
for(; i >=0 ; --i)
{
MaxHeapify(ptr_data, i, len);
}
}
对建堆的数据进行排列就快很多了,因为最大堆的特点,0肯定是最大的,将0和最后一个i交换,然会对i进行堆维护(其它已经在第一次建堆好了,对i维护后可以保证也是最大堆)
void HeapSort(int* ptr_data, int len)
{
BuildMaxHeap(ptr_data,len);
printf("after build max heap:");
PrintfData(ptr_data, len);
int i = 0;
for (i = len-1; i > 0; i--)
{
int temp = ptr_data[i];
ptr_data[i] = ptr_data[0];
ptr_data[0] =temp;
MaxHeapify(ptr_data, 0, i);
}
}
接下来分析一下算法复杂度,看似堆排序的原理是找到最大值放着,再在里面找最大的,其实它比这种找法快很多
维护堆的算法复杂度最大是O(h),h是高度,因为它是按照高度维护下区的,也就是O(lgn),因为对于n的堆,高度是O(lgn),是1,2,4,8这样扩展下去的
建堆的算法复杂度是O(n/2 *lgn),因为需要调用n/2次维护堆函数,实际上建堆过程越到后面成本越低,实际上复杂度只有O(n)
很好看出HeapSort的时间复杂度也是O(nlgn)
堆还有很多其它特性可供使用,因为能够较快的建立堆,利用堆的特性可以做很多其它事情,而不是在一堆毫无序列的数据中操作
如果对毫无序列的数据先进行完整排序,时间复杂度又过大,这就体现了堆的优势。
为了方便显示树,下面增加了将数据打印成树的方法,加这个方法还费了蛮多时间的
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int g_x_max = 64;
int left(int index)
{
return index * 2 + 1;
}
int right(int index )
{
return index * 2 + 2;
}
int lgx(int x)
{
int i = 0;
int i2 = 1;
for (i = 0; i < x; ++i)
{
if (i2 == x)
{
return i;
}
else if (i2 > x)
{
return i - 1; // 往下取值
}
i2 = i2 * 2;
}
assert(0);
return i;
}
int square2(int x)
{
int i = 0;
int iret = 1;
for (i = 0; i < x; ++i)
{
iret = iret * 2;
}
return iret;
}
// 对index进行max堆处理
void MaxHeapify(int* ptr_data, int index, int len)
{
int left_index = left(index);
int right_index = right(index);
int large_index = index;
if (left_index < len && ptr_data[left_index] > ptr_data[large_index])
{
large_index = left_index;
}
if (right_index < len && ptr_data[right_index] > ptr_data[large_index])
{
large_index = right_index;
}
if (large_index != index)
{
int temp = ptr_data[index];
ptr_data[index] = ptr_data[large_index];
ptr_data[large_index] = temp;
MaxHeapify(ptr_data, large_index, len);
}
}
// 对index获取应该显示的位置
void GetPrintPos(int index, int* x, int* y)
{
int height_index = lgx(index + 1);
int layer_current_height = square2(height_index);
int offset = g_x_max / layer_current_height / 2;
if (offset == 0)
{
assert(0);
return;
}
*y = height_index;
int index_in_current_row = index - (layer_current_height - 1);
*x = offset * (2 * index_in_current_row + 1);
}
// 打印数据
void PrintfData(int* ptr_data, int len)
{
int* ptr_node_pos = (int *)malloc(sizeof(int) * len);
int i = 0;
for (i = 0; i < len; ++i)
{
int x = 0;
int y = 0;
GetPrintPos(i, &x, &y);
ptr_node_pos[i] = y * g_x_max + x;
}
i = 0;
int xpos = 0;
int ypos = 0;
int height_index = lgx(len);
for (ypos = 0; ypos < height_index + 1; ++ypos)
{
for(xpos = 0; xpos < g_x_max; ++xpos)
{
if (ypos*g_x_max + xpos == ptr_node_pos[i])
{
printf("%02d", ptr_data[i]);
++i;
}
else
{
printf("**");
}
}
printf("\n");
}
printf("\n");
free(ptr_node_pos);
}
// 建最大堆
void BuildMaxHeap(int* ptr_data, int len)
{
int i = len / 2;
for(; i >=0 ; --i)
{
MaxHeapify(ptr_data, i, len);
}
}
// 堆排序
void HeapSort(int* ptr_data, int len)
{
BuildMaxHeap(ptr_data,len);
int i = 0;
for (i = len-1; i > 0; i--)
{
int temp = ptr_data[i];
ptr_data[i] = ptr_data[0];
ptr_data[0] =temp;
MaxHeapify(ptr_data, 0, i);
}
}
int main()
{
int ptr_data[] = {9,6,5,25,63,15,95,48,56,21,45,2,8,7,11,22,35};
int len = sizeof(ptr_data) / sizeof(int);
int height_index = lgx(len);
int num_last = square2(height_index);
g_x_max = num_last * 2+ 2;
printf("before sort:\n");
PrintfData(ptr_data, len);
printf("after build heap:\n");
BuildMaxHeap(ptr_data, len);
PrintfData(ptr_data, len);
printf("after sort:\n");
HeapSort(ptr_data, len);
PrintfData(ptr_data, len);
getchar();
}