0
点赞
收藏
分享

微信扫一扫

【数据挖掘】将NLP技术引入到股市分析

快乐小鱼儿_9911 2023-07-25 阅读 74

文章目录


前言

适配器(Adapter)

作为stl六大组件之一,适配器也是stl中重要的一部分,那么,适配器是什么呢?

适配器模式的设计模式的出现,为开发带来了极大的便利,提供了一个极好的代码复用的手段,在stl中,适配器主要分为三类:容器适配器,迭代器适配器,仿函数适配器,本篇博客将简单的介绍容器适配器迭代器适配器

容器适配器

应用于容器,容器适配器包括:stack,queue,priority_queue
我们就拿stack和queue来举例,首先我们可以先看看c++文档中对这两个适配器的声明
在这里插入图片描述
在这里插入图片描述

这两个适配器容器相对于普通容器来说最大的区别就是用了第二个模板参数,而这个模板参数的默认参数是deque容器,也就是说这两个容器是在模板提供的容器的前提下进行的设计,也就是说传入什么容器就会生成底层是什么容器的栈和队列,如下:

#include<stack>
using namespace std;
int main()
{
	//默认生成用deque设立的栈
	stack<int> st1;
	//生成底层为vector的栈
	stack<int, vector<int>> st2;
	return 0;
}

那么具体是怎么实现的呢,可以看下面模拟实现的代码:

//模拟实现stl_queue

#pragma once
#include<deque>

namespace lzz
{
	template<typename T, typename container = deque<T>>
	class queue
	{
	private:
		container _con;
	public:
		queue() {}
		void push(const T& val) { _con.push_back(val); }
		void pop() { _con.pop_front(); }
		T& back() { return _con.back(); }
		const T& back() const { return _con.back(); }
		T& front() { return _con.front(); }
		const T& front() const { return _con.front(); }
		size_t size() const { return _con.size(); }
		bool empty() const { return _con.empty(); }
	};
}

///
//模拟实现stl_stack
#pragma once
#include<deque>

namespace lzz
{
	template<typename T, typename container = std::deque<T>>
	class stack
	{
	private:
		container _con;
	public:
		//自定义类型自动调用构造和析构
		stack() {}
		void push(const T& val) { _con.push_back(val); }
		void pop() {_con.pop_back(); }
		T& top() { return _con.back(); }
		size_t size() { return _con.size(); }
		bool empty() { return _con.empty(); }
	};
}

通过模拟实现,我们就可以发现其实容器适配器就是利用stl的容器接口再次进行上层封装得来的,通过上层封装能够做到忽略一些底层的细节,实现代码复用。

迭代器适配器——reverse_iterator

reverse_iterator,故名思意就是反向迭代器,大家仔细了解就能够知道,反向迭代器的++就是正向迭代器的–,反向迭代器的–就是正向迭代器的++,因此反向迭代器的实现可以借助正向迭代器,即使用适配器模式进行设计,即:反向迭代器内部都可以包含一个正向迭代器,对正向迭代器的接口进行包装即可。

首先,我们先来分析一下如何设计reverse_iteratorconst_reverse_iterator,需要写两份代码吗?首先我们来回顾一下iteratorconst_iterator是如何设计的:

template<typename T, typename Ref, typename Ptr>
struct __list_iterator
{
	//...
}

是通过传三个参数来进行控制的,所以在设计reverse_iterator时,我们也可以采取这种方式,下面是reverse_iterator的整体框架:

	template<typename Iterator, typename Ref, typename Ptr>
	class Reverse_iterator
	{
	//...
	}
	//通过如此设计反向迭代器,所有容器的反向迭代器都可以通过传入对应正向迭代器并进行typedef实现
	//list
	typedef Reverse_iterator<__list_iterator, T&, T*> reverse_iterator
	typedef Reverse_iterator<__const_list_iterator, T&, T*> const_reverse_iterator
	//
	//vector
	typedef Reverse_iterator<__vector_iterator, T&, T*> reverse_iterator
	typedef Reverse_iterator<__const_vector_iterator, T&, T*> const_reverse_iterator

具体逻辑

stl在设计反向迭代器时,采用了镜像对称的方式进行设计,也就时说,rbegin()指向的地方就是end()指向的地方,rend()指向的地方就是begin()指向的地方。

在这里插入图片描述
但是这也出现了一个问题,如果解引用,由于镜像对称的原因如果按照正常的解引用操作拿到的数据是错误的,需要拿到前一个迭代器指向的数据才能正确对应关系,所以reverse_iterator的operator*()和operator->()函数需要重新设计,如下:

		//其中先构造一个tmp的原因是不能直接修改_it,而要获得前一个数据只能先创建一个临时变量
		Ref& operator*() 
		{
			Iterator tmp(_it);
			return *--tmp;
		}
		Ptr operator->()
		{
			Iterator tmp(_it);
			--tmp;
			return &(tmp.operator*());
		}	

接着对反向迭代器进行++就是–,对正向迭代器进行–就是++,具体逻辑就是这样了。

完整代码

#pragma once

namespace lzz
{
	template<typename Iterator, typename Ref, typename Ptr>
	class Reverse_iterator
	{
	private:
		Iterator _it;
		typedef Reverse_iterator<Iterator, Ref, Ptr> self;
	public:
		Reverse_iterator() {}
		Reverse_iterator(const Iterator& it) { _it = it; }
		//由于使用了镜像对称,所以应该是返回他的上一个数据
		Ref& operator*() 
		{
			Iterator tmp(_it);
			return *--tmp;
		}
		Ptr operator->()
		{
			Iterator tmp(_it);
			--tmp;
			return &(tmp.operator*());
		}
		self& operator++()
		{
			--_it;
			return *this;
		}
		self& operator--()
		{
			++_it;
			return *this;
		}
		bool operator!=(const self& rit) { return _it != rit._it; }
	};
}

总结

举报

相关推荐

0 条评论