栈和队列模拟实现(C++)

文章目录

  • 0.码云完整代码
  • 1.deque的认识
    • 1.1介绍
    • 1.2图析
    • 1.3性能比较
  • 2.stack的学习
    • 2.1模拟实现
    • 2.2测试函数
  • 3.queue的学习
    • 3.1模拟实现
    • 3.2测试函数
  • 4.优先级队列的学习
    • 4.0仿函数的引入
    • 4.1介绍
    • 4.2例题
    • 4.3模拟实现
  • 5.测试函数

0.码云完整代码

点击 栈 队列 优先级队列 跳转码云获取完整代码

1.deque的认识

1.1介绍

双端队列
Deque(通常读作“deck”)是double-ended queue的不规则首字母缩写。双端队列是动态长度的序列容器,可以在两端(前端或后端)伸缩。
特定的库可能以不同的方式实现deque,通常是某种形式的动态数组。但在任何情况下,它们都允许通过随机访问迭代器直接访问各个元素,存储空间通过根据需要扩展和收缩容器来自动处理。
因此,它们提供了类似于向量的功能,但可以高效地在序列的开头和末尾插入和删除元素。但是,与向量不同的是,deque不能保证将其所有元素存储在连续的存储位置上:通过偏移指向另一个元素的指针来访问deque中的元素会导致未定义的行为。
vector和deque提供了非常相似的接口,也可以用于类似的目的,但两者的内部工作方式却完全不同:vector使用单一数组,需要偶尔重新分配空间以适应增长,而deque中的元素可能分散在不同的存储块中,容器在内部保存了必要的信息,以便以常量时间和统一的顺序接口(通过迭代器)直接访问其中的任何元素。因此,deque的内部结构比vector稍微复杂一些,但这使得它们在某些情况下可以更高效地增长,特别是在序列很长时,重分配的开销会变得更大。
对于频繁地在非起始或结束位置插入或删除元素的操作,deque的性能更差,迭代器和引用的一致性也不如列表和前向列表。

Double ended queue
deque (usually pronounced like "deck") is an irregular acronym of double-ended queue.  Double-ended queues are sequence containers with dynamic sizes that can be expanded or contracted on both ends (either its front or its back).

Specific libraries may implement deques in different ways, generally as some form of dynamic array.  But in any case, they allow for the individual elements to be accessed directly through random access iterators, with storage handled automatically by expanding and contracting the container as needed.

Therefore, they provide a functionality similar to vectors, but with efficient insertion and deletion of elements also at the beginning of the sequence, and not only at its end.  But, unlike vectors, deques are not guaranteed to store all its elements in contiguous storage locations: accessing elements in a deque by offsetting a pointer to another element causes undefined behavior.

Both vectors and deques provide a very similar interface and can be used for similar purposes, but internally both work in quite different ways: While vectors use a single array that needs to be occasionally reallocated for growth, the elements of a deque can be scattered in different chunks of storage, with the container keeping the necessary information internally to provide direct access to any of its elements in constant time and with a uniform sequential interface (through iterators).  Therefore, deques are a little more complex internally than vectors, but this allows them to grow more efficiently under certain circumstances, especially with very long sequences, where reallocations become more expensive.

For operations that involve frequent insertion or removals of elements at positions other than the beginning or the end, deques perform worse and have less consistent iterators and references than lists and forward lists.

1.2图析

在这里插入图片描述
在这里插入图片描述

1.3性能比较

//性能测试vector比deque快大约2倍
void test_op()
{
	srand(time(0));
	const int N = 100000;

	vector<int> v;
	v.reserve(N);

	deque<int> dp;

	for (int i = 0; i < N; ++i)
	{
		auto e = rand();
		v.push_back(e);
		dp.push_back(e);
	}

    int begin1 = clock();
	sort(v.begin(), v.end());
	int end1 = clock();

	int begin2 = clock();
	sort(dp.begin(), dp.end());
	int end2 = clock();

	printf("vector sort:%d\n", end1 - begin1);
	printf("deque sort:%d\n", end2 - begin2);
}

int main()
{
	test_op();

	return 0;
}

2.stack的学习

2.1模拟实现

#pragma once
#include <iostream>
#include <assert.h>
#include <deque>
using namespace std;

namespace apex
{                                // Double-ended queue  双端队列
	template<class T, class Container = deque<T>>
	class stack
	{
	public:
		
		//压栈 -- 栈顶入数据 -- 尾插
		void push(const T& x)
		{
			_con.push_back(x);
		}

		//出栈 -- 栈顶出数据 -- 尾插
		void pop()
		{
			_con.pop_back();
		}

		//取栈顶 -- 数据的尾部 -- back()函数
		T& top()
		{
			return _con.back();
		}
		const T& top() const
		{
			return _con.back();
		}

		//判空 -- 对象的empty函数
		bool empty()  const
		{
			return _con.empty();
		}

		//栈大小 -- size函数
		size_t size() const
		{
			return _con.size();
		}

	private:
		Container _con; 
	};
}

2.2测试函数

//栈的测试
void test_stack()
{
	stack<int> st;
	//stack<int, vector<int>> st;
	//stack<int, list<int>> st;

	st.push(1);
	st.push(2);
	st.push(3);
	st.push(4);

	while (!st.empty())
	{
		cout << st.top() << endl;
		st.pop();
	}
}

3.queue的学习

3.1模拟实现

#pragma once
#include <deque>

namespace apex
{
	template<class T, class Container = deque<T>>
	class queue
	{
	public:
		//入队列 -- 尾插
		void push(const T& x)
		{
			_con.push_back(x);
		}
		
		//出队列 --  头删
		void pop()
		{
			_con.pop_front();
		}

		//取队尾 -- back函数
		T& back()
		{
			return _con.back();
		}
		const T& back() const
		{
			return _con.back();
		}

		//取队头 -- front函数
		T& front()
		{
			return _con.front();
		}
		const T& front() const
		{
			return _con.front();
		}

	    //判空 -- empty函数
		bool empty()  const
		{
			return _con.empty();
		}

		//队列大小 -- size函数
		size_t size() const
		{
			return _con.size();
		}

	private:

		Container _con;
	};
}

3.2测试函数


//队列的测试
void test_queue()
{
	queue<int> q;
	//queue<int, list<int>> q;
    //queue<int, vector<int>> q;

	q.push(1);
	q.push(2);
	q.push(3);
	q.push(4);

	while (!q.empty())
	{
		cout << q.front() << endl;
		q.pop();
	}
}

4.优先级队列的学习

4.0仿函数的引入

/*
 仿函数也称作函数对象  -- 它是一个类 
 在这个类里有公共成员函数 -- ()运算符重载函数
 类实例化对象调用它的公共成员函数 -- 就像是在使用普通函数一样
*/
namespace func
{

	//例子:
	/*
     class less
	{
	public:
		bool operator()(const int& left, const int& right) const
		{
			return left < right;
		}
	};
	*/

	//引入模板参数:
	template<class T>
	class less
	{
	public:
		bool operator()(const T& left, const T& right) const
		{
			return left < right;
		}
	};

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

int main()
{
	func::less<int> lsFunc;
    lsFunc(1, 2);  // lsFunc.operator()(1, 2) ;
	
	func::greater<int> gtFunc;
    gtFunc(1, 2) ;

	return 0;
}

4.1介绍

优先队列
优先级队列是一种容器适配器,根据某种严格的弱排序标准,特别设计为它的第一个元素总是它所包含的元素中的最大元素。
这个上下文类似于堆(heap),在堆中可以随时插入元素,但只能取得堆中最大的元素(优先队列中最上面的那个)。
优先队列是作为容器适配器实现的,容器适配器是使用特定容器类的封装对象作为其底层容器的类,提供一组特定的成员函数来访问其元素。元素从特定容器的“后面”弹出,也就是优先队列的顶部。
底层容器可以是任何标准容器类模板,也可以是其他专门设计的容器类。该容器应可通过随机访问迭代器访问
标准容器类vector和deque可以满足这些需求。默认情况下,如果没有为特定的priority_queue类实例化指定容器类,则使用标准容器向量。
支持随机访问迭代器需要始终在内部保持堆结构。这是由容器适配器自动完成的,在需要时自动调用算法函数make_heap、push_heap和pop_heap。

Priority queue
Priority queues are a type of container adaptors, specifically designed such that its first element is always the greatest of the elements it contains, according to some strict weak ordering criterion.

This context is similar to a heap, where elements can be inserted at any moment, and only the max heap element can be retrieved (the one at the top in the priority queue).

Priority queues are implemented as container adaptors, which are classes that use an encapsulated object of a specific container class as its underlying container, providing a specific set of member functions to access its elements.  Elements are popped from the "back" of the specific container, which is known as the top of the priority queue.

The underlying container may be any of the standard container class templates or some other specifically designed container class.  The container shall be accessible through random access iterators and support the following operations:
empty()
size()
front()
push_back()
pop_back()

The standard container classes vector and deque fulfill these requirements.  By default, if no container class is specified for a particular priority_queue class instantiation, the standard container vector is used.

Support of random access iterators is required to keep a heap structure internally at all times.  This is done automatically by the container adaptor by automatically calling the algorithm functions make_heap, push_heap and pop_heap when needed.

4.2例题

在这里插入图片描述

class solution
{
public:
	int findKthLargest(vector<int>& nums, int k)
	{
	//创建堆 -- O(N)
		priority_queue<int> maxHeap(nums.begin(), nums.end());
	//pop k-1 个数据 -- O(k * logN)
		while (--k)
			maxHeap.pop();
		return maxHeap.top();
	}
};

4.3模拟实现

#pragma once

namespace apex
{
	//仿函数类
	template<class T>
	class less
	{
	public:
		bool operator()(const T& left, const T& right) const
		{
			return left < right;
		}
	};
	template<class T>
	class greater
	{
	public:
		bool operator()(const T& left, const T& right) const
		{
			return left > right;
		}
	};

	//template <class T, class Container = vector<T>, class Compare = less<typename Container::value_type> > 
	template<class T, class Container = vector<T>, class Compare = less<T>>
	class priority_queue
	{
	public:

		//构造函数
		priority_queue()
		{
		
		}
		//迭代器构造
		template <class InputIterator>
		priority_queue(InputIterator first, InputIterator last)
		{
			while (first != last)
			{
				_con.push_back(*first);
				++first;
			}

			// 下调建堆法
			for (int i = (_con.size() - 1 - 1) / 2; i >= 0; --i)
			{
				adjust_down(i);
			}
		}

		// 上调NlogN
		void adjust_up(size_t child)
		{
			Compare com;
			size_t parent = (child - 1) / 2;
			while (child > 0)
			{
				
				//if (_con[parent] > _con[child])   //小堆
				//if (_con[parent] < _con[child])   //大堆
				
				if (com(_con[parent], _con[child])) //大堆
				{
					std::swap(_con[child], _con[parent]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}
		// 下调logN
		void adjust_down(size_t parent)
		{
			Compare com;
			size_t child = parent * 2 + 1;
			while (child < _con.size())
			{
				//if (child + 1 < _con.size() && _con[child] > _con[child + 1])    //找real小孩子
				//if (child + 1 < _con.size() && _con[child] < _con[child + 1])    //找real大孩子
				
				if (child + 1 < _con.size() && com(_con[child], _con[child + 1]))  //找real大孩子
				{
					++child;
				}

				//if (_con[parent] > _con[child])   //小堆
				//if (_con[parent] < _con[child])   //大堆
				
				if (com(_con[parent], _con[child])) //大堆
				{
					std::swap(_con[child], _con[parent]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
				{
					break;
				}
			}
		}

		//入队
		void push(const T& x)
		{
			//尾插数据
			_con.push_back(x);
			//向上调整
			adjust_up(_con.size() - 1);
		}

		//出队
		void pop()
		{
			//堆顶与堆尾交换
			std::swap(_con[0], _con[_con.size() - 1]);
			//删除现堆尾(原堆顶)
			_con.pop_back();

			adjust_down(0);
		}

		//取队头
		const T& top()
		{
			return _con[0];
		}

		//判空
		bool empty()  const
		{
			return _con.empty();
		}

		//队大小
		size_t size() const
		{
			return _con.size();
		}

	private:

		Container _con;
	};
}

5.测试函数

#define _CRT_SECURE_NO_WARNINGS 
#include <iostream>
#include <stack>
#include <queue>
#include <vector>
#include <list>
#include <algorithm>
#include <functional>
#include <time.h>
using namespace std;
 
#include "Stack.h"
#include "Queue.h"
#include "PriorityQueue.h"

//栈的测试
void test_stack()
{
	stack<int> st;
	//stack<int, vector<int>> st;
	//stack<int, list<int>> st;

	st.push(1);
	st.push(2);
	st.push(3);
	st.push(4);

	while (!st.empty())
	{
		cout << st.top() << endl;
		st.pop();
	}
}

//队列的测试
void test_queue()
{
	queue<int> q;
	//queue<int, list<int>> q;
    //queue<int, vector<int>> q;

	q.push(1);
	q.push(2);
	q.push(3);
	q.push(4);

	while (!q.empty())
	{
		cout << q.front() << endl;
		q.pop();
	}
}

//优先级队列的测试
void test_priority_queue()  // 默认大的优先级高
{
    //无参构造
	priority_queue<int> pq;

	//有参构造
	//explicit priority_queue(const Compare & comp = Compare()
	//template<class T, class Container = vector<T>, class Compare = less<T>>
	//class priority_queue { } ;
	less<int> ls;
	std::priority_queue<int> pq0(less<int>());
	std::priority_queue<int> pq1(ls);
	
	//迭代器区间构造
	int a[] = { 1,2,3,4,5,0 };
	priority_queue<int> pq2(a, a + sizeof(a) / sizeof(int));

	//传模板参数
	//大堆:less<T> 小堆:greater<T>
	//template <class T, class Container = vector<T>, class Compare = less<typename Container::value_type> > 
	priority_queue<int, vector<int>, greater<int>> pq3(a, a + sizeof(a) / sizeof(int));

	pq.push(1);
	pq.push(2);
	pq.push(3);
	pq.push(4);
	pq.push(5);
	pq.push(0);

	while (!pq.empty())
	{
		cout << pq.top() << " ";
		pq.pop();
	}
	cout << endl;  	//5 4 3 2 1 0
	
	while (!pq2.empty())
	{
		cout << pq2.top() << " ";
		pq2.pop();
	}
	cout << endl;  //0 1 2 3 4 5
	
}

//vector比deque快大约2倍
void test_op()
{
	srand(time(0));
	const int N = 100000;

	vector<int> v;
	v.reserve(N);

	deque<int> dp;

	for (int i = 0; i < N; ++i)
	{
		auto e = rand();
		v.push_back(e);
		dp.push_back(e);
	}

    int begin1 = clock();
	sort(v.begin(), v.end());
	int end1 = clock();

	int begin2 = clock();
	sort(dp.begin(), dp.end());
	int end2 = clock();

	printf("vector sort:%d\n", end1 - begin1);
	printf("deque sort:%d\n", end2 - begin2);
}

int main()
{
	test_priority_queue();

	return 0;
}


 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/49608.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

鸿鹄协助管理华为云与炎凰Ichiban

炎凰对华为云的需求 在炎凰日常的开发中&#xff0c;对于服务器上的需求&#xff0c;我们基本都是采用云服务。目前我们主要选择的是华为云&#xff0c;华为云的云主机比较稳定&#xff0c;提供的云主机配置也比较多样&#xff0c;非常适合对于不同场景硬件配置的需求&#xff…

石子合并(区间dp模板)

题目描述&#xff1a; dp分析&#xff1a; 解题代码&#xff1a; #include<iostream> using namespace std;const int N1e36;int f[N][N]; int a[N]; int s[N];int main(){int n;cin>>n;for(int i1;i<n;i){scanf("%d",&s[i]);s[i]s[i-1];//前缀和…

2.1数据结构——线性表

一、定义 线性表是具有相同数据类型的n&#xff08;n>0&#xff09;个数据元素的有限序列&#xff0c;&#xff08;n表示表长&#xff0c;n0为空表&#xff09; 用L表示&#xff1a; 位序&#xff1a;线性表中的“第i个” a1是表头元素&#xff1b;an是表尾元素 除第一个…

《吐血整理》进阶系列教程-拿捏Fiddler抓包教程(8)-Fiddler如何设置捕获会话

1.简介 前边几篇宏哥介绍了Fiddler界面内容以及作用。今天宏哥就讲解和分享如何设置Fiddler后&#xff0c;我们就可以捕获会话&#xff0c;进行抓包了。 2.捕获会话的设备 常见的捕获会话的设备分为PC&#xff08;电脑&#xff09;端和手机&#xff08;Android和IOS苹果&…

【SpringⅢ】Spring 的生命周期

目录 &#x1f96a;1 Bean 的作用域 &#x1f969;1.1 singleton&#xff1a;单例模式 &#x1f359;1.2 prototype&#xff1a;原型模式 &#x1f371;1.3 Bean 的其他作用域 &#x1f35c;2 Spring 生命周期(执行流程) &#x1f958;2.1 启动容器 &#x1f372; 2.2 读…

Elasticsearch:使用 ELSER 释放语义搜索的力量:Elastic Learned Sparse EncoderR

问题陈述 在信息过载的时代&#xff0c;根据上下文含义和用户意图而不是精确的关键字匹配来查找相关搜索结果已成为一项重大挑战。 传统的搜索引擎通常无法理解用户查询的语义上下文&#xff0c;从而导致相关性较低的结果。 解决方案&#xff1a;ELSER Elastic 通过其检索模型…

vue elementui table去掉滚动条与实现表格自动滚动且无滚动条

当table内容列过多时&#xff0c;可通过height属性设置table高度以固定table高度、固定表头&#xff0c;使table内容可以滚动。 现在需求是右侧滚动条不好看&#xff0c;需要去除滚动条&#xff0c;并隐藏滚动条所占列的位置。让他可以滚动但是不出现滚动条,不然即时隐藏了滚动…

Mybatis学习笔记

Mybatis 文章目录 Mybatis搭建环境创建Maven工程将数据库中的表转换为对应的实体类配置文件核心配置文件mybatis-config.xml创建Mapper接口映射文件xxxMapper.xmllog4j日志功能 Mybatis操纵数据库示例及要点说明获取参数的两种方式${}#{} 各种类型的参数处理单个字面量参数多个…

keil官网下载MDK的STM32芯片pack包

背景 最近重装了电脑系统&#xff0c;重新安装了MDK所以导致MDK芯片包需要重新下载&#xff0c;软件内下载又太慢&#xff0c;所以趁现在找到了官网下载方法把方法分享出来供大家参考。 1、在浏览器中输入网址&#xff1a;www.keil.arm.com进入如下界面&#xff0c;然后点击&am…

Mock-MOCO使用过程

一、jar包下载&#xff1a;https://github.com/dreamhead/moco 二、准备mock的json文件 data.json内容&#xff1a; ####GET请求 [{"description": "response使用Content-Type为charsetGBK编码格式来查看返回信息为中文的内容","request": {&q…

Tensorflow预训练模型ckpt与pb两种文件类型的介绍

我们在 Tensorflow无人车使用移动端的SSD(单发多框检测)来识别物体及Graph的认识 熟悉了Graph计算图以及在 Tensorflow2.0中function(是1.0版本的Graph的推荐替代)的相关知识介绍 这个tf.function的用法&#xff0c;了解到控制流与计算图的各自作用&#xff0c;无论使用哪种方…

Linux基本指令操作

登陆指令&#xff08;云服务器版&#xff09; 当我们获取公网IP地址后&#xff0c;我们就可以打开xshell。 此时会有这样的界面&#xff0c;我们若是想的登陆&#xff0c;则需要输入以下的指令 ssh 用户名公网IP地址 然后会跳出以下的窗口 接着输入密码——密码便是先前定好…

利用小波包对一维信号进行降噪或压缩(MATLAB)

function [ output_args ] example4_12( input_args ) %EXAMPLE4_12 Summary of this function goes here % Detailed explanation goes here clc; clear; % 设置信噪比和随机数的初始值 snr 3; init 2055615866; % 生成一个原始信号xref和含高斯白噪声的信号x [xref,x] …

微服务契约测试框架-Pact

契约测试 契约测试的思想就是将原本的 Consumer 与 Provider 间同步的集成测试&#xff0c;通过契约进行解耦&#xff0c;变成 Consumer 与 Provider 端两个各自独立的、异步的单元测试。 契约测试的优点&#xff1a; 契约测试与单元测试以及其它测试之间没有重复&#xff0c…

零的奇幻漂移:解密数组中的神秘消失与重生

本篇博客会讲解力扣“283. 移动零”的解题思路&#xff0c;这是题目链接。 思路1 这道题目很有意思。虽然是简单题&#xff0c;其蕴含的玄机还是很多的。正常来讲&#xff0c;这种题目一般都会原地操作&#xff08;不开辟额外的数组&#xff0c;空间复杂度是O(1)&#xff09;&…

计算机组成原理(2)- 浮点数的存储

1、浮点数的表示方法 假设有以下小数&#xff0c;它表示的十进制数是多少呢&#xff1f; 00000000 00000000 00000000 1010.10101*2^3 1*2^1 1*2^-1 1*2^-3 10.625 1010.1010可以用科学计数法来表示为1.0101010 * 2^3。关于科学计数法再举个例子0.10101用科学计数法表示…

uni-app:模态框的实现(弹窗实现)

效果图 代码 标签 <template><view><!-- 按钮用于触发模态框的显示 --><button click"showModal true">显示模态框</button><!-- 模态框组件 --><view class"modal" v-if"showModal"><view cla…

网红项目AutoGPT源码内幕及综合案例实战(三)

AutoGPT on LangChain PromptGenerator等源码解析 本节阅读AutoGPT 的prompt_generator.py源代码,其中定义了一个PromptGenerator类和一个get_prompt函数,用于生成一个提示词信息。PromptGenerator类提供了添加约束、命令、资源和性能评估等内容的方法,_generate_numbered_l…

线性表之顺序表

在计算机科学中&#xff0c;数据结构是非常重要的基础知识之一。数据结构为我们提供了组织和管理数据的方法和技巧&#xff0c;使得我们可以高效地存储、检索和操作数据。而顺序表作为数据结构中最基本、最常用的一种存储结构&#xff0c;也是我们学习数据结构的第一步。 本文将…

QT: 完成服务器的实现

1> 思维导图 2> 手动完成服务器的实现&#xff0c;并具体程序要注释清楚 Widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTcpServer> //服务器类 #include <QTcpSocket> //客户端类 #include <QMessageBox> //…