堆的一些基本问题

使用平台:vs2013


基础概念部分

堆:堆数据结构是一种数组对象,通过数组实现堆数据结构,可以看做是一颗完全二叉树结构。

堆分为大堆和小堆

大堆:每个父节点都大于子节点;
小堆:每个父节点都小于孩子节点。


堆实现过程主要用到的知识点

1>用parent代表父节点下标,chaild代表孩子节点下标,则:

chaild=parent*2+1

parent=(chaild-1)/2

2>通过仿函数实现大小堆代码的复用;

3>用vector实现Heap时,注意需要先把空间开辟出来,实现通过下标访问;

#pragma once
#include <iostream>
using namespace std;

#include <vector>

#include <assert.h>

template <class T>
struct Greater
{
    bool operator()(const T& l, const T& r)
    {
        return l > r;
    }
};

template <class T>
struct Less
{
    bool operator()(const T& l, const T& r)
    {
        return l < r;
    }
};

//默认建大堆
template <class T, class Compare = Greater<T>>
class Heap
{
public:
    Heap()
    {}

    Heap(T* a, int n)
        :_array(a, a + n)//利用迭代器实现开辟n个大小空间
    {

        for (int i = (_array.size() - 2) / 2; i >= 0; --i)
        {
            _AdjustDown(i);
        }
    }

    void Push(const T& data)
    {
        _array.push_back(data);
        _AdjustUp(_array.size() - 1);
    }

    void Pop()
    {
        //vector 有判空机制
        swap(_array[0], _array[_array.size() - 1]);
        _array.pop_back();
        _AdjustDown(0);
    }

    size_t Size()
    {
        return _array.size();
    }

    bool Empty()
    {
        return _array.empty();
    }

    T& Top()
    {
        assert(!Empty());
        return _array[0];
    }

protected:

    //向上调整
    void _AdjustUp(int root)
    {
        int child = root;
        int parent = (root - 1) / 2;

        while (child >0)
        {
            Compare compare;
            if (compare(_array[child], _array[parent]))
            {
                swap(_array[parent], _array[child]);
                child = parent;
                parent = (child - 1) / 2;
            }
            else
            {
                break;
            }
        }
    }

    //向下调整
    void _AdjustDown(int root)
    {
        int parent = root;
        int child = parent * 2 + 1;
        int size = _array.size();

        //注意结束条件
        while (child < size)
        {
            Compare compare;
            if (child + 1 < size && compare(_array[child + 1], _array[child]))
            {
                ++child;
            }

            if (compare(_array[child], _array[parent]))
            {
                swap(_array[parent], _array[child]);

                parent = child;
                child = parent * 2 + 1;
            }
            else
            {
                break;
            }
        }
    }

protected:
    vector<T> _array;
};

TopK问题

1>找最大的前K个数,建小堆

2>找最小的前K个数,建大堆

找最大的前K个数基本思想:

通过前K个数建立一个小堆,堆顶存放的是这K个数中最小的数,剩余的数和堆顶的数进行比较,大于堆顶数据,交换,堆顶数据进行向下调整。

//topK问题
void AdjustDown(int* arr,int root,int k)
{
    int parent = root;
    int child = parent * 2 + 1;

    while (child < k)
    {
        if (child + 1 < k&&arr[child + 1] < arr[child])
            ++child;
        if (arr[parent]>arr[child])
        {
            swap(arr[parent], arr[child]);
            parent = child;
            child = parent * 2 + 1;
        }
        else
        {
            break;
        }
    }
}

//1. 找最大的前K个数——建小堆
void GetTopK(int* arr,int size,int k)
{
    //2.建堆——小堆
    for (int i = (k-2)/2; i >=0; --i)
    {
        AdjustDown(arr,i,k);
    }

    //3.剩余数和堆顶数进行比较,大于堆顶数,和堆顶数进行交换,向下调整
    int cur = k;
    while (cur < size)
    {
        if (arr[0] < arr[cur])
        {
            swap(arr[0], arr[cur]);
            AdjustDown(arr, 0, k);
            ++cur;
        }
        else
        {
            ++cur;
        }
    }

    //4.打印前K个数
    for (int i = 0; i < k; ++i)
        cout << arr[i] << " ";
    cout << endl;

}

优先级队列:在库中优先级队列是通过堆来实现的

template <class T,class Compare=Greater<T>>
class PriorityQueque
{
public:
    void Push(const T& data)
    {
        _hp.Push()
    }

    void Pop()
    {
        _hp.Pop();
    }

    bool Empty()
    {
        return _hp.Empty();
    }

    T& Top()
    {
        return _hp.Top();
    }

protected:
    Heap<T, Compare> _hp;
};

堆排序大致思路:

以降序为例,建小堆,堆顶数据为最小值,和最后一个数据进行交换,数组的可视范围减一,堆顶数据向下调整,直到数组大小减到0。

堆排序

//降序——建小堆
void HeapSort(int* arr,int n)
{
    assert(n>0);

    //建堆
    for (int i = (n - 2) / 2; i >= 0; --i)
    {
        AdjustDown(arr, i, n);
    }

    //调整顺序

    int end = n - 1;
    while (end > 0)
    {
        swap(arr[0], arr[end]);
        AdjustDown(arr, 0, end);
        --end;
    }

    for (int i = 0; i < n; ++i)
    {
        cout << arr[i] << " ";
    }
    cout << endl;
}

测试函数:

void TestHeap()
{
    int arr[9] = { 1, 2, 5, 0, 7, 3, 8, 4, 6 };
    Heap<int,Less<int>> hp(arr, sizeof(arr) / sizeof(arr[0]));
    hp.Pop();
    hp.Push(10);

    //topk
    int arr2[] = { 1, 2, 4, 3, 6, 5, 4, 9, 7, 8, 0 };
    int size = sizeof(arr2) / sizeof(arr2[0]);
    int k = 5;
    GetTopK(arr2, size,k);

    HeapSort(arr, sizeof(arr) / sizeof(arr[0]));

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值