STL--list

一、list介绍

列表是序列容器,允许在序列内的任何位置执行恒定时间插入和擦除操作,以及双向迭代

列表容器作为双向链表实现;双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个和后一个元素

它们与forward_list非常相似:主要区别在于forward_list对象是单链表,因此它们只能向前迭代,从而更简单高效

与其他基本标准序列容器(array、vector和 deque)相比,list在任意位置进行插入、移除元素的执行效率更高

与其他序列容器相比,list和 forward_lists 的主要缺点是不支持任意位置的随机访问。例如,要访问列表中的第六个元素,必须从已知位置(如开始或结束)迭代到该位置,这需要这些元素之间的距离的线性时间。它们还会消耗一些额外的内存来保持与每个元素关联的链接信息(这也许是影响存储小数据的大list的因素)

优点缺点
任意位置高效插入删除不能支持随机访问

二、list接口

详情可见

list - C++ Reference (cplusplus.com)https://legacy.cplusplus.com/reference/list/list/

1.常见构造

函数名称功能说明
list (size_type n, const value_type& val = value_type())构造的list中包含n个值为val的元素
list()构造空的list
list (const list& x拷贝构造函数
list (InputIterator first, InputIterator last)用[first, last)区间中的元素构造list

2.容量操作

函数名称接口说明
empty

检测list是否为空,是返回true,否则返回false

size返回list中有效节点的个数

3.访问与遍历

函数名称接口说明
begin+end返回第一个元素的迭代器+返回最后一个元素下一个位置的迭代器
rbegin+rend返回第一个元素的reverse_iterator,即end位置。返回最后一个元素下一个位置的reverse_iterator,即begin位置
front返回list的第一个节点中值的引用
back返回list的最后一个节点中值的引用

begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动

rbegin与rend为反向迭代器,对迭代器执行++操作,迭代器向前移动

4.修改操作

函数名称接口说明
push_front在list首元素钱插入值为val的元素
pop_front删除list中的第一个元素
push_back在list尾部插入值为val的元素
pop_back删除list最后一个元素
insert在list position位置中插入值为val的元素
erase删除list position位置的元素
swap交换两个list中的元素
clear清空list中的有效元素

5.list迭代器失效

三、list模拟实现

迭代器实现

		iterator begin() { return iterator(_head->_next); }//匿名构造迭代器对象
		iterator begin()const { return iterator(_head->_next); }

返回值返回一个匿名对象构造的迭代器对象

为什么const还可以构造普通迭代器?

因为const修饰*this,也就是一个指针,指针本身不可以改变,但是可以对齐指针指向的内容修改。也就是_head本身不可以改变,但是_head指向的next可以改变

对于常量迭代器对象,可以采用重新实现普通迭代的方式,但是这种方式过于繁琐,并且与普通迭代器的事项方式基本相同,因此采用类模板多个参数的处理方式

//常量迭代器类
	template<class T>
	struct __list_const_iterator
	{
		typedef list_node<T> node;
		typedef __list_const_iterator<T> self;//类对象本身
		node* _node;

		__list_const_iterator(node* n)//迭代器初始化
			:_node(n)
		{}

		const T& operator* ()//不能修改数据
		{
			return _node->_data;
		}

		self& operator++()
		{
			_node = _node->_next;
			return *this;
		}
		self& operator++(int)
		{
			self tmp(*this);
			_node = _node->_next;
			return tmp;
		}
		self& operator--()
		{
			_node = _node->_prev;
			return *this;
		}

		self& operator--(int)
		{
			self tmp(*this);
			_node = _node->_prev;
			return tmp;
		}
		bool operator!=(const self& li)
		{
			return _node != li._node;
		}
		bool operator==(const self& li)
		{
			return _node == li._node;
		}
	};

自定义类型处理

list中除了可以存储内置类型之外,还可以存放自定义类型数据,因此还需要对list的迭代器做自定义类型内容的处理

	struct test_A
	{
		int _a1;
		int _a2;
		test_A(int a1=0, int a2=0)
			:_a1(a1), _a2(a2)
		{}
	};

	void test_2()
	{
		list<test_A> lt;//指定内部为自定义类型
		lt.push_back(test_A(1, 1));
		lt.push_back(test_A(2, 2));
		lt.push_back(test_A(2, 2));

		list<test_A>::iterator it = lt.begin();
		while (it != lt.end())
		{
			cout << *it << " ";
			it++;
		}
		cout << endl;
	}

对于上图这样的一个简单自定义类型,如果仍然使用原来的迭代器输出方式,会产生报错

可将其改为

cout << (*it)._a1 << " ";

但是显然这样的输出方式并不符合一般的书写模式,一般情况下访问指针对象的成员并不会先解引用再读取成员。而是直接使用->的方式,因此需要重载->操作符

		T* operator->()//->运算符重载
		{
			return &_node->data
		}

//此时的调用为
    cout<<it->_a1<<" ";
//相当于it.operator->()->_a1,也就是(test_A*) ->_a1
//但是为了可读性编译器会自动省略一个箭头

insert操作

与vector不同,list的insert操作传入的是迭代器,并且不会出现迭代器失效的位置,因为迭代器的相对位置并没有改变,指向也不改变

#pragma once
#include<iostream>
#include<assert.h>
using std::cout;
using std::endl;
namespace my_list
{
	//节点类
	template<class T>
	struct list_node//默认访问权限是public,不对成员的访问限制
	{
		list_node<T>* _next;
		list_node<T>* _prev;
		T _data;

		list_node(const T& x=T())//匿名对象做缺省值,T需要默认构造
			:_next(nullptr), _data(x), _prev(nullptr)
		{
		}
	};

	//迭代器是原生指针或者是自定义类型
	//普通迭代器类
	template<class T,class Ref,class Ptr>
	//Ref与Ptr是为了适用常量迭代器,Ref=T&	Ptr=T*
	struct __list_iterator
	{
		typedef list_node<T> node;
		typedef __list_iterator<T,Ref,Ptr> self;//类对象本身
		node* _node;

		__list_iterator(node* n)//迭代器初始化
			:_node(n)
		{}

		Ref operator* ()
		//常量迭代器与普通迭代器只有返回值不同
		{
			return _node->_data;
		}
		Ptr operator->()
		{
			return &_node->_data;
		}

		self& operator++()//返回迭代器类对象
		{
			_node = _node->_next;
			return *this;
		}
		self& operator++(int)//int只用于标识后置++
		{
			self tmp(*this);
			_node = _node->_next;
			return tmp;
		}
		self& operator--()
		{
			_node = _node->_prev;
			return *this;
		}
		self& operator--(int)
		{
			self tmp(*this);
			_node = _node->_prev;
			return tmp;
		}
		bool operator!=(const self& li)
		{
			return _node != li._node;
		}
		bool operator==(const self& li)
		{
			return _node == li._node;
		}
	};


	//链表类
	template<class T>
	class list
	{
		typedef list_node<T> node;//节点
	public:
		typedef __list_iterator<T,T&,T*> iterator;//普通迭代器
		typedef __list_iterator<T, const T&,const T*> const_iterator;//常量迭代器
		//typedef __list_const_iterator<T> const_iterator;//常量迭代器
		void empty_init()
		{
			_head = new node;
			_head->_next = _head;
			_head->_prev = _head;
		}
		list()
		{
			empty_init();
		}
		template<class Iterator>
		list(Iterator first, Iterator last)
		{
			empty_init();//空初始化
			while (first != last)
			{
				push_back(*first);
				first++;
			}
		}
		void swap(list<T>& tmp)//套用std库中的swap方便实现拷贝
		{
			std::swap(_head, tmp._head);
		}
		list(const list<T>& cst)//拷贝构造
		{
			empty_init();
			list<T> tmp(cst.begin(), cst.end());
			swap(tmp);
		}
		list<T>& operator=(list<T> lt)//赋值构造
		//如果引用传参会导致拷贝
		{
			swap(lt);
			return *this;
		}
		~list()
		{
			clear();
			delete _head;
			_head = nullptr;
		}



		//迭代器
		iterator begin() { return iterator(_head->_next); }//匿名构造迭代器对象
		const_iterator begin()const { return const_iterator(_head->_next); }
		iterator end() { return iterator(_head); }
		const_iterator end()const { return const_iterator(_head); }



		//增删查改
		void push_back(const T& x)
		{
			node* tail = _head->_prev;
			node* newnode = new node(x);
			tail->_next = newnode;
			newnode->_prev = tail;
			newnode->_next = _head;
			_head->_prev = newnode;
			newnode->_data = x;
		}
		//void push_back(const T& x)
		//{
		//	insert(end(), x);
		//}
		void push_front(const T& x)
		{
			insert(begin(), x);
		}
		void pop_back()
		{
			erase(--end());
		}
		void insert(iterator pos,const T& x)
		{
			node* cur = pos._node;
			node* prev = cur->_prev;

			node* new_node = new node();

			prev->_next = new_node;
			new_node->_prev = prev;
			new_node->_next = cur;
			cur->_prev = new_node;
			new_node->_data = x;
		}

		iterator erase(iterator pos)
		{
			assert(pos != end());
			node* prev = pos._node->_prev;
			node* next = pos._node->_next;

			prev->_next = next;
			next->_prev = prev;
			delete pos._node;

			return iterator(next);
		}
		void clear()
		{
			iterator it = begin();
			while (it != end())
			{
				it=erase(it);
			}
		}
	private:
		node* _head;//哨兵位,不含数据
	};




	template<typename T>
	void show(const list<T>& ls)
	{
		//auto it = ls.begin();
		//while (it != ls.end())
		//{
		//	cout << *it << " ";
		//	++it;
		//}
		//cout << endl;
		for (auto ch : ls)
		{
			cout << ch << " ";
		}
		cout << endl;
	}


	void test_1()
	{
		list<int> l1;
		l1.push_back(1);
		l1.push_back(2);
		l1.push_back(3);
		l1.push_back(4);
		show(l1);

		const list<int> lt1;
		//const对象在定义的时候是不具有const属性的,否则无法进行初始化

		list<int> l2;
		l2 = l1;
		show(l2);

		list<int> l3 = l1;
		show(l3);
	}



	struct test_A
	{
		int _a1;
		int _a2;
		test_A(int a1=0, int a2=0)
			:_a1(a1), _a2(a2)
		{}
	};


	void test_2()
	{
		list<test_A> lt;//指定内部为自定义类型
		lt.push_back(test_A(1, 1));
		lt.push_back(test_A(2, 2));
		lt.push_back(test_A(3, 3));

		list<test_A>::iterator it = lt.begin();
		while (it != lt.end())
		{
			//cout << (*it)._a1 << " ";
			cout << it->_a1 << " " << it->_a2 <<endl;
			it++;
		}
		cout << endl;
	}

	void test_3()
	{
		list<test_A> lt;
		lt.push_back(test_A(1, 1));
		lt.push_back(test_A(2, 2));
		lt.push_back(test_A(3, 3));

		lt.insert(lt.begin(), test_A(5,5));
		list<test_A>::iterator it_2 = lt.begin();
		while (it_2 != lt.end())
		{
			//cout << (*it)._a1 << " ";
			cout << it_2->_a1 << " " << it_2->_a2 << endl;
			it_2++;
		}
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
STL分解-LSTM是一种深度学习模型,它结合了STL(Seasonal and Trend decomposition using Loess)分解和LSTM(Long Short-Term Memory)模型的特点。在这种方法中,首先使用STL分解将时间序列数据分解为趋势、季节性和残差三个部分。然后,将分解后的趋势和季节性数据作为LSTM模型的输入,用于预测未来的时间序列值。通过结合STL分解和LSTM模型,STL分解-LSTM模型可以更好地捕捉时间序列数据的长期依赖和季节性变化,从而提高预测准确性。引用中的图7展示了ISTL-LSTM模型和STL-LSTM模型的预测结果的比较,而引用中的图6展示了不同深度学习模型(包括ISTL-LSTM,STL-LSTM,LSTM和GRU)在不同超参数设置下的预测效果比较。另外,引用给出了STL分解-LSTM模型的超参数设置,其中包括隐藏层数、神经元数量、训练迭代次数、batch size、dropout率、激活函数、损失函数和优化器的选择。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [《一种改进的STL-LSTM模型:用于COVID-19疫情期间每日公交客流预测》](https://blog.csdn.net/zuiyishihefang/article/details/123320971)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值