排序算法-堆排序

归并排序需要我们多一份空间出来,算法复杂度为O(nlgn)
堆排序也能做到算法复杂度为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();
}
 




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值