list的底层与使用

前言:list是带头双向循环链表,物理空间不连续,导致对于迭代器的操作需要进行运算符重载,难点也在于对迭代器的使用与实现

cpp 复制代码
//底层代码
#pragma once
#include<assert.h>
#include<iostream>
using namespace std;
namespace bit
{
	template <typename T>
	struct ListNode
	{
		ListNode<T>* next;
		ListNode<T>* prev;
		T data;
		ListNode(T x = 0)//在这里进行数据的深拷贝
			: next(nullptr), prev(nullptr), data(x)//初始化列表
		{}
	};
	template<typename T,typename ptr , typename ref>
	struct NodeIterator
	{
	
		typedef ListNode<T> Node;
		typedef NodeIterator<T,ptr,ref> iterator;
		
		NodeIterator(Node* tmp)
			: _node( tmp)
		{}
		
		ref operator*() const
		{
			return _node->data;
		}
		//++it
		iterator operator++()
		{
			_node = _node->next;
			return *this;
		}
		// it++
		iterator operator++(int)
		{
			iterator tmp(*this);
			_node = _node->next;
			return tmp;
		}
		//it--
		iterator operator--(int)
		{
			iterator tmp(*this);
			_node = _node->prev;
			return tmp;
		}
		iterator operator--()
		{
			_node = _node->prev;
			return *this;
		}
		bool operator!=(const iterator& n) const
		{
			return _node != n._node;
		}
		ptr operator->()
		{
			return &(_node->data);
		}
		Node* _node;
	};
	template<typename T>
	class list
	{
	public:
		typedef NodeIterator<T,T* , T&> iterator;
		typedef NodeIterator<T,const T* ,const T&> const_iterator;
		typedef ListNode<T> Node;
		list(const list& s)
		{
			size = 0;
			phead = new Node(0);
			phead->prev = phead->next = phead;
			for (auto& e : s)
				push_back(e);

		}
		void clear()
		{
			auto it = begin();
			while (it != end())
				it = erase(it);

		}
		~list()
		{
			clear();
			delete phead;
			size = 0;
			phead = nullptr;
		}
		list()
		{
			size = 0;
			phead = new Node(0);
			phead->prev = phead->next = phead;
			
		}
		void push_back(const T& x)
		{
			insert(end(), x);
		}
		void push_front(const T& x)
		{
			insert(begin(), x);
		}
		void pop_back()
		{
			erase(end()._node->prev);
		}
		void pop_front()
		{
			erase(begin());
		}
		iterator begin()
		{
			return phead->next;
		}
		iterator end()
		{
			return phead;
		}
		const_iterator begin()const
		{
			return phead->next;
		}
		const_iterator end()const
		{
			return phead;
		}
		void insert(iterator position, const T& val)
		{
			Node* _position = position._node;
			Node* tmp = new Node(val);
			tmp->next = _position;
			tmp->prev = _position->prev;
			_position->prev->next = tmp;
			_position->prev = tmp;
			size++;
		}
		iterator erase(iterator position)
		{
			Node* _position = position._node;
			Node* tt = _position->next;
			Node* tmp = _position->prev;
			tmp->next = _position->next;
			_position->next->prev = tmp;
			delete _position;
			size--;
			_position = nullptr;
			return tt;
		}
        list& operator= ( list x )
        {
            swap(x);
            return *this;
        }

		bool empty()
		{
			return size == 0;
		}
		void swap(list<T> s)
        {
	        std::swap(size, s.size);
	        std::swap(phead, s.phead);
        }
        list& operator= (list<T> x)
        {
	        swap(x);
        	return *this;
        }
	private:
		Node* phead;//头结点
		int size;
		
	};
}

迭代器

迭代器一般需要进行如下操作

std::list<int>::iterator it = s.begin();

while( it != s.end())

{

cout << *it << " ";

it++;

}

也就是需要对运算符 * != ++ 对操作符重载

明确一点:链表中的迭代器是节点的指针 , 指针是内置类型 ,但需要对内置类型的行为重新定义,则可以把内置类型转换成自定义类型(单独为迭代器写一个类)

首先 * 一般是取链表中的元素(节点中的data) ,在迭代器中需要取data,只需要将节点的指针作为迭代器类的成员变量

第二点 迭代器可以分为const 或者是 非const ,则可以将迭代器写成一个类模版

cpp 复制代码
// 首先在begin函数中 分为 iterator begin()    const_iterator begin() const
// typedef NodeIterator< T ,  T& , typename T*>  iterator;
// typedef NodeIterator< T , const T& , T* > const_iterator;
// 就导致NodeIterator只生成两个类
// iterator begin 放回的是iterator(他就只会调用第一个类)
// const_iterator begin返回的是const_iterator(只会调用第二个类)
template<typename T,typename ptr , typename ref>
struct NodeIterator
{

	typedef ListNode<T> Node;
	typedef NodeIterator<T,ptr,ref> iterator;
	
	NodeIterator(Node* tmp)
		: _node( tmp)
	{}
	
	ref operator*() const
	{
		return _node->data;
	}
	//++it
	iterator operator++()
	{
		_node = _node->next;
		return *this;
	}
	// it++
	iterator operator++(int)
	{
		iterator tmp(*this);
		_node = _node->next;
		return tmp;
	}
	//it--
	iterator operator--(int)
	{
		iterator tmp(*this);
		_node = _node->prev;
		return tmp;
	}
	iterator operator--()
	{
		_node = _node->prev;
		return *this;
	}
	bool operator!=(const iterator& n) const
	{
		return _node != n._node;
	}
	ptr operator->()
	{
		return &(_node->data);
	}
	Node* _node;
};

构造函数

方法1:初始化链表初始化

cpp 复制代码
#include<iostream>
#include<vector>
#include<list>
#include<stack>
using namespace std;
int main()
{
	list<int> s = { 1 , 2 , 3 , 4 , 5 };
	for (auto& e : s)cout << e << " ";
	cout << endl;
}

方法2:迭代器区间初始化

cpp 复制代码
#include<iostream>
#include<vector>
#include<list>
#include<stack>
using namespace std;
int main()
{
	vector<int> dp = { 1 , 2 , 3 ,4 , 6 };
	auto it = dp.begin();
	list<int> s(it + 2, dp.end() - 1);
	for (auto& e : s)cout << e << " ";
	cout << endl;
}

方法3:不加任何条件

cpp 复制代码
#include<iostream>
#include<vector>
#include<list>
#include<stack>
using namespace std;
int main()
{
	list<int> s;
    return 0;
}

拷贝构造与赋值重载

均为深拷贝

front与back函数

返回头和尾元素

cpp 复制代码
#include<iostream>
#include<vector>
#include<list>
#include<stack>
using namespace std;
int main()
{
	vector<int> dp = { 1 , 2 , 3 ,4 , 6 };
	int f = dp.front();
	int t = dp.back();
	cout << f << " " << t << endl;

}

insert函数

在某一个位置之前插入一个值或一段区间

cpp 复制代码
#include<iostream>
#include<vector>
#include<list>
#include<stack>
using namespace std;
int main()
{
	list<int> s = { 1 , 2 , 4  , 5 , 6 };
	auto it = s.begin();
	vector<int> dp = { 1 , 0 , 9 };
	s.insert(it, dp.begin(), dp.end());
	for (auto& e : s)cout << e << " ";
	cout << endl;
	s.insert(s.end(), 10);
	for (auto& e : s)cout << e << " ";
	cout << endl;

}

erase函数

去除某一个位置的值,或某一段区间的值

cpp 复制代码
#include<iostream>
#include<vector>
#include<list>
#include<stack>
using namespace std;
int main()
{
	list<int> s = { 1 , 2 , 3 , 5 , 3 };
	s.erase(s.begin());
	list<int> p = { 4 , 5 , 12 , 3 , 4 };
	s.erase(++p.begin(), --p.end());
	for (auto& e : p)cout << e << " ";
	cout << endl;

}

push_back 与push_front函数

本质复用insert函数 尾插 头插

pop_back与pop_front函数

本质复用erase函数

assign函数

将链表中的内容重新分配

cpp 复制代码
#include<iostream>
#include<vector>
#include<list>
#include<stack>
using namespace std;
int main()
{
	list<int> s = { 1, 2, 3, 4, 6 };
	list<int> k = { 9 , 1 , 0 };
	s.assign({ 2,3,45 });
	for (auto& e : s)cout << e << " ";
	cout << endl;
	s.assign(k.begin(),k.end());
	for (auto& e : s)cout << e << " ";
	cout << endl;

}
相关推荐
软件资深者44 分钟前
HP M126a打印机,系统不支持请求的命令或者资源管理器出错
windows·windows11·系统修复
SJjiemo1 小时前
TreeSize Pro 专业磁盘空间分析
windows
学嵌入式的小杨同学1 小时前
【嵌入式 C 语言实战】交互式栈管理系统:从功能实现到用户交互全解析
c语言·开发语言·arm开发·数据结构·c++·算法·链表
多米Domi0111 小时前
0x3f 第40天 setnx的分布式锁和redission,写了一天项目书,光背了会儿八股,回溯(单词搜索)
数据结构·算法·leetcode
历程里程碑2 小时前
Linux 3 指令(3):进阶指令:文件查看、资源管理、搜索打包压缩详解
linux·运维·服务器·c语言·数据结构·笔记·算法
一分之二~2 小时前
二叉树--求最小深度(迭代和递归)
数据结构·c++·算法·leetcode·深度优先
wWYy.3 小时前
详解redis(8):数据结构Hash
数据结构·redis·哈希算法
智者知已应修善业3 小时前
【输出一个N*N的01矩阵,表示最后的汉字点阵图】2024-10-22
c语言·数据结构·c++·经验分享·笔记·算法·矩阵
uesowys3 小时前
华为OD算法开发指导-二级索引
数据结构·算法·华为od
摸鱼仙人~4 小时前
构建基于 JSON 模板的可插拔通用LLM信息提取系统
windows