2024年最新STL设计之容器适配器,加之经典题目解析_stl 适配器(1),「架构师必备

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

push 和 pop 函数关键分析

AdjustUp

AdjustDown

整体实现代码

priority_queue 适用地TopK问题分析

总结


前言

小杰地STL设计随笔会持续跟新, 之前已经跟新地有vector, list随笔. 附上链接在此, 感兴趣地可以阅读, 之后小杰也会持续根据自己所学输出好的作品,希望大家可以关注,交流,感谢,你的评论,阅读,点评都是对小杰地最大认可和支持

分块刨析从函数原型到分块实现C++STL(vector)_小杰312的博客-CSDN博客分块刨析从函数原型到分块实现C++STL(vector)外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传https://blog.csdn.net/weixin_53695360/article/details/123248476?spm=1001.2014.3001.5502STL设计之链表设计,分块分组件分析,迭代器设计思路_小杰312的博客-CSDN博客STL设计之链表设计,分块分组件分析,迭代器设计思路外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传https://blog.csdn.net/weixin_53695360/article/details/123647344?spm=1001.2014.3001.5502

stack + queue 容器适配器理解实现

=

  • 理解容器适配器

以某种已有地既定容器作为底层结构,在其地基础上进一步地进行封装接口函数。使其可以满足先进后出  (栈特性)  或者  先进先出  (队列特性)

上述这种具备以底层容器为基础,封装新的接口,形成另外一种特性地容器,这个往往不被叫做容器,而是称为  adapter (配接器)

正是如此,往往STL中地   stack  +  queue  不被归类为 container(容器) 而是 container adapter 容器配接器  (容器适配器)

  • 思考stack 和 queue 是否存在迭代器?

stack 和 queue 都不具备迭代器,   因为两者都不具备遍历走访功能,所以自然不需要设计迭代器

  • stack 和 queue可以以哪些容器作为底层容器?

使用 deque双端队列 + list 双向循环链表作为底层容器都是OK的   对于stack 使用 vector作为底层容器也是OK的

  • 底层容器如何传进去?

作为模板参数传入进去.   如下方式

  • 重点函数分块分析

  • stack分析

  • 这个stack 因为仅仅只是适配器,相当于是对于已有容器地接口基础上再进行地一层封装,因为是再封装,所以函数分析就仅仅浮于函数原型上,只要我们按照栈地特性去再封装就是      (注意:栈和队列抓地是特性,而不是实现, 栈,先进先出,子弹后上膛地先射出)
  • 所以我们仅仅在一个接口上进行   压入数据和弹出数据就可以满足栈地特性了,不论选择头部还是尾部都是可以地,此处用vector作为底层容器,所以我实用  back位置 进行元素地压入和弹出
namespace tyj {
	//template<class T, class Sequence = deque<T>>
	//template<class T, class Sequence = list<T>>
	template<class T, class Sequence = vector<T>>
	class stack {
	public:
		stack() {}//无参构造
		bool empty() const {
			return st.empty();
		}

		size_t size() {
			return st.size();
		}

		T& top() {
			return st.back();
		}

		void push(const T& val) {
			st.push_back(val);
		}

		void pop() {
			st.pop_back();
		}

	private:
		Sequence st;
	};
}
  • queue分析

  • queue 和 stack地道理是完全一样地,   只需要满足先入先出地特性即可,满足这种特性就是queue了,也就是在容器地一端出元素另外一端入元素.    这样地结构就是队列。
  • 针对队列需要两端进行操作,一端入元素,另外一端出元素,所以我们需要实用地是双端操作地容器作为底层容器, 可以是deque 也可以是 list 双端链表, 此处我们实用list作为底层容器进行进一步地封装接口
namespace tyj {
    template<class T, class Sequence = list<T>>
	class queue {
	public:
		queue() {} //无参构造
		bool empty() const {
			return q.empty();
		}

		size_t size() {
			return q.size();
		}

		T& front() {
			return q.front();
		}

		T& back() {
			return q.back();
		}

		void push(T& val) {
			q.push_back(val);
		}

		void pop() {
			q.pop_front();
		}
	private:
		Sequence q;
	};
}

stack 经典例题

剑指 Offer 31. 栈的压入、弹出序列

输入:pushed = [1,2,3,4,5], popped = [4,5,3,2,1]
输出:true
解释:我们可以按以下顺序执行:
push(1), push(2), push(3), push(4), pop() -> 4,
push(5), pop() -> 5, pop() -> 3, pop() -> 2, pop() -> 1

题目地含义就是给与一个   pushed 数组作为入栈顺序,   poped地数组是出栈顺序, 按照 入栈数组地入栈顺序  给与地出栈数组出栈序列是否是一个可能地结果

  • 思路描述: 对于这个可能地出栈序列问题,应该采取地是栈模拟地方式来处理,因为直接地去从整体思考解决这个问题是非常复杂和不好处理地,这个时候我们可以考虑地是将其按照入栈和出栈序列真正地放入到实际地栈中走一遍,模拟一下这个过程,看看这样地入栈序列是否可能产生如此地出栈序列
  • 首先pushI  是指向pushed数组地下标, popJ 是指向poped数组地下标
  • 我们不断地将pushI指向地元素压入st 栈中, 如果 出现了 st.top == poped[popJ]地时候, 说明了这个元素我们应该弹出
  • **我们不断地将pushed数组中地元素放入到st栈中,同时我们不断地对比st.top()元素是不是当前出栈元素,是我们就出栈,不是就继续入栈,直到整个入栈序列走完之后我们判断popJ 是否走到poped 数组地末尾即可,**走到末尾说明是一个合法地出栈序列,否则不是
class Solution {
public:
    bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
        stack<int> st;
        int pushI = 0, popJ = 0;
        for (pushI = 0; pushI < pushed.size(); ++pushI) {
            st.push(pushed[pushI]);
            while (popJ < popped.size() && !st.empty() && popped[popJ] == st.top()) {
                st.pop();
                ++popJ;
            }
        }
        return popJ == popped.size();                  
    }
};

上述题目地核心,我们实实在在地将序列元素放入一个实际地栈中去模拟整个过程,入栈过程中同时贪心地  尝试 对比  pop 栈顶元素,如果整个过程走完,popJ走到poped地末尾就是一个合法地出栈序列,否则就不是了.

150. 逆波兰表达式求值

**输入:tokens = ["2","1","+","3","\*"]
输出:9
解释:该算式转化为常见的中缀算术表达式为:((2 + 1) \* 3) = 9**

题目含义: 就是题目给与一个后缀表达式数组,然后我们需要将其转换为我们平常可见地中缀表达式求取中缀表达式答案

  • 后缀表达式  lhs左操作数   rhs右操作数   op操作符
  • 我们需要将其转换为   lhs op rhs 这种形式来处理
  • 所以我们在遍历地过程中需要先将  lhs push 到栈中,rhs 也 push 到栈中, 遇到 op就将两个栈顶元素弹出运算, 同时将运算结果 再 push 到栈中
  • 最终返回   st.top()   就是最终地ans
class Solution {
public:
    int evalRPN(vector<string>& s) {
        stack<int> st;
        int lhs, rhs;
        for (int i = 0; i < s.size(); ++i) {
          if (s[i] == "+") {
              rhs = st.top(); st.pop();
              lhs = st.top(); st.pop();
              st.push(lhs + rhs);
          } else if (s[i] == "-") {
              rhs = st.top(); st.pop();
              lhs = st.top(); st.pop();
              st.push(lhs - rhs);
          } else if (s[i] == "*") {
              rhs = st.top(); st.pop();
              lhs = st.top(); st.pop();
              st.push(lhs * rhs);
          } else if (s[i] == "/") {
              rhs = st.top(); st.pop();
              lhs = st.top(); st.pop();
              st.push(lhs / rhs);
          } else {
              st.push(stoi(s[i]));
          }
        }
        return st.top();
    }
};

priority_queue 分解实现

从数据结构地较入认识priority_queue
  • 先理解一下何为优先队列, 优先队列就是拥有权值地队列,按照权值大小进行存储,其实也就是我们C语言里面所接触到地  heap 堆数据结构.  优先队列《==》堆
  • 父节点地权值需要大于两个子结点

从STL组件地角度去看priority_queue
  • priority_queue本质上和queue一样还是一个容器适配器, 底层容器实用地是 vector

  • compare  是什么?  是仿函数,可调用对象,是一种比较规则:  可以理解为C语言里面地函数指针
push 和 pop 函数关键分析
  • 核心关键在于理解为啥要 上浮  和  下沉  (此处地例子为小顶堆)

  • push 元素到数组尾部,堆底层,可能影响整个堆结构地特性,需要调用AdjustUp向上调整算法,调整 插入元素到正确位置上去

  • pop 元素,pop 地是堆顶地元素,采取地方式是使用堆尾元素和堆顶元素swap, 然后进行pop_back() 弹出整个本应该在堆顶地元素, 然后堆顶元素更换会影响到整个堆结构地特性,使其不满足堆结构地特性要求,于是需要调用向下调整算法,将堆顶元素下称操作到应该地位置上去

  • 至此其实思路已经很清楚了,核心地关键在于什么? 在于AdjustUp 和 AdjustDown 向上和向下调整算法地书写

  • AdjustUp

  • AdjustDown

整体实现代码
namespace tyj {	
    template<class T>
	struct less
	{
		bool operator()(const T& l, const T& r)
		{

img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

T>

struct less
{
bool operator()(const T& l, const T& r)
{

[外链图片转存中…(img-AYpBZAKO-1715662388725)]
[外链图片转存中…(img-jMlctK8s-1715662388725)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

  • 21
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值