C++模板学习之优先队列实现
转载: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++模板学习之优先队列实现的更多相关文章
- XTemplate模板学习和使用总结
XTemplate模板学习和使用总结 前言 XTemplate是我接触的第一个模板语言,用在公司的一个NodeJS项目中,跟它打交道经常是因为需要使用它的语法向模板中注入数据.因为是刚入门前端不久 ...
- PHP-自定义模板-学习笔记
1. 开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2. 整体架构图 ...
- C++模板学习
一.定义函数模板 template<class T> 函数定义 举个例子比较两个数大小: template<class T> int Compare(T a,T b) { ; ...
- C++模板学习随笔
本文学习内容参考:http://www.cnblogs.com/gw811/archive/2012/10/25/2738929.html C++模板 1.模板分为函数模板和类模板两种类型 函数模板针 ...
- 模板学习实践二 pointer
c++ template学习记录 使用模板将实际类型的指针进行封装 当变量退出作用域 自动delete // 1111.cpp : 定义控制台应用程序的入口点. // #include "s ...
- 算法模板学习专栏之总览(会慢慢陆续更新ing)
博主欢迎转载,但请给出本文链接,我尊重你,你尊重我,谢谢~http://www.cnblogs.com/chenxiwenruo/p/7495310.html特别不喜欢那些随便转载别人的原创文章又不给 ...
- wordpress学习三:wordpress自带的模板学习
在<学习二>里,大概说了下怎么去查找模板,本节我们以一个简单的模板为例子,继续说说wordpress的模板机制,看看做一个自己的模板需要哪些知识点. 页面模板渲染 wordpress的模板 ...
- C++模板学习笔记
一个有趣的东西:实现一个函数print, 输入一个数组, 输出数组的各个维度长度. eg. ], b[][], c[][][]; print(a); //(2, 4) print(b); //(3, ...
- 转:C++模板学习
C++ 模板 转:http://www.runoob.com/cplusplus/cpp-templates.html 2018-01-05 模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的 ...
随机推荐
- 三大数据库 sequence 之华山论剑 (上篇)
前言 本文将基于以下三种关系型数据库,对 sequence (序列) 展开讨论. Oracle - 应用最广泛的商用关系型数据库 PostgreSQL - 功能最强大的开源关系型数据库 MySQL - ...
- 用 UI 多线程处理 WPF 大量渲染的解决方案
众所周知, WPF 的 UI 渲染是单线程的,所以如果我们异步或者新建线程去进行数据处理的时候,处理完,想要更新 UI 的时候,需要调用一下 Dispatcher.Invoke,将处理完的数据推入到 ...
- 每日一算法之two sum
题目如下:首先准备一个数组,[1,2,8,4,9] 然后输入一个6,找出数组两项之和为6的两个下标. 啥也不想,马上上代码,这个太简单了, static int[] twoSum(int[] num ...
- Tableau学习Step2一数据文件的读取与统计图、表的概述
Tableau学习Step2一数据文件的读取与统计图.表的概述 本文首发于博客冰山一树Sankey,去博客浏览效果更好. 一. 前言 本教程通过一个案例从浅到深来学习Tableau知识 案例概述: 二 ...
- 面试官:Redis中哈希数据类型的内部实现方式是什么?
面试官:Redis中基本的数据类型有哪些? 我:Redis的基本数据类型有:字符串(string).哈希(hash).列表(list).集合(set).有序集合(zset). 面试官:哈希数据类型的内 ...
- mysql破解root口令
破解root口令 [root@centos8 ~]#vim /etc/my.cnf [mysqld] skip-grant-tables #取消密码验证 skip-networking # mysql ...
- linux作业--第一周
1.按系列罗列Linux的发行版,并描述不同发行版之间的联系与区别. 目前三大主流发行版分别为Debian.Redhat.SUSE. redhat: RHEL: Red Hat公司发布的面向企业用户的 ...
- MySQL启动报错Failed to open log (file 'D:\phpStudy\PHPTutorial\MySQL\data\mysql_bin.000045', errno 2)
MySQL报错 191105 9:39:07 [Note] Plugin 'FEDERATED' is disabled. 191105 9:39:07 InnoDB: The InnoDB memo ...
- 使用 Fiddler 进行 iOS 抓包
使用 Fiddler(下载) 进行 iOS 抓包,具体步骤如下: 安装并配置 Fidder 安装并打开 Fiddler, 点击 Tools -> Fiddler Options 选中 Decrp ...
- centeros7 定时任务
crond是什么? crond 和crontab是不可分割的.crontab是一个命令,常见于Unix和类Unix的操作系统之中,用于设置周期性被执行的指令.该命令从标准输入设备读取指令,并将其存放于 ...