C++笔记归纳8:stack & queue

stack & queue

目录

[stack & queue](#stack & queue)

[一、stack & queue](#一、stack & queue)

二、Stack的模拟实现

三、Queue的模拟实现

四、相关试题

试题1:最小栈

试题2:栈的压入、弹出序列

试题3:二叉树的层序遍历

五、容器适配器

六、deque

七、优先级队列(priority_queue)

八、仿函数(函数对象)

九、与堆相关的算法


一、stack & queue

容器适配器(adaptor)

它们的底层容器为deque

用stack实现后进先出

用queue实现先进先出

二、Stack的模拟实现

cpp 复制代码
#pragma once
#include <deque>

//template<class T>
//class stack
//{
//private:
//	T* _a;
//	size_t _top;
//	size_t _capacity;
//};

namespace bit
{
	//用Container(适配器)适配转换出stack
	//template<class T,class Container>
	//可以给模板参数设置缺省值
	//template<class T, class Container = vector<T>>
	template<class T, class Container = deque<T>>
	class stack
	{
	public:
		//压栈
		void push(const T& x)
		{
			_con.push_back(x);
		}
		//出栈
		void pop()
		{
			_con.pop_back();
		}
		//获取栈顶数据
		const T& top() const
		{
			return _con.back();
		}
		//计算数据个数
		size_t size() const
		{
			return _con.size();
		}
		//判空
		bool empty() const
		{
			return _con.empty();
		}
	private:
		Container _con;
	};
}

三、Queue的模拟实现

cpp 复制代码
#pragma once
#include <deque>

namespace bit
{
	template<class T, class Container = deque<T>>
	class queue
	{
	public:
		//入队
		void push(const T& x)
		{
			_con.push_back(x);
		}
		//出队
		void pop()
		{
			_con.pop_front();
		}
		//获取队首数据
		const T& front() const
		{
			return _con.front();
		}
		//获取队尾数据
		const T& back() const
		{
			return _con.back();
		}
		//计算数据个数
		size_t size() const
		{
			return _con.size();
		}
		//判空
		bool empty() const
		{
			return _con.empty();
		}
	private:
		Container _con;
	};
}

四、相关试题

试题1:最小栈

题目内容:

设计一个支持push,pop,top操作,并且能在常数时间内检索到最小元素的栈

实现MinStack类

MinStack():初始化堆栈对象

void push(int val):将元素val推入堆栈

void pop():删除堆栈顶部的元素

int top():获取堆栈顶部元素

int getMin():获取堆栈中的最小元素

cpp 复制代码
class MinStack 
{
public:
    MinStack() 
    {
    }
    
    void push(int val) 
    {
        _st.push(val);
        if(_minst.empty() || val <= _minst.top())
        {
            _minst.push(val);
        }
    }
    
    void pop() 
    {
        if(_st.top() == _minst.top())
        {
            _minst.pop();
        }
        _st.pop();
    }
    
    int top() 
    {
        return _st.top();
    }
    
    int getMin() 
    {
        return _minst.top();
    }
private:
    stack<int> _st;
    stack<int> _minst;
};

试题2:栈的压入、弹出序列

题目内容:

输入两个整数序列,第一个序列表示栈的压入顺序

判断第二个序列是否可能为该栈的弹出顺序

假设压入栈的所有数字均不相等例如序列1,2,3,4,5是某栈的压入顺序

序列4,5,3,2,1是该压栈序列对应的一个弹出序列

但4,3,5,1,2就不可能是该压栈序列的弹出序列

示例1:

输入:[1,2,3,4,5],[4,5,3,2,1]

返回:true

示例2:

输入:[1,2,3,4,5],[4,3,5,1,2]

返回:false

cpp 复制代码
class Solution 
{
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param pushV int整型vector 
     * @param popV int整型vector 
     * @return bool布尔型
     */
    bool IsPopOrder(vector<int>& pushV, vector<int>& popV) 
    {
        size_t popi = 0;
        stack<int> st;
        for(auto&e : pushV)
        {
            //入栈
            st.push(e);
            //与出栈序列匹配
            while(!st.empty() && st.top() == popV[popi])
            {
                st.pop();
                popi++;
            }
        }
        return st.empty();
    }
};

试题3:二叉树的层序遍历

题目内容:

给你二叉树的根节点 root,返回其节点值的层序遍历

(即逐层地,从左到右访问所有节点)

示例:

输入:root = [3,9,10,null,null,15,7]

输出:[[3],[9,20],[15,7]]

cpp 复制代码
class Solution 
{
public:
    vector<vector<int>> levelOrder(TreeNode* root) 
    {
        vector<vector<int>> vv;
        queue<TreeNode*> q;
        //当前层的数据个数
        int levelSize = 0;
        if(root)
        {
            q.push(root);
            levelSize = 1;
        }
        while(!q.empty())
        {
            vector<int> v;
            //当前层数据个数,控制一层一层出
            while(levelSize--)
            {
                TreeNode* front = q.front();
                q.pop();
                v.push_back(front->val);
                if(front->left)
                {
                    q.push(front->left);
                }
                if(front->right)
                {
                    q.push(front->right);
                }
            }
            vv.push_back(v);
            //当前层出完,下一层都进队列,队列的个数就是下一层的数据个数
            levelSize = q.size();
        }
        return vv;
    }
};

五、容器适配器

**适配器:**一种设计模式(23种,包括迭代器模式)

设计模式:一套被反复使用的,多数人知晓的,进过分类编目的,代码设计经验的总结

**作用:**将一个类的接口转换成客户希望的另外一个接口

stack和queue这些依赖于vector,list实现的数据结构,它们的模板都需要有一个适配器

来进行选择,是用链式结构来存储数据,还是用顺序表结构来存储数据

六、deque

vector与list的缝合

vector

优点:

  • 尾插尾删效率高
  • 支持高效的下标随机访问(物理空间连续)
  • 高速缓存利用率高(物理空间连续)

缺点:

  • 空间不够需要扩容,造成空间浪费和数据拷贝
  • 头部与中间的插入删除效率低

list

优点:

  • 按需申请释放空间,不需要扩容
  • 任意位置的插入删除

缺点:

  • 不支持下标的随机访问

deque的结构图:

头插尾插效率高

既没有像链表频繁地申请空间

也没有像顺序表需要大量扩容

下标访问效率较好,但不如顺序表

中间插入删除效率低,需要挪动数据,时间复杂度为O(N)

七、优先级队列(priority_queue)

**底层结构:**堆(用vector作默认适配容器)

优先级队列的使用

**top:**默认大的值优先级高

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
#include <queue>

int main()
{
	//默认建大堆
	priority_queue<int, vector<int>> pq;
	//使用仿函数建小堆:priority_queue<int,vector<int>,greater<int>> pq;
	pq.push(4);
	pq.push(1);
	pq.push(5);
	pq.push(7);
	pq.push(9);
	while (!pq.empty())
	{
		cout << pq.top() << " ";
		pq.pop();
	}
	cout << endl;

	return 0;
}

模拟实现

cpp 复制代码
#pragma once
#include <vector>

namespace bit
{
    template<class T>
    class Less
    {
    public:
	    bool operator()(const T& x, const T& y)
	    {
		    return x < y;
	    }
    };

    template<class T>
    class Greater
    {
    public:
	    bool operator()(const T& x, const T& y)
	    {
		    return x > y;
	    }
    };
    
	template<class T, class Container = vector<T>,class Compare = Less<T>>
	class priority_queue
	{
	public:
		void AdjustUp(int child)
		{
			int parent = (child - 1) / 2;
			while (child > 0)
			{
				Compare com;
				if (com(_con[parent],_con[child]))
				{
					swap(_con[child], _con[parent]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}

		void AdjustDown(int parent)
		{
			int child = parent * 2 + 1;
			Compare com;
			while (child < _con.size())
			{
				if (child + 1 < _con.size() && com(_con[child],_con[child + 1]))
				{
					++child;
				}
				if (com(_con[parent], _con[child]))
				{
					swap(_con[child], _con[parent]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
				{
					break;
				}
			}
		}

		void push(const T& x)
		{
			_con.push_back(x);
			AdjustUp(_con.size() - 1);
		}

		void pop()
		{
			swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();
			AdjustDown(0);
		}

		const T& top()
		{
			return _con[0];
		}

		size_t size() const
		{
			return _con.size();
		}

		bool empty() const
		{
			return _con.empty();
		}
	private:
		Container _con;
	};
}

八、仿函数(函数对象)

本质是一个类

这个类重载了operator(),它的对象可以像函数一样调用

需要手动实现仿函数的情况:

  • 类类型不支持比较大小
  • 支持比较大小,但比较的逻辑不是你想要的
cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;

template<class T>
class Less
{
public:
	bool operator()(const T& x, const T& y)
	{
		return x < y;
	}
};

template<class T>
class Greater
{
public:
	bool operator()(const T& x, const T& y)
	{
		return x > y;
	}
};

//<:升序
//>:降序
template<class Compare>
void BubbleSort(int* a, int n, Compare com)
{
	for (int j = 0; j < n; j++)
	{
		int flag = 0;
		for (int i = 1; i < n - j; i++)
		{
			//if (a[i] < a[i - 1])
			if(com(a[i],a[i - 1]))
			{
				swap(a[i - 1], a[i]);
				flag = 1;
			}
		}
		if (flag == 0)
		{
			break;
		}
	}
}

int main()
{
	Less<int> LessFunc;//对象
	Greater<int> GreaterFunc;//对象
	//函数对象
	cout << LessFunc(1, 2) << endl;
	//本质
	cout << LessFunc.operator()(1,2) << endl;

	int a[] = { 9,1,2,5,7,4,6,3 };
	BubbleSort(a, 8, LessFunc);
	BubbleSort(a, 8, GreaterFunc);
	//除了传有名对象
	//也可以传匿名对象
	BubbleSort(a, 8, Less<int>());
	BubbleSort(a, 8, Greater<int>());
	return 0;
}

九、与堆相关的算法

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <algorithm>
using namespace std;

int main()
{
	int myints[] = { 10,20,30,5,15 };
	sort(myints, myints + 5);
	std::vector<int> v(myints, myints + 5);
	//判断是否是堆
	cout << is_heap(v.begin(), v.end()) << endl;
	//物理上连续,原生指针就是天然的迭代器
	cout << is_heap(myints, myints + 5) << endl;
	//默认建大堆
	make_heap(v.begin(), v.end());
	//判断是否是堆
	cout << is_heap(v.begin(), v.end()) << endl;
	//堆排序
	std::sort_heap(v.begin(), v.end());
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
	return 0;
}
相关推荐
sichuanwuyi2 小时前
wydevops——最佳应用场景解析
java·开发语言·云原生·云计算·paas·devops
晚枫歌F2 小时前
跳表Skip List以及实现代码C语言
c语言·开发语言
少控科技2 小时前
C#基础学习 - 中国民族编码资源代码
开发语言·c#
爱吃生蚝的于勒2 小时前
【Linux】网络基础(一)
linux·运维·服务器·网络·后端·算法·架构
24白菜头2 小时前
第十六届蓝桥杯C&C++大学B组
数据结构·c++·笔记·算法·职场和发展·蓝桥杯
小年糕是糕手2 小时前
【35天从0开始备战蓝桥杯 -- Day2】
开发语言·jvm·数据库·c++·程序人生·考研·蓝桥杯
小年糕是糕手2 小时前
【35天从0开始备战蓝桥杯 -- Day1】
jvm·数据结构·c++·程序人生·算法·职场和发展·蓝桥杯
Gold Steps.2 小时前
Go 语言核心:函数、结构体与接口深度解析
开发语言·后端·golang
日光倾2 小时前
【Vue.js 入门笔记】Webpack 入门
vue.js·笔记·webpack