转载:https://www.cnblogs.com/muzicangcang/p/10579250.html

今天将继续将强C++模板类的学习,同时为了巩固已经学习过的数据结构中有关优先队列的知识,我将会使用模板类来实现自己的优先队列。在给出具体实现之前,我要先介绍一下什么是优先队列,聊以为复习吧。

在某些情况下,我们会收集一些元素,处理当前元素的最大值,然后再收集更多数据,再处理此时的最大值。这就要求我们设计的数据结构能够随时访问元素集合中的最大值和能够随时插入数据。优先队列即可以实现这种功能。

优先队列

优先队列的实现有两种思路,第一是在数据插入时保存数据元素的有序性,这意味着我们能够以O(1)的时间复杂度来访问元素中的最大值。但是我们在数据进行插入的时候,对寻找数据的合适位置的访问操作的最坏时间复杂度为O(N)。第二种思路是构建一个堆,他能够让我们以N(1)的时间复杂度来访问元素中的最大值,而以O(logN)的时间复杂度来调整堆,以便将元素插入到合适的位置。综上所述,在具体实现优先队列的时候需要根据待处理的元素量级来确定到底使用哪种思路。很明显,当数量级较小的时候,适合使用第一种思路;当数量级较大的时候,第二种思路将比较好。

首先简单介绍一下什么是堆。

1、堆是一种数据结构,他是一棵完全二叉树

2、在堆中,每个父节点都大于等于它的两个孩子结点,被称为堆有序

3、如果将堆由上到下,由左到右从0开始编号(即根节点编号为0),则某个节点,它的左孩子编号=(该结点的编号*2+1);右孩子结点的编号=(该结点编号*2+2)。他的第一个存在孩子结点的结点编号为(堆长度/2-1)

优先队列堆实现

//
// Created by yz on 19-8-31.
//
#include <iostream>
#include <algorithm>
#include <vector> using namespace std; /*****************优先队列实现**************************/
//默认仿函数,最大堆
template <class T>
class _compare
{
public:
bool operator()(T a,T b)
{
return a<b;
}
}; template <class T,class compareType=_compare<T>>
class MyPriorityQueue
{
private:
T* m_data;//数据
size_t m_size;//元素个数
size_t m_capacity;//队容量
compareType m_compare;
private:
void heapInsert();//向上调整堆
void heapify();//向下调整堆
void obj_cpy(T*,const T*,size_t);//元素复制
inline void swap(size_t i,size_t j);//交换元素
public:
MyPriorityQueue();//构造函数
~MyPriorityQueue(); bool push(const T& obj);//入队操作
bool pop();//删除队头元素
T top();//获取队头元素 bool empty()const//返回是否为空
{
return 0==m_size;
}
size_t size()const//返回队列大小
{
return m_size;
}
size_t capacity()const //返回队列容量
{
return m_capacity;
}
void show()
{
cout<<"队列元素数量为:"<<m_size<<endl;
cout<<"将队列从大到小打印"<<endl;
size_t len=m_size;
for (int i = 0; i <len; ++i) {
cout<<top()<<" ";
pop();
}
cout<<endl;
}
};
//无参构造函数
template <class T,class compareType>
MyPriorityQueue<T,compareType>::MyPriorityQueue() :m_size(0),m_capacity(10)
{
m_data=new T[m_capacity];
if(nullptr==m_data)
{
throw "申请空间失败";
}
}
//析构函数
template <class T,class T2>
MyPriorityQueue<T,T2>::~MyPriorityQueue()
{
if(m_data!= nullptr)
{
delete [] m_data;//释放空间
m_data= nullptr;//置空
}
}
//交换元素
template <class T,class T2>
void MyPriorityQueue<T,T2>::swap(size_t i, size_t j)
{
T temp=m_data[i];
m_data[i]=m_data[j];
m_data[j]=temp;
}
//插入队尾后,需要向上重新调整堆结构
template <class T,class T2>
void MyPriorityQueue<T,T2>::heapInsert()
{
size_t index=m_size-1;//index指向最后一个元素
//同父节点进行比较,如果满足,交换,上浮
while(index>0&&m_compare(m_data[(index-1)/2],m_data[index]))
{
swap((index-1)/2,index);
index=(index-1)/2;//index指向他的父节点;
}
}
//当队头出队,需要将队尾移动到队头,向下重新调整堆
template <class T,class T2>
void MyPriorityQueue<T,T2>::heapify()
{
size_t index=0;
size_t left=index*2+1;
while(left<m_size)//该节点有左孩子
{
//有右孩子的话选择左右孩子较大的那一个
size_t largest=left+1<m_size&&m_compare(m_data[left],m_data[left+1])?left+1:left;
//比较孩子节点与父节点
largest=m_compare(m_data[largest],m_data[index])?index:largest;
if(largest==index)//父节点已经是最大节点跳出循环
{
break;
}
swap(largest,index);
index=largest;
left=2*index+1;
} }
//元素复制
template <class T,class T2>
void MyPriorityQueue<T,T2>::obj_cpy(T * dest, const T * sour, size_t n)
{
for (size_t i = 0; i <n; ++i) {
dest[i]=sour[i];
}
} //入队操作
template <class T,class T2>
bool MyPriorityQueue<T,T2>::push(const T& obj)
{
T* tempPtr=m_data;
if(m_size==m_capacity)//空间不足,则需要重新申请空间
{
m_capacity*=2;//重新申请的空间的大小
m_data=new T[m_capacity];
if(m_data== nullptr)
{
m_data=tempPtr;//恢复原来的空间
m_capacity/=2;//恢复原来的容量
return false;//返回失败
}//申请空间成功
obj_cpy(m_data,tempPtr,m_size);//复制数据到新空间中
delete [] tempPtr;//删除旧空间
}
m_data[m_size++]=obj;//加入队列
heapInsert();//向上重新调整堆
return true;
}
//出队操作
template <class T,class T2>
bool MyPriorityQueue<T,T2>::pop()
{
if(m_size==0)
return false;
if (m_size==1)
{
m_size=0;
return true;
}
m_data[0]=m_data[m_size-1];//将队尾数据复制到队头
m_size--;//队尾元素个数减一
heapify();//重新向下调整堆
return true;
}
//取队头元素
template <class T,class T2>
T MyPriorityQueue<T,T2>::top()
{
if(m_size<=0)
throw "空队列";
return m_data[0];//返回队头元素
}
/******************************************************/
//仿函数,最小堆
template <class T>
class MyCompare
{
public:
bool operator()(T a,T b)
{
return a>b;
}
};
void test01()
{
MyPriorityQueue<int> maxQueue;
maxQueue.push(4);
maxQueue.push(2);
maxQueue.push(3);
cout<<"利用默认比较函数建最大堆"<<endl;
maxQueue.show(); cout<<"利用自己定义的比较仿函数,建最小堆"<<endl;
MyPriorityQueue<int,MyCompare<int>>minQueue;
minQueue.push(3);
minQueue.push(1);
minQueue.push(2);
minQueue.show();
}
int main()
{
test01();
return 0;
}

  

C++模板学习之优先队列实现的更多相关文章

  1. XTemplate模板学习和使用总结

    XTemplate模板学习和使用总结 前言   XTemplate是我接触的第一个模板语言,用在公司的一个NodeJS项目中,跟它打交道经常是因为需要使用它的语法向模板中注入数据.因为是刚入门前端不久 ...

  2. PHP-自定义模板-学习笔记

    1.  开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2.  整体架构图 ...

  3. C++模板学习

    一.定义函数模板 template<class T> 函数定义 举个例子比较两个数大小: template<class T> int Compare(T a,T b) { ; ...

  4. C++模板学习随笔

    本文学习内容参考:http://www.cnblogs.com/gw811/archive/2012/10/25/2738929.html C++模板 1.模板分为函数模板和类模板两种类型 函数模板针 ...

  5. 模板学习实践二 pointer

    c++ template学习记录 使用模板将实际类型的指针进行封装 当变量退出作用域 自动delete // 1111.cpp : 定义控制台应用程序的入口点. // #include "s ...

  6. 算法模板学习专栏之总览(会慢慢陆续更新ing)

    博主欢迎转载,但请给出本文链接,我尊重你,你尊重我,谢谢~http://www.cnblogs.com/chenxiwenruo/p/7495310.html特别不喜欢那些随便转载别人的原创文章又不给 ...

  7. wordpress学习三:wordpress自带的模板学习

    在<学习二>里,大概说了下怎么去查找模板,本节我们以一个简单的模板为例子,继续说说wordpress的模板机制,看看做一个自己的模板需要哪些知识点. 页面模板渲染 wordpress的模板 ...

  8. C++模板学习笔记

    一个有趣的东西:实现一个函数print, 输入一个数组, 输出数组的各个维度长度. eg. ], b[][], c[][][]; print(a); //(2, 4) print(b); //(3, ...

  9. 转:C++模板学习

    C++ 模板 转:http://www.runoob.com/cplusplus/cpp-templates.html 2018-01-05 模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的 ...

随机推荐

  1. [故障]ceph存储池权限修改错误,导致存储池的业务hang住

    描述: 记录一次重大事故:根据IaaS资源业务要求,需要增加某些功能,所以要修改部署代码.修改后重推部署代码,检查发现没有什么异常. 但是一段时间后就收到用户的报障反馈,接连一个电话.2个电话.3个电 ...

  2. 从这3个方面考虑BI工具,选型一选一个准

    BI工具在很多场合都能听到,那么BI工具有什么功能呢?能给企业带来什么?好用的BI工具长什么样?今天跟着小编走近BI工具,一探究竟! 首先要了解BI工具的定义,什么是BI工具.BI工具是指利用现代数据 ...

  3. 一图胜千言,想让数据产生影响力,必须拥有好上手的BI数据分析工具

    当杂乱无章的数据,经过数据清洗后,得到了想用的数据,但是查看这些数据通过数据库只能看到数据本身,无法看到其中的规律,可以通过BI数据分析工具,图形化展示数据,使数据更形象化的展现在用户面前,更容易看出 ...

  4. 【C# .Net GC】GC内存分配规则

    GC 管理内存分配和回收 公共语言运行时的垃圾回收器为应用程序管理内存的分配和释放. https://docs.microsoft.com/zh-cn/dotnet/standard/automati ...

  5. 【C# 锁】SpinWait结构 -同步基元|同步原语

    锁提供了线程安全三要素中的 有序性.二.SpinWait是同步锁的核心,而Thread是SpinWait的核心. Spinwait结构 完成代码:SpinWait.cs (dot.net) SpinW ...

  6. 【Windows 访问控制】八、安全主体和安全对象

    安全主体(security principal)? 安全主体是任何可通过操作系统进行身份验证的实体,例如用户帐户.计算机帐户.在用户或计算机帐户的安全上下文中运行的线程或进程,或者这些帐户的安全组. ...

  7. ConvertHelper

    DataTable 转Json using Newtonsoft.Json; public static string DataTableToJson(DataTable dt) { varJsonS ...

  8. 【有奖调研】来,聊聊TTS音色定制这件事儿

    音色个性化定制,一个能让文字转语音服务(TTS)在用户交互过程中注入温度的技术. 文能在营销及内容交付中让品牌保持一致性,武能让开发者"音"量加持,创新开发. 这个100%钢铁纯技 ...

  9. linux su、sudo、sudo su、sudo -i的用法和区别

    sudo : 暂时切换到超级用户模式以执行超级用户权限,提示输入密码时该密码为当前用户的密码,而不是超级账户的密码.不过有时间限制,Ubuntu默认一次时长15分钟. su : 切换到某某用户模式,提 ...

  10. 专业5 laravel框架添加,删除,恢复,分页,搜索接口

    //////////////////////资源路由 //商品资源路由恢复Route::get('/restore/{id}','goodController@restore');//商品资源路由添加 ...