IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> list. -> 正文阅读

[数据结构与算法]list.

list的介绍及使用

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 iterator的使用

  1. 可暂时将迭代器理解成一个指针,该指针指向list中的某个节点。
  2. begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动
  3. rbegin(end)与rend(begin)为反向迭代器,对迭代器执行++操作,迭代器向前移动

list的迭代器失效

前面说过,此处大家可将迭代器暂时理解成类似于指针,迭代器失效即迭代器所指向的节点的无效,即该节
点被删除了。因为list的底层结构为带头结点的双向循环链表,因此在list中进行插入时是不会导致list的迭代
器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响

void TestListIterator1()
{
	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())
	{
		// 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的模拟实现

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<assert.h>
using namespace std;
namespace sz
{
//  链表节点  /
	template <class T>
	struct list_node
	{
		//_list_node<T>* next;
		//_list_node<T>* prev;
		typedef list_node Node;
		Node* _next;
		Node* _prev;
		T _data;

		// 不需要像以前写一个BuyNode里面malloc一个节点然后初始化
		// 这里new Node的时候,直接会调用里面的构造函数,初始化这个节点
		list_node(const T& x = T())
			:_data(x)
			, _next(nullptr)
			, _prev(nullptr)
		{}
	};

//  list迭代器(正向)  /
	/*
	  刚开始可能会感到疑惑,为什么list不能象string与vector一样 typedef T* iterator
	  反而要写一个类,因为我们要像vector中的迭代器一样,auto it = lt.begin()之后
	  可以 it++, *it(解引用)但是 node++,*node是错误的,因为链表不是连续的++不可以,而且我们解引用
	  是为了获取node中的data,但是直接*node获取不到

	  这时我们就可以想到用运算符重载来解决这些问题,所以要将迭代器写成一个类
	 */



	 // 像指针一样的对象
	//template <class T>
	template <class T, class Ret, class Ptr> // 这里是为了可以使用const_iterator
	struct list_iterator // 这里的迭代器对象不需要析构,因为_node指向的空间是属于list的
	{
		//typedef list_iterator<T> iterator;
		typedef list_iterator<T, Ret, Ptr> iterator;
		typedef list_node<T> Node;

		Node* _node;

		// 构造函数
		list_iterator(Node* node)
			:_node(node)
		{}

		bool operator!=(const iterator& it)
		{
			return _node != it._node; // 用节点的指针比较
		}
		bool operator==(const iterator& it)
		{
			return _node == it._node;
		}

		/*
		T& 中可以修改数据,但是还需要一个const 的迭代器保证数据不能修改
		加一个const 在T&前面不能解决问题因为 返回值不能构成重载  	如何解决呢?
		方法一,重新写一份 list_itreator,里面用cosnt T,但是太麻烦,因为需要加cosnt只有
		T& operator*和T* operator->可能会修改数据
		方法二: 模板实例化的时候区分  template <class T, class Ret, class Ptr>

		下面使用模板时,实例化不同就可以了
		typedef __list_iterator<T, T&, T*>             iterator;
		typedef __list_iterator<T, const T&, const T*> const_iterator;

		*/

		// *it
		//T& operator*()// 调用iterator时Ref会被实例化为 T&
		Ret operator*() // 调用const_iterator时Ref会被实例化为 const T&
		{
			return _node->_data;
		}

		// ++it 会改变_node
		iterator& operator++()
		{
			_node = _node->_next;
			return *this; // 返回迭代器对象
		}
		// it++
		iterator& operator++(int)
		{
			iterator tmp(*this);
			_node = _node->_next;
			return tmp;
		}
		//--it
		iterator& operator--()
		{
			_node = _node->_prev;
			return *this;
		}
		iterator& operator--(int)
		{
			iterator tmp(*this);
			_node = _node->_prev;
			return tmp;
		}
		// it->_aa 其实本质是  it->->_aa (语法为了可读性,编译器经行的特殊处理,省略了一个 -> )  
		// 前面it-> 是调用重载 返回 T*
		//T* operator->()
		Ptr operator->()
		{
			// _node是一个节点 里面存储的数据 是一个对象
			// _node->data 找到这个对象,返回
			return &(operator*()); // return &(_node->_data); // 取这个对象的地址
		}
	};

	
	
//  list模拟实现  /
	template <class T>
	class list
	{
		typedef list_node<T> Node;
		//typedef list_iterator<T> iterator;  放在pubilc中,外面要使用
	public:
		//typedef list_iterator<T> iterator;
		typedef list_iterator<T, T&, T*> iterator;
		typedef list_iterator<T, const T&, const T*> const_iterator;

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

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


		// 注意 it++ 返回的还是迭代器,不是Node
		iterator begin()
		{
			// 构造一个迭代器返回,这里是一个匿名对象
			// 这里直接返回会有优化
			return iterator(_head->_next);
		}

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

		void empty_init()
		{
			_head = new Node;
			_head->_next = _head;
			_head->_prev = _head;
		}

		list()
		{
			//_head = new Node;
			//_head->_next = _head;
			//_head->_prev = _head;
			empty_init();
		}
		template <class InputIterator>
		list(InputIterator first, InputIterator last)
		{
			empty_init();
			while (first != last)
			{
				push_back(*first); // 将节点中的值作为参数,这里会调用operator*
				first++;
			}
		}

		// 仅限在类里面,可以不写模板参数,下面也是允许的
		// void swap(list& x)
		void swap(list<T>& x)
		{
			std::swap(_head, x._head);
		}
		// lt2(lt1)
		list(const list<T>& lt)
		{ 
			// 浅拷贝会出现问题
			//_head = it._head; 

			// 深拷贝
			empty_init();
			list<T> tmp(lt.begin(), lt.end());
			swap(tmp);
		}

		// lt1 = lt3
		list<T>& operator=(list<T> lt)
		{
			swap(lt);
			return *this;
		}

		~list()
		{
			clear();
			delete _head; // 释放哨兵位节点
			_head = nullptr;
		}

		void clear()
		{
			iterator it = begin();
			while (it != end())
			{
				it = erase(it);
			}
		}
		void push_back(const T& x)
		{
			// 尾插,先保存尾节点
			Node* tail = _head->_prev; 
			// 申请一个节点
			Node* newnode = new Node(x);
			// 尾插入 _head  tail  newnode
			_head->_prev = newnode;
			newnode->_next = _head;
			tail->_next = newnode;
			newnode->_prev = tail;

			 //复用insert
			//insert(end(), x);
		}

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

		iterator inster(iterator pos, const T& x)
		{
			Node* cur = pos._node;
			Node* prev = cur->_prev;

			Node* newnode = new Node(x);

			// prev newnode cur
			prev->_next = newnode;
			newnode->_prev = cur;
			newnode->_next = prev;
			prev->_prev = newnode;

			return iterator(newnode);
		}

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

			prev->_next = next;
			next->_prev = prev;
			delete cur;

			return iterator(next);
		}
		iterator pop_back()
		{
			erase(--end()); // end指哨兵位节点
		}
		iterator pop_front()
		{
			erase(begin());
		}

	private:
		Node* _head;
	};
}

void TextList1()
{
	sz::list<int> lt;
	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	// 拷贝构造 - 浅拷贝
	//  // list_iterator it = lt.begin() -> list_iterator(lt.begin())
	sz::list<int>::iterator it = lt.begin();
	while (it != lt.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;

	it = lt.begin();
	while (it != lt.end())
	{
		*it *= 2;
		++it;
	}
	cout << endl;

	it = lt.begin();
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;
}

void TextList2()
{
	struct Pos
	{
		int _aa;
		int _bb;

		Pos(int aa = 10, int bb = 20)
			:_aa(aa)
			, _bb(bb)
		{}
	};

	Pos p1;
	Pos* p2 = &p1;
	p2->_aa;
	p2->_bb;

	sz::list<Pos> lt;
	lt.push_back(Pos(10, 20));
	lt.push_back(Pos(30, 40));

	sz::list<Pos>::iterator it = lt.begin();

	while (it != lt.end())
	{
		//cout << *it << " "; // 报错 *it是Pos对象,自定义类型,需要重载流输入

		//cout << (*it)._aa << ":" << (*it)._bb << endl; //可以 

		// it是一个结构,在结构体里面 (*it)._aa == it->_aa
		// 想要像这样去访问就要用到 -> 的运算符重载
		cout << it->_aa << ":" << it->_bb << endl; //可以
		it++;
	}
}

void Func(const sz::list<int>& l)
{
	sz::list<int>::const_iterator it = l.begin();
	while (it != l.end())
	{
		cout << *it << " ";
		//*it *= 2;
		++it;
	}
	cout << endl;
	it = l.begin();
	while (it != l.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
}
void TextList3()
{
	sz::list<int> lt;
	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);

	Func(lt);
}

void TextList4()
{
	sz::list<int> lt;
	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);

	sz::list<int>::iterator it = lt.begin();

	while (it != lt.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;

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

	sz::list<int> lt2;
	lt2.push_back(10);
	lt2.push_back(20);
	lt2.push_back(30);

	lt = lt2;
	it = lt.begin();
	while (it != lt.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;
}
int main()
{
	TextList4();
	return 0;
}

list反向迭代器

reverse_reverse

这里的反向迭代器不仅适用list也适用vector

#pragma once
namespace sz
{
	// 复用, 迭代器适配器
	template<class Iterator, class Ret, class Ptr>
	class _reverse_iterator
	{
	public:
		Iterator _cur;

		typedef _reverse_iterator<Iterator, Ret, Ptr> RIterator;
		
		_reverse_iterator(Iterator it)
			:_cur(it)
		{}
		// 前置
		RIterator operator++()
		{
			--_cur;
			return *this;
		}
		// 后置
		RIterator operator++(int)
		{
			_cur--;
			return *this;
		}

		RIterator operator--()
		{
			++_cur;
			return *this;
		}

		RIterator operator--(int)
		{
			_cur++;
			return *this;
		}

		// 这里解引用要注意,先减减再返回
		// 注意list和vector 中end指向 list end指向哨兵位的节点  vector指向最后一个元素
		Ret operator*()
		{
			//return *_cur;
			auto tmp = _cur;
			--tmp;
			return *tmp;
		}

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

		bool operator!=(const RIterator& it)
		{
			return _cur != it._cur;
		}
	};
}

list.h

#pragma once
#include<iostream>
#include<assert.h>
#include"reverse_iterator.h"
using namespace std;
namespace sz
{
	template <class T>
	struct list_node
	{
		//_list_node<T>* next;
		//_list_node<T>* prev;
		typedef list_node Node;
		Node* _next;
		Node* _prev;
		T _data;

		list_node(const T& x = T())
			:_data(x)
			, _next(nullptr)
			, _prev(nullptr)
		{}
	};
	 // 像指针一样的对象
	//template <class T>
	template <class T, class Ret, class Ptr> // 这里是为了可以使用const_iterator
	struct list_iterator // 这里的迭代器对象不需要析构,因为_node指向的空间是属于list的
	{
		//typedef list_iterator<T> iterator;
		typedef list_iterator<T, Ret, Ptr> iterator; // 迭代器的类型是一个对象 list_iterator<T, Ret, Ptr>
		typedef list_node<T> Node;

		Node* _node;

		// 构造函数
		list_iterator(Node* node)
			:_node(node)
		{}

		bool operator!=(const iterator& it)
		{
			return _node != it._node; // 用节点的指针比较
		}
		bool operator==(const iterator& it)
		{
			return _node == it._node;
		}

		// *it
		//T& operator*()// 调用iterator时Ref会被实例化为 T&
		Ret operator*() // 调用const_iterator时Ref会被实例化为 const T&
		{
			return _node->_data;
		}

		// ++it 会改变_node
		iterator& operator++()
		{
			_node = _node->_next;
			return *this; // 返回迭代器对象
		}
		// it++
		iterator& operator++(int)
		{
			iterator tmp(*this);
			_node = _node->_next;
			return tmp;
		}
		//--it
		iterator& operator--()
		{
			_node = _node->_prev;
			return *this;
		}
		iterator& operator--(int)
		{
			iterator tmp(*this);
			_node = _node->_prev;
			return tmp;
		}
		// it->_aa 其实本质是  it->->_aa (语法为了可读性,编译器经行的特殊处理,省略了一个 -> )  
		// 前面it-> 是调用重载 返回 T*
		//T* operator->()
		Ptr operator->()
		{
			// _node是一个节点 里面存储的数据 是一个对象
			// _node->data 找到这个对象,返回
			return &(operator*()); // return &(_node->_data); // 取这个对象的地址
		}

	};

	template <class T>
	class list
	{
		typedef list_node<T> Node;
		//typedef list_iterator<T> iterator;  放在pubilc中,外面要使用
	public:
		//typedef list_iterator<T> iterator;
		typedef list_iterator<T, T&, T*> iterator;
		typedef list_iterator<T, const T&, const T*> const_iterator;

		// 反向迭代器
		typedef _reverse_iterator<iterator, T&, T*> reverse_iterator;
		typedef _reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;


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

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

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

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

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

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


		// 注意 it++ 返回的还是迭代器,不是Node
		iterator begin()
		{
			// 构造一个迭代器返回,这里是一个匿名对象
			// 这里直接返回会有优化
			return iterator(_head->_next);
		}

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

		void empty_init()
		{
			_head = new Node;
			_head->_next = _head;
			_head->_prev = _head;
		}

		list()
		{
			//_head = new Node;
			//_head->_next = _head;
			//_head->_prev = _head;
			empty_init();
		}
		template <class InputIterator>
		list(InputIterator first, InputIterator last)
		{
			empty_init();
			while (first != last)
			{
				push_back(*first); // 将节点中的值作为参数,这里会调用operator*
				first++;
			}
		}

		// 仅限在类里面,可以不写模板参数,下面也是允许的
		// void swap(list& x)
		void swap(list<T>& x)
		{
			std::swap(_head, x._head);
		}
		// lt2(lt1)
		list(const list<T>& lt)
		{
			// 浅拷贝会出现问题
			//_head = it._head; 

			// 深拷贝
			empty_init();
			list<T> tmp(lt.begin(), lt.end());
			swap(tmp);
		}

		// lt1 = lt3
		list<T>& operator=(list<T> lt)
		{
			swap(lt);
			return *this;
		}

		~list()
		{
			clear();
			delete _head; // 释放哨兵位节点
			_head = nullptr;
		}

		void clear()
		{
			iterator it = begin();
			while (it != end())
			{
				it = erase(it);
			}
		}
		void push_back(const T& x)
		{
			// 尾插,先保存尾节点
			Node* tail = _head->_prev;
			// 申请一个节点
			Node* newnode = new Node(x);
			// 尾插入 _head  tail  newnode
			_head->_prev = newnode;
			newnode->_next = _head;
			tail->_next = newnode;
			newnode->_prev = tail;

			//复用insert
		   //insert(end(), x);
		}

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

		iterator inster(iterator pos, const T& x)
		{
			Node* cur = pos._node;
			Node* prev = cur->_prev;

			Node* newnode = new Node(x);

			// prev newnode cur
			prev->_next = newnode;
			newnode->_prev = cur;
			newnode->_next = prev;
			prev->_prev = newnode;

			return iterator(newnode);
		}

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

			prev->_next = next;
			next->_prev = prev;
			delete cur;

			return iterator(next);
		}
		iterator pop_back()
		{
			erase(--end()); // end指哨兵位节点
		}
		iterator pop_front()
		{
			erase(begin());
		}

	private:
		Node* _head;
	};
}


  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-12-25 11:33:24  更:2022-12-25 11:35:29 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/3 3:41:41-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码