数据结构-----堆的应用

上次内容中,我们对堆有了一个大概的认识,现在,我们就来看看堆中有哪些应用吧!!!
一、优先级队列
概念:优先级队列是不同于先进先出队列的另一种队列。每次从队列中取出的是具有最高优先权的元素。
解释:优先级队列是对堆的一次封装,利用堆的性质,封装出来一个与堆类似的东西,从而达到自己的目的。
下面,直接来上代码,此处的优先级队列,依赖前面的堆的基础实现,有需要的,可以先看堆的实现有关堆的创建与实现
现在,我们来具体看下如何对堆实现一次封装,代码如下所示:

#define _CRT_SECURE_NO_WARNINGS 1
//#pragma once
#include"heap.hpp"

//优先级队列
template<class T,class Compare>
class PriorityQueue
{
public:
    PriorityQueue()
    {}

    void Push(const T&data)
    {
        _hp.Push(data);
    }
    void Pop()
    {
        _hp.Pop();
    }
    bool Empty()const
    {
        return _hp.Empty();
    }
    size_t Size()const
    {
        return _hp.Size();
    }
    T Top()const
    {
        return _hp.Top();
    }

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

void Test1()
{
    PriorityQueue<int,Less<int> > q;
    q.Push(2);//往堆中放入元素
    q.Push(10);
    q.Push(1);
    cout << q.Size() << endl;
    cout << q.Top() << endl;

    q.Pop();//删除堆中元素
    cout << q.Size() << endl;
    cout << q.Top() << endl;
    if (!q.Empty())//判空
        cout << "非空" << endl;
    else
        cout << "空" << endl;

    q.Pop();
    cout << q.Size() << endl;
    cout << q.Top() << endl;

    q.Pop();//堆中只有一个元素
    cout << q.Size() << endl;
    cout << q.Top() << endl;
    if (!q.Empty())
        cout << "非空" << endl;
    else
        cout << "空" << endl;
    q.Pop();//空堆
    cout << q.Size() << endl;
    cout << q.Top() << endl;
    if (!q.Empty())
        cout << "非空" << endl;
    else
        cout << "空" << endl;
}

二、堆排序
堆排序主要有两个步骤,分别为:
1、创建堆——>向下调整
升序—->大堆
降序—->小堆
2、排序(此处先默认为升序—->大堆)
在这里,排序的主要思路是:利用堆顶元素与堆中最后一个元素进行交换,则将最大的元素放置在最后,相当于这个元素已经排好,而交换后的堆有可能不符合堆的条件,则进行调整(向下调整的思路),此次的调整,排除最后一个元素,让上面的步骤不断重复,则将生成一个升序的序列。
注意:在排序中,如果为空堆与堆中只有一个元素,则都不需要进行排序。
堆排序的时间复杂度为:两次调整的时间复杂度,即N*logN+N*logN=O(N*logN)。

堆排序的代码如下所示:

#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<algorithm>
#include<iostream>
using namespace std;
//升序----大堆,降序----小堆
void AdjustHeap(int *array, int size, size_t parent)
{
    //默认左孩子最大
    size_t child = parent * 2 + 1;
    while (child < size)
    {
        //找最大的孩子
        if (child + 1 < size&&array[child] < array[child + 1])
            child = child + 1;
        //交换
        if (array[parent] < array[child])
        {
            swap(array[parent], array[child]);
            parent = child;
            child = parent * 2 + 1;
        }
        else
            return;
    }
}

void HeapSort(int *array, int size)
{
    //创建堆
    int root = (size - 1 - 1) >> 1;
    for (; root >= 0; --root)
    {
        AdjustHeap(array, size, root);//向下调整
    }
    //排序
    int i = 0;
    for (; i < size - 1; ++i)
    {
        //堆顶元素与最后一个元素交换
        swap(array[0], array[size - 1 - i]);
        AdjustHeap(array, size - i - 1,0);
    }
}

void Test2()
{
    int array[] = { 53, 17, 78, 9, 45, 65, 87, 23 };
    HeapSort(array, sizeof(array) / sizeof(*array));
    int i = 0;
    for (; i < sizeof(array) / sizeof(*array); ++i)
    {
        cout << array[i] << " " << endl;
    }
}

但是,如果要在堆排序中,进行任意排序,即降序与升序均可,则需要一个比较器,将其定义为一个模板,则可以进行任意的排序了,具体实现如下所示:

#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<iostream>
using namespace std;
template<class T>
class Last//小堆
{
public:
    bool operator()(const T&left, const T&right)
    {
        return left < right;
    }
};

template<class T>
class Most//大堆
{
public:
    bool operator()(const T&left, const T&right)
    {
        return left > right;
    }
};

template<class T, class Compare1 = Last<T>>//缺省时为小堆
class HeapSort1
{
public:
    HeapSort1(T*array, size_t size)
    {
        //创建堆
        //开辟空间
        _array.resize(size);
        //拷贝元素
        for (int i = 0; i < size; ++i)
        {
            _array[i] = array[i];
        }
        //调整元素
        int root = (size - 1 - 1) >> 1;
        for (; root >= 0; --root)
        {
            AdjustHeap(size, root);
        }

        //排序
        int j = 0;
        for (; j < size - 1; ++j)
        {
            //堆顶元素与最后一个元素交换
            swap(_array[0], _array[size - 1 - j]);
            AdjustHeap(size - j - 1, 0);
        }
    }
    void Print(size_t size)
    {
        int i = 0;
        for (; i < size; ++i)
        {
            cout << _array[i] << " ";
        }
        cout << endl;
    }
private:
    //创建小堆-----向下调整
    void AdjustHeap(int size, size_t parent)
    {
        //标记左孩子,且默认左孩子为最小的孩子
        size_t child = parent * 2 + 1;
        //找最小的孩子
        while (child < size)
        {
            //Compare com;
            if (child + 1 <size && Compare1()(_array[child + 1], _array[child]))//在此处,因为默认左孩子最小,因此要返回true,只能是这样
            {
                child = child + 1;//右孩子为最小
            }
            //比较最小的孩子与双亲的大小----值域
            if (Compare1()(_array[child], _array[parent]))
            {
                swap(_array[parent], _array[child]);
                //交换之后,可能导致孩子结点不为堆
                parent = child;
                child = parent * 2 + 1;
            }
            else
                return;
        }
    }

private:
    vector<T> _array;
};

void Test3()
{
    int array[] = { 53, 17, 78, 9, 45, 65, 87, 23 };

    HeapSort1<int, Most<int> > hs(array, sizeof(array) / sizeof(*array));
    hs.Print(sizeof(array) / sizeof(*array));
}

至此,有关堆的应用大概就这么多,还请大家多多指教!!!

只有不停奔跑,才能不停留在原地。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值