stl_list.h源码剖析

容器list双向环形链表

list相较于vector的连续线性空间,list显得复杂许多,好处是每次插入或者删除一个元素,就配置或释放一个元素空间。因此list对于空间的运用绝对精准,一点也不浪费。而且对于任何位置的元素插入和元素移除,list永远是常数时间<STL源码剖析>

相关图

在这里插入图片描述

节点设计
template <class T>
struct __list_node {
	typedef void* void_pointer;//缺陷,使用时都得强转成_list_node类型
	void_pointer next;  // 指针指向下一个节点 
	void_pointer prev;  // 指针指向前一个节点
	T data;				//相应数据类型的data
};
__list_iterator
template<class T, class Ref, class Ptr>
struct __list_iterator { 
	typedef __list_iterator<T, T&, T*>             iterator;
	typedef __list_iterator<T, const T&, const T*> const_iterator;
	typedef __list_iterator<T, Ref, Ptr>           self;

	// 定义五种必要的迭代器类型
	typedef bidirectional_iterator_tag iterator_category;	 // (1) 双向
	typedef T value_type; 			// (2) 数据类型
	typedef Ptr pointer; 			// (3) 指针类型
	typedef Ref reference; 			// (4) 引用
	typedef __list_node<T>* link_type; //节点指针类型
	typedef size_t size_type;
	typedef ptrdiff_t difference_type; // (5)

	link_type node;  // 指向容器的节点

	// 对迭代器解引用,获取节点里保存的data数据
	reference operator*() const { return (*node).data; }

	//重载前++运算符
	self& operator++() {
		//将当前节点指向下一个节点
		node = (link_type)((*node).next);
		return *this;
	}
	//重载后++运算符
	self operator++(int) {
		self tmp = *this;
		//当前节点++
		++*this;
		//将当前节点的赋给临时变量并返回
		return tmp;
	}
	// 重载前--运算符
	self& operator--() {
		//将指针指向当前节点的上一个节点(pre)
		node = (link_type)((*node).prev);
		return *this;
	}
	//重载后--
	self operator--(int) {
		self tmp = *this;
		//前--
		--*this;
		//返回当前节点的临时值
		return tmp;
	}
};
list容器
template <class T, class Alloc = alloc> //默认alloc
class list {
protected:
	typedef void* void_pointer;
	//节点
	typedef __list_node<T> list_node;
	//空间配置器,每次分配一个list_node节点大小的内存
	typedef simple_alloc<list_node, Alloc> list_node_allocator;
public:
	typedef T value_type;			//元素类型
	typedef value_type* pointer;	//指针类型
	typedef const value_type* const_pointer; //const指针类型
	typedef value_type& reference;			 //引用
	typedef const value_type& const_reference;
	typedef list_node* link_type;            //节点类型
	typedef size_t size_type;	
	typedef ptrdiff_t difference_type;

public:
	//迭代器
	//迭代器使用者,使用迭代器时,便会将迭代器中的节点指针指向容器
	typedef __list_iterator<T, T&, T*>             iterator;
	typedef __list_iterator<T, const T&, const T*> const_iterator;
protected:
	// 空间配置申请一个节点内存的大小,并返回指针
	link_type get_node() { return list_node_allocator::allocate(); }
	// 释放内存
	void put_node(link_type p) { list_node_allocator::deallocate(p); }

	// 申请一个节点,并进行相应的赋值。insert时调用
	link_type create_node(const T& x) {
		link_type p = get_node();
		construct(&p->data, x);	//很重要调用place new构造函数;
		return p;
	}
	// 释放一个节点 erase时调用
	void destroy_node(link_type p) {
		 //很重要调用析构函数 
		//inline void destroy(T* pointer) {
		//pointer->~T();	// 喚起 dtor ~T()
		destroy(&p->data); 	   
		put_node(p);		// 释放内存给内存池
	}

protected:
	//双向环形链表,永远指向最后一个节点的下一个节点,以及第一个节点的上一个节点
	//空节点,哨兵节点
	//容器内唯一一个元素
	link_type node; 
	
	//容器的节点的初始化
	list() { empty_initialize(); }  
	void empty_initialize() {
		node = get_node();	// 申请一个节点
		node->next = node;	// 令头尾都指向自己不设元素值
		node->prev = node;
	}
	//容器内保存的节点的下一个节点是第一个节点
	iterator begin() { return (link_type)((*node).next); }
	//end是尾节点的下一个节点,也就是容器内保存的节点
	iterator end() { return node; }
	
	//常见函数实现
	// 往头结点前插入一个元素
	void push_front(const T& x) { insert(begin(), x); }
	// 往尾节点插入一个元素,end()之前也就是最后一个节点的后面
	void push_back(const T& x) { insert(end(), x); }
		
	// 移除头结点
	void pop_front() { erase(begin()); }
	// 移除尾节点,容器节点是尾节点的下一个,所以移除(--tmp)
	void pop_back() {
		iterator tmp = end();
		erase(--tmp);
	}
	
	//向位置position之前插入一个元素
	iterator insert(iterator position, const T& x) {
		link_type tmp = create_node(x); // 申请一个节点,data数据为x
		// 调整节点内的两个指针(总共需要调整四个指针的指向,position的prev tmp的prev和next,position.prev的next)
		//tmp的next指向position
		tmp->next = position.node;
		//tmp的pre指针指向position的prev;
		tmp->prev = position.node->prev;
		//position上个节点的next指针指向tmp
		(link_type(position.node->prev))->next = tmp;
		//position的prev执行tmp
		position.node->prev = tmp;
		return tmp;
	}
	// 移除迭代器 position 所指节点
	iterator erase(iterator position) {
		link_type next_node = link_type(position.node->next);
		link_type prev_node = link_type(position.node->prev);
		//移除需要调整两个指针(position上一个节点的next,以及position下一个节点的pre)
		prev_node->next = next_node;
		next_node->prev = prev_node;
		//移除节点
		destroy_node(position.node);
		//用移除了的节点的下一个节点初始化一个迭代器并返回
		return iterator(next_node);
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值