数据结构 堆排序

堆排序

堆排序(Heap Sort)是一种基于比较的排序算法,利用堆这种数据结构来实现排序。堆是一种特殊的完全二叉树,分为最大堆和最小堆。

堆的定义

  • 最大堆:对于每个节点,节点的值都大于或等于其子节点的值。

  • 最小堆:对于每个节点,节点的值都小于或等于其子节点的值。

一、堆排序的步骤

堆排序(从最下开始)(时间复杂度为O(NlogN+N),N可省略,即为O(NlogN) 1.建堆(若要降序排序则建小堆,若要升序排序则建大堆) 2.排序

二、相关函数

typedef class {
public:
    symbol* m_a;
    int m_size;
    int m_capacity;
}Heap;
//交换
void Swap(symbol* a, symbol* b);
//向下调整法
void AdjustDown(symbol* m_a, int size, int root);
//向上调整法
void AdjustUp(symbol* m_a, int size, int child);
//堆的初始化
void HeapInit(Heap* hp, symbol* a, int size);
//堆的排序
void HeapSort(Heap* hp);
//堆的删除
void HeapDestroy(Heap* hp);
//向堆内推入一个数
void HeapPush(Heap* hp, symbol pushnumber);
//推出堆顶的数
void HeapPop(Heap* hp);
//返回堆顶的数
symbol HeapTop(Heap* hp);

三、前提概要

求二叉树某一结点的孩子结点:左孩子lchild = parent * 2 + 1;右孩子rchild = parent * 2 + 2(或lchild++)

求某一结点的父节点:parent=(child-1)/2;

四、相关函数的实现

  • 交换

void Swap(symbol* a1, symbol* b1) {
    symbol tmp = *a1;
    *a1 = *b1;
    *b1 = tmp;
}
  • 向下调整算法:时间复杂度为O(logN==h)

void AdjustDown(symbol* m_a, int size, int root) {
    symbol parent = root;
    symbol child = parent * 2 + 1;
    while (child < size) {
        if (child + 1 < size && m_a[child + 1] < m_a[child])//当建的是小堆时为<,当建的是大堆时为>
            ++child;
        if (m_a[child] < m_a[parent])//当建的是小堆时为<,当建的是大堆时为>
        {
            Swap(&m_a[child], &m_a[parent]);
            parent = child;
            child = parent * 2 + 1;
        }
        else break;
    }
}
  • 向上调整算法:时间复杂度为O(logN==h)

void AdjustUp(symbol* m_a, int size, int child) {
    symbol parent = (child - 1) / 2;
    while (child > 0) {
        if (m_a[child] < m_a[parent]) {
            Swap(&m_a[child], &m_a[parent]);
            child = parent;
            parent = (child - 1) / 2;
        }
        else break;
    } 
}
  • 堆的初始化

void HeapInit(Heap* hp, symbol* a, int size) {
    hp->m_a = new int[size];
    hp->m_capacity =hp->m_size= size;
    memcpy(hp->m_a, a, sizeof(int)*size);
​
    //建堆(时间复杂度为O(N),利用错位相减法求时间复杂度)
    for (int i = (size - 1 - 1) / 2; i >= 0; i--) {
        AdjustDown(hp->m_a, hp->m_size, i);
    }
}
  • 排序

void HeapSort(Heap*hp) {
    //排序(时间复杂度为O(NlogN)
    //通过建堆可选出最小(大)数位于堆顶,且左右子树是小(大)堆
    //将堆顶的数与最后一个数交换,再从堆顶开始向下调整算法并将交换至末尾的数排除,即可选出次小(大)的数,将其置于最小(大)的前一位
    //共有N个节点,故重复N次,即可完成降序排序
    //每次向下调整算法的时间复杂度为O(logN),所以排序的时间复杂度为O(NlogN)
    int end = hp->m_size - 1;
    while (end > 0) {
        Swap(&hp->m_a[0], &hp->m_a[end]);
        AdjustDown(hp->m_a, end, 0);
        --end;
    }
}
  • 向堆内推入一个数

//先将该数推入堆的末尾,再通过向上调整法和父亲比较,若小则交换,再和父亲比较直至堆顶,若大则停止
void HeapPush(Heap* hp, symbol pushnumber) {
    if (hp->m_capacity == hp->m_size) {
        hp->m_capacity *= 2;
        symbol* tmp = (symbol*)realloc(hp->m_a, sizeof(symbol) * hp->m_capacity);
        if (tmp == NULL)
        {
            cout << "内存不足";
            exit(-1);
        }
        else hp->m_a = tmp;
    }
    hp->m_a[hp->m_size] = pushnumber;
    ++hp->m_size;
    AdjustUp(hp->m_a, hp->m_size, hp->m_size-1);
}
  • 推出堆顶的数

//将堆顶的数和最后一个数交换,然后通过size-1删去交换到最后一个数的堆顶,因为左右子树都是小堆,故进行一次向下调整法一个获得一个小堆
void HeapPop(Heap* hp) {
    Swap(&hp->m_a[0], &hp->m_a[hp->m_size-1]);
    --hp->m_size;
    AdjustDown(hp->m_a, hp->m_size, 0);
}

//返回堆顶的数
symbol HeapTop(Heap* hp) {
    return hp->m_a[0];
}
  • 删除堆

//堆的删除
void HeapDestroy(Heap* hp) {
    delete hp->m_a;
    hp->m_a = NULL;
    hp->m_capacity = hp->m_size = 0;
}

向下调整算法图示:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值