STL源码分析 -sList

STL源码分析 -sList

概述介绍

之前博客介绍过List,List是个双向链表,同时STL中也提供了单向链表结构,本次主要介绍单向链表节点、迭代器和单向链表实现设计。

sList的节点-node

单向链表是由每一个节点组成的,每一个节点的职责就是寻找下一个节点对象和存储当前节点对象的值,因此单向链表的节点对象中需含有next对象的指针,和当前节点对象的值。

	struct sListNodeBase {
		sListNodeBase* next;
	};
	template<typename T>
	struct sListNode :public sListNodeBase{
		T data;
	};

sList 的迭代器

单向链表的迭代器结构:

	struct sList_Iterator_Base {
		typedef size_t					size_type;
		//typedef ptrdiff_t				different_type;
		//typedef forward_iterator_tag    iterator_category;

		sListNodeBase* node;
		sList_Iterator_Base(){}
		sList_Iterator_Base(sListNodeBase* x):node(x){}

		void incr() { node = node->next; }
		bool operator== (const sList_Iterator_Base& x) { return node == x.node; }
		bool operator!= (const sList_Iterator_Base& x) { return node != x.node; }
	};

	template<typename T>
	struct sList_Iterator :public sList_Iterator_Base {
		typedef T					value_type;
		typedef T*					pointer;
		typedef T&					reference;
		typedef sListNode<T>		list_node;
		typedef sList_Iterator<T>   iterator;
		typedef sList_Iterator<T>   self;
		
		//slist_Iterator() {};
		sList_Iterator(list_node*x):sList_Iterator_Base(x){}
		sList_Iterator(const iterator &iter):sList_Iterator_Base(iter.node){}

		reference operator* ()const { return((list_node*)node)->data; }
		pointer operator->()const { &(operator*()); }
		self& operator++()
		{
			incr();
			return *this;
		}
		self operator++(int)
		{
			self temp = *this;
			incr();
			return temp;
		}
	};

因为sList是单向迭代器,即迭代器对象只实现operator++方法。iterator的实现原理如下图所示(图片来源于网上)
STL源码分析 -sList

sList 的数据结构

介绍完sList的节点对象和迭代器设计之后,我们介绍下sList的对象成员和成员函数。因为sList只需要一个头节点就可以遍历整个链表,所以sList的成员对象中只含有一个节点对象。在这里实现了sList常用的几个接口,如对象构造、析构、插入节点,pop节点等接口。并用测试代码进行验证。

	template <typename T,class Alloc = std::allocator<sListNode<T>>>
	class sList{
	public:
		typedef T					value_type;
		typedef value_type*			pointer;
		typedef const value_type	const_pointer;
		typedef value_type&			reference;
		typedef const value_type&	const_reference;
		typedef size_t				size_type;
		//typedef ptrdiff_t			difference_type;
		typedef sList_Iterator<T>	iterator;

	private:
		typedef sListNode<T>		list_node;
		typedef sListNodeBase		list_node_base;
		typedef sList_Iterator_Base iterator_base;
	private:
		list_node_base head;//头结点不存放数据
	private:
		list_node* create_node(const value_type& x)
		{
			Alloc alloc;
			list_node* p = alloc.allocate(1);//申请一个node的内存
			construct(&p->data, x);
			return p;
		}
		void destory_node(list_node* p)
		{
			destory(&p->data);
			Alloc().deallocate(p, 1);
		}
	public:
		sList() { head.next = nullptr; }
		~sList() { clear(); }//清除节点,并释放节点对象内存
		iterator begin() { return iterator((list_node*)head.next); }
		iterator end() { return iterator(nullptr); }
		bool empty() { return head.next == nullptr; }
		size_type size() { return slist_size(head.next);	}
		//两个slist交换,只需要将head 指针交换即可
		void swap(sList& L)
		{
			list_node_base tmp = head.next;
			head.next = L.head.next;
			L.head.next = tmp;
		}
		reference front()
		{
			return ((list_node*)head.next)->data;
		}
		void push_front(const_reference x)
		{
			slist_make_link(&head, create_node(x));
		}
		//从头部删除元素
		void pop_front()
		{
			list_node*node = (list_node*)head.next;
			head.next = node->next;
			destory_node(node);
		}
		void clear()
		{
			list_node* cur = (list_node*)head.next;
			while (cur != nullptr)
			{
				list_node* tmp = (list_node*)cur;
				cur = (list_node*)cur->next;
				destory_node(tmp);
			}
			head.next = nullptr;
		}
	};

测试代码

int main()
{
	//****************************test int******************************************
	std::cout << "test int: \n";
	STL::sList<int> intList;
	auto iterbegin = intList.begin();
	auto iterend = intList.end();
	intList.push_front(2);
	intList.push_front(4);
	intList.push_front(6);
	intList.push_front(8);

	iterbegin = intList.begin();
	iterend = intList.end();
	for (auto iter = intList.begin(); iter != intList.end(); ++iter)
	{
		std::cout << (*iter) << "  ";
	}
	std::cout << std::endl;
	intList.pop_front();
	intList.pop_front();
	for (auto iter = intList.begin(); iter != intList.end(); ++iter)
	{
		std::cout << (*iter) << "  ";
	}
	intList.clear();
	for (auto iter = intList.begin(); iter != intList.end(); ++iter)
	{
		std::cout << (*iter) << "  ";
	}
	//intList.reverse();
	//for (auto iter = intList.begin(); iter != intList.end(); ++iter)
	//{
	//	std::cout << (*iter) << "  ";
	//}
	//std::cout << std::endl;
	std::cout << std::endl;

	//***************************************test shared ptr obj*********************************
	std::cout << "test class object:\n";
	std::cout << "test push_front():\n";
	STL::sList<std::shared_ptr<test_class_t_obj>>listObj;
	std::cout << "listObj size :" << listObj.size() << std::endl;

	for (size_t i = 1; i < 6; i++)
	{
		auto sp_obj = std::make_shared<test_class_t_obj>(10);
		listObj.push_front(sp_obj);
		std::cout << "listObj size :" << listObj.size() << std::endl;
	}
	for (auto iter = listObj.begin(); iter != listObj.end(); ++iter)
	{
		std::cout << "list obj is: " << *iter << std::endl;
	}
	//std::cout << "test reverse():\n";
	//listObj.reverse();
	//for (auto iter = listObj.begin(); iter != listObj.end(); ++iter)
	//{
	//	std::cout << "list obj is: " << *iter << std::endl;
	//}

	std::cout << "test pop_front():\n";
	listObj.pop_front();
	listObj.pop_front();

	for (auto iter = listObj.begin(); iter != listObj.end(); ++iter)
	{
		std::cout << "list obj is: " << *iter << std::endl;
	}
	std::cout << "test clear():\n";
	listObj.clear();
	for (auto iter = listObj.begin(); iter != listObj.end(); ++iter)
	{
		std::cout << (*iter) << "  ";
	}
	std::cout << std::endl;

	return 0;
}

这里用int 类型和 class obj分别进行测试验证。本博主只是实现了少量的接口,后续会继续完善。

上一篇:String.Join的使用,让代码更优美


下一篇:线性表的基本操作