STL -- vector 和 list

本文主讲C++ STL中的vector和list,介绍了部分接口函数,分析这连两个数据结构的优劣。
其实者两个就类似于之前C语言阶段的顺序表双向链表

vector

vector介绍

vector是表示可变大小数组的序列容器, 就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。

vector接口

vector capacity

函数功能
size()返回实际元素个数。
resize()改变实际元素的个数。
capacity()返回当前容量。
empty()判断容器中是否有元素,若无元素,则返回 true;反之,返回 false
reserve()修改容器的容量

list modifiers

函数功能
push_back()在序列的尾部添加一个元素。
pop_back()移出序列尾部的元素。
insert()在指定的位置插入一个或多个元素。
erase()移出一个元素或一段元素。
clear()移出所有的元素,容器大小变为 0
swap()交换两个容器的所有元素。
operator[ ]重载了 [ ]运算符,可以向访问数组中元素那样,通过下标即可访问甚至修改 vector 容器中的元素。

vector iterator

函数功能
begin()返回指向容器中第一个元素的迭代器。
end()返回指向容器最后一个元素所在位置后一个位置的迭代器,通常和 begin() 结合使用。
rbegin()返回指向最后一个元素的迭代器。
rend()返回指向第一个元素所在位置前一个位置的迭代器。

vector优劣

优:

  • 支持高效随机访问。

劣:

  • 空间不够需要增容,就可能导致频繁增容和空间浪费的问题
  • 头部和中部插入数据时效率较低(因为需要挪动数据)

vector实现

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


namespace hw
{
	using std::swap;
	template <class T>
	class vector
	{
	public:
		typedef T* iterator;
		typedef const T* const_iterator;

		vector()
			:_start(nullptr)
			, _finish(nullptr)
			, _endofstorage(nullptr)
		{}

		传统写法
		// //v2(v1)
		//vector(const vector<T>& v)
		//{
		//	_start = new T[v.capacity()];
		//	_finish = _start + v.size();
		//	_endofstorage = _start + v.capacity();

		//	memcpy(_start, v._start, v.size() * sizeof(T));

		//}

		//迭代器初始化
		//vector<int> v2(++v1.begin(), --v1.end());
		template <class InputIeterator>
		vector(InputIeterator first, InputIeterator last)
			:_start(nullptr)
			, _finish(nullptr)
			, _endofstorage(nullptr)
		{
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}

		void swap(vector<T>& v)
		{
			std::swap(_start, v._start);
			std::swap(_finish, v._finish);
			std::swap(_endofstorage, v._endofstorage);
		}

		//现代写法
		//v2(v1)
		vector(const vector<T>& v)
			:_start(nullptr)
			, _finish(nullptr)
			, _endofstorage(nullptr)
		{
			vector<T> tmp(v.begin(), v.end());

			swap(tmp);
		}

		//v1 = v2
		vector<T>& operator=(vector<T>& v)
		{
			swap(v);
			return *this;
		}

		~vector()
		{
			if (_start)
			{
				delete[] _start;
				_start = _finish = _endofstorage = nullptr;
			}
		}


		const_iterator begin() const
		{
			return _start;
		}

		const_iterator end() const
		{
			return _finish;
		}

		iterator begin()
		{
			return _start;
		}

		iterator end()
		{
			return _finish;
		}

		T& operator[](size_t i)
		{
			assert(i <= size());
			return _start[i];
		}

		size_t size() const
		{
			return _finish - _start;
		}

		size_t capacity() const
		{
			return _endofstorage - _start;
		}

		void reserve(size_t n)
		{
			if (n > capacity())
			{
				//扩容
				size_t sz = size();
				T* tmp = new T[n];
				if (_start)
				{
					//memcpy(tmp, _start, sizeof(T) * size());
					for (size_t i = 0; i < sz; i++)
					{
						//T是int没问题
						//T是string, 调用了T的深赋值拷贝
						tmp[i] = _start[i];
					}

					delete[] _start;
				}

				_start = tmp;
				_finish = _start + sz;
				_endofstorage = _start + n;
			}
		}
		//cosnt T& val = 0; 不合适(因为有些类型不适合),这里给的是 T()匿名对象 缺省
		//并且内置类型也是可以这样的,C++对内置类型进行升级,也可以使用构造函数
		//必须使用 const + 引用,并且 const + 引用 会延长匿名对象生命周期
		void resize(size_t n, const T& val = T()) 
		{									
			if (n < size())
			{
				_finish = _start + n;
			}
			else
			{
				if (n > capacity())
				{
					reserve(n);
				}
				while (_finish != _start + n)
				{
					*_finish = val;
					++_finish;
				}
			}
		}

		void push_back(const T& x)
		{
			if (_finish == _endofstorage)
			{
				
				//扩容
				reserve(capacity() == 0 ? 4 : capacity() * 2);
			}
			*_finish = x;
			++_finish;
		}

		iterator insert(iterator pos, const T& x)
		{
			assert(pos >= _start);
			assert(pos <= _finish);

			if (_finish == _endofstorage)
			{
				//扩容导致pos迭代器失效,扩容需要更新一下pos
				size_t len = pos - _start;
				reserve(capacity() == 0 ? 4 : capacity() * 2);
				pos = _start + len;
			}
			iterator end = _finish - 1;
			while (end >= pos)
			{
				*(end + 1) = *(end);
				--end;
			}
			*pos = x;
			++_finish;

			return pos;
		}

		iterator erase(iterator pos)
		{
			assert(pos >= _start);
			assert(pos < _finish);

			iterator begin = pos + 1;
			while (begin < _finish)
			{
				*(begin - 1) = *(begin);
				++begin;
			}
			--_finish;
			return pos;
		}

		void pop_back()
		{
			assert(_finish > _start);
			--_finish;
		}

			

private:
	iterator _start;
	iterator _finish;
	iterator _endofstorage;
	};

}

list

list介绍

STL list 容器,又称双向链表容器,即该容器的底层是以双向链表的形式实现的。这意味着,list 容器中的元素可以分散存储在内存空间里,而不是必须存储在一整块连续的内存空间中。
在这里插入图片描述

list接口

这里只展示常用的

list capacity

函数功能
empty()判断容器中是否有元素,若无元素,则返回 true;反之,返回 false。
size()返回当前容器实际包含的元素个数。
resize()调整容器的大小。

list element access

函数功能
front()返回第一个元素的引用。
back()返回最后一个元素的引用。

list modifiers

函数功能
push_front()在容器头部插入一个元素。
pop_front()删除容器头部的一个元素。
push_back()在容器尾部插入一个元素。
pop_back()删除容器尾部的一个元素。
insert()在容器中的指定位置插入元素。
erase()删除容器中一个或某区域内的元素。
swap()交换两个容器中的元素,必须保证这两个容器中存储的元素类型是相同的。
clear()删除容器存储的所有元素。

list Iterator

函数功能
begin()返回指向容器中第一个元素的双向迭代器。
end()返回指向容器中最后一个元素所在位置的下一个位置的双向迭代器。
rbegin()返回指向最后一个元素的反向双向迭代器。
rend()返回指向第一个元素所在位置前一个位置的反向双向迭代器。
cbegin()和 begin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。
cend()和 end() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。
crbegin()和 rbegin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。
crend()和 rend() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。

list优劣

优:

  • 按需申请空间
  • 支持任意位置 O(1) 插入,删除

劣:

  • 不支持随机读取,访问后面的元素需要用一个指针从前往后访问。

其实看完这两个数据结构的优劣,不难看出这其实是两个互补的数据结构。

实现迭代器时可能出现的问题

如果我们想要实现对其他复杂一点的自定义类型的访问,例如日期类Date

class Date
{
public:
	Date(int year = 1, int _month = 1, int day = 1)
	{}
private:
	int _year;
	int _month;
	int _day;
};

可能需要重载->
这样的运算符在我们访问可能就会这样it -> -> _year 使用了两次->
其实这里我们编译器有一些优化。
为了增强可读性,编译器帮我们省略了一个->,所以我们就只需要写一个
->

	void test_list2()
	{
		my_list<Date> lt;
		lt.push_back(Date(2022, 8, 12));
		lt.push_back(Date(2022, 7, 13));
		lt.push_back(Date(2022, 6, 14));

		my_list<Date>::iterator it = lt.begin();
		while (it != lt.end())
		{
			//cout << (*it)._year << "/" << (*it)._month << "/" << (*it)._day << endl;
			cout << it->_year << "/" << it->_month << "/" << it->_day << endl;

			++it;
		}
		cout << endl;
	}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

eptcup_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值