list~模拟实现

目录

list的介绍及使用

list的底层结构

节点类的实现

list的实现

构造函数

拷贝构造

方法一:方法二:

 析构函数

赋值重载

insert  /  erase

push_/pop_(尾插/尾删/头插/头删)

begin和end(在已建立迭代器的基础上)

迭代器实现

迭代器类模板参数说明

list包含在头文件

 部分摘自— list模拟实现


list的介绍及使用

list的介绍
1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。
2. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向 其前一个元素和后一个元素。ps—>2
3. list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高效。
4. 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好。
5. 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list 的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间 开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这 可能是一个重要的因素)

list的底层结构

ps—>2

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


节点类的实现

但我们要去实现list,就首先需要定义实现好一个结点类。

而一个结点需要存储:

需要存储的数据、前驱节点、后继节点的地址。

这里用struct定义这个节点类不用class,因为很多地方都要用到和访问这个节点类,成员变量就都共有。

这里也不需要专门单独写一个析构函数,因为这个节点类并没有对应的资源需要清理;

template <class T>
struct ListNode
{
	ListNode<T>* _prev;
	ListNode<T>* _next;
	T _data;

	ListNode(const T& data = T())
		:_prev(nullptr)
		, _next(nullptr)
		, _data(data)
	{}
};

list的实现

链表其实就是用一个指向头节点的指针管理起来的,所以,我们可以定义一个list类,它的成员变量是一个指向头节点的指针,因为,list的底层是一个带头双向循环链表,所以这里的指针,应该指向,带有哨兵位的头节点。

template<class T>
class list
{
public:
	/*typedef ListNode<T> Node;
	typedef ListIterator<T, T&, T*> iterator;
	typedef ListIterator<T, const T&, const T*> const_iterator;
	list()
	{
		_head = new Node();
		_head->_prev = _head;
		_head->_next = _head;
	}

	iterator begin()
	{
		return iterator(_head->_next);
	}
	iterator end()
	{
		return iterator(_head);
	}*/

private:

	Node* _head;
};

构造函数

ist是一个带头双向循环链表,在构造一个list对象时,首先要申请一个头结点,并让其前驱指针和后继指针都指向自己。

list()
{
	_head = new node; //申请头结点
	_head->_next = _head; //头结点的后继指针指向自己
	_head->_prev = _head; //头结点的前驱指针指向自己
}


拷贝构造

拷贝构造有两种方式:        ①用一个list构造方法二        ②迭代器区间

为了方便起见,我们可以先封装手撕一个empty()函数,去申请头节点,生成一个空链表,在构造和拷贝构造的时候,可以更加方便地调用。

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

方法一:

已经申请一个头结点,并让其前驱指针和后继指针都指向自己,然后将所给容器当中的数据,通过遍历的方式一个个尾插到新构造的容器后面即可。

list(const list<T>& lt)
{
	empty();

	for (const auto& e : lt)
	{
		push_back(e);
	}
}

方法二:

我们先实现一个使用迭代器区间构造的函数。

template <class Iterator>
list(Iterator first, Iterator last)
{
	empty;//不加会出问题

	while (first != last)
	{
		push_back(*first);
		++first;
	}
}

然后,我们先创建一个临时对象让他利用被拷贝对象的迭代器构造出来,然后再交换,被利用完后的临时对象会在栈帧结束后被清除。

我们先实现swap函数,很简单,交换头节点的指针就可以。

void swap(list<T>& tmp)
{
	std::swap(_head, tmp._head);
}
list(const list<T>& lt)
{
	empty();

	list<T> tmp(lt.begin(), lt.end());

	swap(tmp);
}


 析构函数

我们可以调用clear函数清理容器当中的数据,然后将头结点释放,最后将头指针置空即可

void clear()//将头结点释放
{
	iterator it = begin();

	while (it != end())
	{
		//it = erase(it);
		erase(it++);
	}
}
~list()
{
	clear();//将头结点释放

	delete _head;//最后将头指针置空即可
	_head = nullptr;
}


赋值重载

通过编译器自动调用list的拷贝构造函数构造出来一个list对象,然后调用swap函数将原容器与该list对象进行交换即可。

list<T>& operator=(list<T> tmp)
{
	swap(tmp);

	return *this;
}

insert  /  erase

insert函数的作用时在指定迭代器的位置之前插入一个数据。

iterator insert(iterator pos, const T& x)
{
	Node* node = pos._node;//记录当前节点
	Node* prev = node->_prev;//记录前驱节点

	Node* newnode = new Node(x);//记录要插入节点

	newnode->_prev = prev;
	newnode->_next = node;
	
	prev->_next = newnode;
	node->_prev = newnode;

	return iterator(newnode);
}

erase函数用来删除指定迭代器位置的数据。

iterator erase(iterator pos)
{
	assert(pos != end());//防止删除头节点
	
	Node* del = pos._node;//记录要删除节点
	Node* prev = del->_prev;//记录前驱节点
	Node* next = del->_next;//记录后续节点

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

	return iterator(next);//返回所给迭代器pos的下一个迭代器,防止迭代器失效
}

push_/pop_(尾插/尾删/头插/头删)


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()); 
}


begin和end(在已建立迭代器的基础上)

begin函数返回的是第一个有效数据的迭代器,end函数返回的是最后一个有效数据的下一个位置的迭代器。

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);
}


迭代器实现

对于list来说,它的数据不是连续存储的而是通过一个一个节点通过指针连接到一起的,所以,_head++并不能到下一个数据的位置,但是可以通过_head = _head->_next实现,所以这里我们可以使用节点的指针单独封装一个类,通过运算符重载模拟指针的行为。

(vector迭代器可以使用原生指针来实现,因为vector的空间时连续的,可以直接支持运算符++的重载,_start时指向第一个数据的指针,_start++就指向下一个位置了。

迭代器类模板参数说明

template<class T, class Ref, class Ptr>

 在list的模拟实现当中,我们typedef了两个迭代器类型,普通迭代器和const迭代器

typedef _list_iterator<T, T&, T*> iterator;
typedef _list_iterator<T, const T&, const T*> const_iterator;

所以,迭代器类的模板参数列表当中的RefPtr分别代表的是解引用类型指针类型

当我们使用普通迭代器时,编译器就会实例化出一个普通迭代器对象;当我们使用const迭代器时,编译器就会实例化出一个const迭代器对象。

template <class T,class Ref,class Ptr>
struct ListIterator
{
	typedef ListNode<T> Node;
	Node* _node;

	typedef ListIterator<T,Ref,Ptr> self;

	ListIterator(Node* node)
		:_node(node)
	{}

	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;
	}

	Ref operator*()
	{
		return _node->_data;
	}

	bool operator!=(const self& node)
	{
		return _node != node._node;
	}

	bool operator==(const self& node)
	{
		return _node == node._node;
	}

	Ptr operator->()
	{
		return &_node->_data;
	}
};


struct Pos
	{
		int _row;
		int _col;

		Pos(int row = 0, int col = 0)
			:_row(row)
			,_col(col)
		{}
	};

	

	void test_list2()
	{
		list<Pos> lt1;
		lt1.push_back(Pos(100, 100));
		lt1.push_back(Pos(200, 200));
		lt1.push_back(Pos(300, 300));

		list<Pos>::iterator it = lt1.begin();
		while (it != lt1.end())
		{
			//cout << (*it)._row << ":" << (*it)._col << endl;
			// 为了可读性,省略了一个->
			cout << it->_row << ":" << it->_col << endl;
			//cout << it->->_row << ":" << it->->_col << endl;
			cout << it.operator->()->_row << ":" << it.operator->()->_col << endl;

			++it;
		}
		cout << endl;
	}


list包含在头文件

因为list类是一种模板,不建议list内部内容函数声明定义分开来写,所以都包含在同一个文件当中

#pragma once
#include<assert.h>

namespace bit
{
	template<class T>
	struct ListNode
	{
		ListNode<T>* _next;
		ListNode<T>* _prev;

		T _data;

		ListNode(const T& data = T())
			:_next(nullptr)
			,_prev(nullptr)
			,_data(data)
		{}
	};

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

		ListIterator(Node* node)
			:_node(node)
		{}

		// ++it;
		Self& operator++()
		{
			_node = _node->_next;
			return *this;
		}

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

		Self operator++(int)
		{
			Self tmp(*this);
			_node = _node->_next;

			return tmp;
		}

		Self& operator--(int)
		{
			Self tmp(*this);
			_node = _node->_prev;

			return tmp;
		}

		Ref operator*()
		{
			return _node->_data;
		}

		Ptr operator->()
		{
			return &_node->_data;
		}

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

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

	//template<class T>
	//class ListConstIterator
	//{
	//	typedef ListNode<T> Node;
	//	typedef ListConstIterator<T> Self;

	//	Node* _node;
	//public:
	//	ListConstIterator(Node* node)
	//		:_node(node)
	//	{}

	//	// ++it;
	//	Self& operator++()
	//	{
	//		_node = _node->_next;
	//		return *this;
	//	}

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

	//	Self operator++(int)
	//	{
	//		Self tmp(*this);
	//		_node = _node->_next;

	//		return tmp;
	//	}

	//	Self& operator--(int)
	//	{
	//		Self tmp(*this);
	//		_node = _node->_prev;

	//		return tmp;
	//	}

	//	//*it
	//	const T& operator*()
	//	{
	//		return _node->_data;
	//	}

	//	const T* operator->()
	//	{
	//		return &_node->_data;
	//	}

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

	//	bool operator==(const Self& it)
	//	{
	//		return _node == it._node;
	//	}
	//};

	template<class T>
	class list
	{
		typedef ListNode<T> Node;
	public:
		// 不符合迭代器的行为,无法遍历
		//typedef Node* iterator;
		//typedef ListIterator<T> iterator;
		//typedef ListConstIterator<T> const_iterator;

		typedef ListIterator<T, T&, T*> iterator;
		typedef ListIterator<T, const T&, const T*> const_iterator;

		iterator begin()
		{
			//iterator it(_head->_next);
			//return it;
			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);
		}

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

		void push_back(const T& x)
		{
			/*Node* newnode = new Node(x);
			Node* tail = _head->_prev;

			tail->_next = newnode;
			newnode->_prev = tail;
			newnode->_next = _head;
			_head->_prev = newnode;*/

			insert(end(), x);
		}

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

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

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

		// 没有iterator失效
		iterator insert(iterator pos, const T& x)
		{
			Node* cur = pos._node;
			Node* newnode = new Node(x);
			Node* prev = cur->_prev;

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

			return iterator(newnode);
		}

		// erase 后 pos失效了,pos指向节点被释放了
		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);
		}

	private:
		Node* _head;
	};

	void Func(const list<int>& lt)
	{
		// const iterator const 迭代器不能普通迭代器前面加const修饰
		// const 迭代器目标本身可以修改,指向的内容不能修改 类似const T* p 
		list<int>::const_iterator it = lt.begin();
		while (it != lt.end())
		{
			// 指向的内容不能修改
			//*it += 10;

			cout << *it << " ";
			++it;
		}
		cout << endl;
	}

	void test_list1()
	{
		list<int> lt1;

		// 按需实例化(不调用就不实例化这个成员函数)
		lt1.push_back(1);
		lt1.push_back(2);
		lt1.push_back(3);
		lt1.push_back(4);
		lt1.push_back(5);

		Func(lt1);

		//ListIterator<int> it = lt1.begin();
		list<int>::iterator it = lt1.begin();
		while (it != lt1.end())
		{
			*it += 10;

			cout << *it << " ";
			++it;
		}
		cout << endl;

		for (auto e : lt1)
		{
			cout << e << " ";
		}
		cout << endl;
	}

	struct Pos
	{
		int _row;
		int _col;

		Pos(int row = 0, int col = 0)
			:_row(row)
			,_col(col)
		{}
	};

	

	void test_list2()
	{
		list<Pos> lt1;
		lt1.push_back(Pos(100, 100));
		lt1.push_back(Pos(200, 200));
		lt1.push_back(Pos(300, 300));

		list<Pos>::iterator it = lt1.begin();
		while (it != lt1.end())
		{
			//cout << (*it)._row << ":" << (*it)._col << endl;
			// 为了可读性,省略了一个->
			cout << it->_row << ":" << it->_col << endl;
			//cout << it->->_row << ":" << it->->_col << endl;
			cout << it.operator->()->_row << ":" << it.operator->()->_col << endl;

			++it;
		}
		cout << endl;
	}


	void test_list4()
	{
		list<int> lt1;
		lt1.push_back(1);
		lt1.push_back(2);
		lt1.push_back(3);
		lt1.push_back(4);
		lt1.push_back(5);

		Func(lt1);

		lt1.push_front(10);
		lt1.push_front(20);
		lt1.push_front(30);

		Func(lt1);

		lt1.pop_front();
		lt1.pop_front();
		Func(lt1);

		lt1.pop_back();
		lt1.pop_back();
		Func(lt1);

		lt1.pop_back();
		lt1.pop_back();
		lt1.pop_back();
		lt1.pop_back();
		//lt1.pop_back();
		Func(lt1);
	}
}


 部分摘自— list模拟实现
  • 14
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
引用和提供了关于实现vector的两种方法。其中,引用展示了一个使用reserve和push_back方法的示例,而引用展示了一个使用new和memcpy函数的示例。这两种方法都是常见的实现vector的方式。 在第一种方法中,通过reserve函数可以预留足够的内存空间,然后使用push_back函数逐个将元素添加到vector中。这种方法的好处是可以避免不必要的内存重分配,提高了效率。 而第二种方法使用new操作符在堆上分配内存空间,并使用memcpy函数将已有的vector对象的数据复制到新的内存空间中。通过这种方式,可以实现深拷贝,即两个vector对象拥有独立的内存空间。这种方法的好处是可以在不修改原始vector对象的情况下创建一个新的vector对象。 除了以上两种方法,还可以使用其他方式实现vector类。例如,可以使用动态数组来实现vector的底层数据结构,然后通过成员函数实现vector的各种操作,如增加、删除、查找等。 总结来说,c语言模拟实现vector的关键是动态内存管理和对元素的增删改查操作。可以使用预留空间和逐个添加元素的方式,也可以使用动态数组和复制数据的方式来实现vector类。具体的实现方式可以根据需求和实际情况选择。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [C++——vector模拟实现](https://blog.csdn.net/weixin_49449676/article/details/126813526)[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^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

尚尚.

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

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

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

打赏作者

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

抵扣说明:

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

余额充值