首页 > 其他分享 >熟悉使用list

熟悉使用list

时间:2024-03-17 22:29:06浏览次数:24  
标签:head const iterator list next 熟悉 使用 return

list的介绍

1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。

2. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向 其前一个元素和后一个元素。

3. list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高 效。

4. 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率 更好。

5. 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list 的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间 开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这 可能是一个重要的因素)

list的构造

构造函数

list (size_type n, const value_type& val = value_type())        构造的list中包含n个值为val的元素

ist()                                                                                         构造空的list

list (const list& x)                                                                    拷贝构造函数

list (InputIterator first, InputIterator last)                                 用[first, last)区间中的元素构造list

//list的构造
void TestList1()
{
    list<int> l1;                         // 构造空的l1
    list<int> l2(4, 100);                 // l2中放4个值为100的元素
    list<int> l3(l2.begin(), l2.end());  // 用l2的[begin(), end())左闭右开的区间构造l3
    list<int> l4(l3);                    // 用l3拷贝构造l4

    // 以数组为迭代器区间构造l5
    int array[] = { 16,2,77,29 };
    list<int> l5(array, array + sizeof(array) / sizeof(int));

    // 列表格式初始化C++11
    list<int> l6{ 1,2,3,4,5 };
}

list iterator的使用

begin + end                返回第一个元素的迭代器+返回最后一个元素下一个位置的迭代器

rbegin + rend             返回第一个元素的reverse_iterator,即end位置,返回最后一个元素下一个位                                    置的 reverse_iterator,即begin位置

	list<int> lt{ 1,2,3,4,5 };
	// 用迭代器方式打印lt中的元素
	list<int>::iterator it = lt.begin();
	while (it != lt.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;

运行结果如下

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

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

front                  返回list的第一个节点中值的引用

back                  返回list的最后一个节点中值的引用

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中的有效元素

void PrintList(list<int>& l)
{

	for (list<int>::iterator it = l.begin(); it != l.end(); ++it)
	{
		cout << *it << " ";
	}
	cout << endl;
}
// list插入和删除
// push_back/pop_back/push_front/pop_front
void TestList2()
{
	list<int> L{ 1,2,3 };

	// 在list的尾部插入4,头部插入0
	L.push_back(4);
	L.push_front(0);
	PrintList(L);

	// 删除list尾部节点和头部节点
	L.pop_back();
	L.pop_front();
	PrintList(L);
}

运行结果如下

// insert /erase 
void TestList3()
{
	list<int> L{ 1, 2, 3 };

	// 获取链表中第二个节点
	auto pos = ++L.begin();
	cout << *pos << endl;

	// 在pos前插入值为4的元素
	L.insert(pos, 4);
	PrintList(L);

	// 在pos前插入5个值为5的元素
	L.insert(pos, 5, 5);
	PrintList(L);

	// 在pos前插入[v.begin(), v.end)区间中的元素
	vector<int> v{ 7, 8, 9 };
	L.insert(pos, v.begin(), v.end());
	PrintList(L);

	// 删除pos位置上的元素
	L.erase(pos);
	PrintList(L);

	// 删除list中[begin, end)区间中的元素,即删除list中的所有元素
	L.erase(L.begin(), L.end());
	PrintList(L);
}

运行结果如下

list的迭代器失效

迭代器失效即迭代器所指向的节点的无效,即该节 点被删除了。因为list的底层结构为带头结点的双向循环链表,因此在list中进行插入时是不会导致list的迭代 器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响。

void TestListIterator1()
{
	list<int> l{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
	auto it = l.begin();
	while (it != l.end())
	{
		// erase()函数执行后,it所指向的节点已被删除,因此it无效,在下一次使用it时,必须先给其赋值
		l.erase(it);
		++it;
	}
}

运行结果如下

// 改正
void TestListIterator()
{
 int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
 list<int> l(array, array+sizeof(array)/sizeof(array[0]));
 auto it = l.begin();
 while (it != l.end())
 {
 l.erase(it++); // it = l.erase(it);
 }
}

 list与vector的对比

vector与list都是STL中非常重要的序列式容器,由于两个容器的底层结构不同,导致其特性以及应用场景不 同,其主要不同如下:

模拟实现一个list

template<class T>
	struct ListNode
	{
		ListNode(const T& val = T())
			: _prev(nullptr)
			, _next(nullptr)
			, _val(val)
		{}

		ListNode<T>* _prev;
		ListNode<T>* _next;
		T _val;
	};

	template<class T, class Ref, class Ptr>
	class ListIterator
	{
		typedef ListNode<T> Node;
		typedef ListIterator<T, Ref, Ptr> Self;

	public:
		typedef Ref Ref;
		typedef Ptr Ptr;
	public:
		//
		// 构造
		ListIterator(Node* node = nullptr)
			: _node(node)
		{}

		//
		// 具有指针类似行为
		Ref operator*() 
		{ 
			return _node->_val;
		}

		Ptr operator->() 
		{ 
			return &(operator*()); 
		}

		//
		// 迭代器支持移动
		Self& operator++()
		{
			_node = _node->_next;
			return *this;
		}

		Self operator++(int)
		{
			Self temp(*this);
			_node = _node->_next;
			return temp;
		}

		Self& operator--()
		{
			_node = _node->_prev;
			return *this;
		}

		Self operator--(int)
		{
			Self temp(*this);
			_node = _node->_prev;
			return temp;
		}

		//
		// 迭代器支持比较
		bool operator!=(const Self& l)const
		{ 
			return _node != l._node;
		}

		bool operator==(const Self& l)const
		{ 
			return _node != l._node;
		}

		Node* _node;
	};

	template<class T>
	class list
	{
		typedef ListNode<T> Node;

	public:
		// 正向迭代器
		typedef ListIterator<T, T&, T*> iterator;
		typedef ListIterator<T, const T&, const T&> const_iterator;

	public:
		///
		// List的构造
		list()
		{
			CreateHead();
		}

		list(int n, const T& value = T())
		{
			CreateHead();
			for (int i = 0; i < n; ++i)
				push_back(value);
		}

		template <class Iterator>
		list(Iterator first, Iterator last)
		{
			CreateHead();
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}

		list(const list<T>& l)
		{
			CreateHead();

			// 用l中的元素构造临时的temp,然后与当前对象交换
			list<T> temp(l.begin(), l.end());
			this->swap(temp);
		}

		list<T>& operator=(list<T> l)
		{
			this->swap(l);
			return *this;
		}

		~list()
		{
			clear();
			delete _head;
			_head = nullptr;
		}

		///
		// List的迭代器
		iterator begin() 
		{ 
			return iterator(_head->_next); 
		}

		iterator end() 
		{ 
			return iterator(_head); 
		}

		const_iterator begin()const 
		{ 
			return const_iterator(_head->_next); 
		}

		const_iterator end()const
		{ 
			return const_iterator(_head); 
		}

		reverse_iterator rbegin()
		{
			return reverse_iterator(end());
		}

		reverse_iterator rend()
		{
			return reverse_iterator(begin());
		}

		const_reverse_iterator rbegin()const
		{
			return const_reverse_iterator(end());
		}

		const_reverse_iterator rend()const
		{
			return const_reverse_iterator(begin());
		}

		///
		// List的容量相关
		size_t size()const
		{
			Node* cur = _head->_next;
			size_t count = 0;
			while (cur != _head)
			{
				count++;
				cur = cur->_next;
			}

			return count;
		}

		bool empty()const
		{
			return _head->_next == _head;
		}

		void resize(size_t newsize, const T& data = T())
		{
			size_t oldsize = size();
			if (newsize <= oldsize)
			{
				// 有效元素个数减少到newsize
				while (newsize < oldsize)
				{
					pop_back();
					oldsize--;
				}
			}
			else
			{
				while (oldsize < newsize)
				{
					push_back(data);
					oldsize++;
				}
			}
		}
		
		// List的元素访问操作
		// 注意:List不支持operator[]
		T& front()
		{
			return _head->_next->_val;
		}

		const T& front()const
		{
			return _head->_next->_val;
		}

		T& back()
		{
			return _head->_prev->_val;
		}

		const T& back()const
		{
			return _head->_prev->_val;
		}

		
		// List的插入和删除
		void push_back(const T& val) 
		{ 
			insert(end(), val); 
		}

		void pop_back() 
		{ 
			erase(--end()); 
		}

		void push_front(const T& val) 
		{ 
			insert(begin(), val); 
		}

		void pop_front() 
		{ 
			erase(begin()); 
		}

		// 在pos位置前插入值为val的节点
		iterator insert(iterator pos, const T& val)
		{
			Node* pNewNode = new Node(val);
			Node* pCur = pos._node;
			// 先将新节点插入
			pNewNode->_prev = pCur->_prev;
			pNewNode->_next = pCur;
			pNewNode->_prev->_next = pNewNode;
			pCur->_prev = pNewNode;
			return iterator(pNewNode);
		}

		// 删除pos位置的节点,返回该节点的下一个位置
		iterator erase(iterator pos)
		{
			// 找到待删除的节点
			Node* pDel = pos._node;
			Node* pRet = pDel->_next;

			// 将该节点从链表中拆下来并删除
			pDel->_prev->_next = pDel->_next;
			pDel->_next->_prev = pDel->_prev;
			delete pDel;

			return iterator(pRet);
		}

		void clear()
		{
			Node* cur = _head->_next;
			
			// 采用头删除删除
			while (cur != _head)
			{
				_head->_next = cur->_next;
				delete cur;
				cur = _head->_next;
			}

			_head->_next = _head->_prev = _head;
		}

		void swap(bite::list<T>& l)
		{
			std::swap(_head, l._head);
		}

	private:
		void CreateHead()
		{
			_head = new Node;
			_head->_prev = _head;
			_head->_next = _head;
		}
	private:
		Node* _head;
	};

标签:head,const,iterator,list,next,熟悉,使用,return
From: https://blog.csdn.net/xybbbb/article/details/136773710

相关文章

  • 在IDEA中使用Gradle存在的显示乱码问题
    项目使用Gradle进行依赖管理,当代码中存在错误时,运行程序时Build界面将报错(这是正常的),但是在报错结果中显示乱码信息,如下所示:解决办法:给IDEA添加JVM参数:-Dfile.encoding=UTF-8,然后重启IDEA即可。参数修改路径:Help->EditCustomVMOptions...【参考】如何修复IDEA使用Gr......
  • 如何不中断连接保持linux服务器持续运行 —— screen 使用介绍
     请参考ck'sblog以获取最佳观感在linux服务器上跑模型的时候,有时会在终端会话中持续了一段时间后超时断开,或者因为意外情况断网,如果正常在命令行终端执行程序时,此时会中断程序的进行,这很恼火,这就意味着要让程序持续运行,就必须得保持主机和服务器的连接,程序跑一晚上,主机就......
  • linux libc.so.6软链接错误 导致ls等基础命令无法使用,系统无法登录
    转:linuxlibc.so.6软链接错误导致ls等基础命令无法使用_error:/lib64/libpthread.so.0:symbol__libc_dl_er-CSDN博客目录 一、背景说明二、处置步骤1、故障状态2、通过ls命令tab补全键查看文件列表3、查看glibc版本4、重建libc.so.6的软链接5、ssh远程连接报错6、......
  • STL容器之list类
    文章目录STL容器之list类1、list的介绍2、list的使用2.1、list的常见构造2.2、list的iterator的使用2.3、list空间增长问题2.4、list的增删查改2.5、list迭代器失效问题3、list的模拟实现(含反向迭代器)STL容器之list类1、list的介绍list是序列容器,允许在序列中......
  • 实验一 c语言开发环境使用和数据类型、运算符、表达式
    task1`#include<stdio.h>include<stdlib.h>intmain(){printf("o\to\n");printf("<H>\t<H>\n");printf("II\tII\n");system("pause:");return0;}`task2`#include......
  • 实验1 C语言开发环境使用和数据类型、运算符、表达式
    点击查看代码#include<stdio.h>#include<stdlib.h>intmain(){ printf("oo\n"); printf("<H><H>\n"); printf("IIII\n"); system("pause"); return0;}点击查看代码#include<stdio......
  • 【Python/Numpy】list/tuple/dictionary/numpy 的操作
    CommonDataStructuresListsListsaremutablearrays.普通操作#Twowaystocreateanemptylistempty_list=[]empty_list=list()#Createalistthatcontainsdifferentdatatypes,thisisallowedinPythonmylist=["aa","bb",1,2......
  • 3-4-帮助命令使用
    3-4帮助命令使用方法一:man命令按q退出 方法二:命令-help 3-5开关机命令及7个启动级别常用的几个关机,重启命令shutdowninitrebootpoweroff3.5.1关机命令之-----shutdown作......
  • vector的使用
    前言前两期我们对STL和string的使用进行了介绍并对string进行了模拟实现!本期我们接着来对STL的vector进行学习!本期内容介绍什么是vector?vector常用的接口什么是vector?通过官方文档可以很清楚的看到,vector是一个可变长的顺序表!这就意味着它可以支持扩容等一系列操作!......
  • 使用linux三剑客取ip地址
    1,使用awk命令ifconfigens33(先试用ifconfig来查看IP地址在几行几列或者使用ip-a也可以)可以看到IP地址在第二列第二行,接下来使用awk命令来取出IP地址ifconfigens33|awk'{print$2}'|awk'NR==2{print$0}'(print$2打印出第二列)(print$0打印出一整行内容)(NR等......