STL list的模拟实现

不同于vector,List不是连续线性空间,

list的好处是每次插入或删除一个一个元素,就配置或释放一个元素的空间,因此,它对空间一点都不浪费,而且对于任何位置的插入或删除,list永远是时间常数。

list有一个重要性质,插入、接合操作都不会造成原有迭代器失效,这在vector中是不存在的,而list的删除操作也只有“指向被删除元素”的那个迭代器失效,其它迭代器不受影响。

List.h

#ifndef __List__
#define __List__

//STL对于区间前闭后开

//List的节点
template<class T>
struct ListNode
{
	typedef ListNode<T>* Node_p;
	Node_p _prev;
	Node_p _next;
	T _data;
	ListNode(const T& data=T() )
		:_prev(NULL)
		, _next(NULL)
		, _data(data)
	{}
};

//List中的迭代器(由于list不是线性空间结构,通用迭代器无法正常移动,所以list需要定义专门的迭代器。)
template<class T,class Ref,class Ptr>
struct Iterator
{
	typedef ListNode<T> Node, *Node_p;
	typedef Iterator<T, Ref, Ptr> Self;
	Node_p _node;

	Iterator()
	{}
	Iterator(Node_p node)
		:_node(node)
	{}
	//取节点的数值
	Ref operator*()const
	{
		return _node->_data;
	}
	/*Ptr operator->()const
	{
		return &(operator*());
	}*/
	bool operator == (const Self& x)
	{
		return (_node==x._node);
	}
	bool operator != (const Self& x)
	{
		return (_node != x._node);
	}
	Self& operator++()
	{
		_node = _node->_next;
		return *this;
	}
	Self operator++(int)
	{
		Self old = *this;
		++(*this);
		return old;
	}
	Self& operator--()
	{
		(_node = _node->_prev);
		return *this;
	}
	Self operator--(int)
	{
		Self old = *this;
		--(*this);
		return old;
	}
};

//List是一个带头结点的双向循环链表
template<class T>
class List
{
public:
	typedef Iterator<T, T&, T*> Iterator;//STL强制要求*******
private:
	typedef ListNode<T> Node, *Node_p;
	typedef T& Reference;
public:
	List()
		:_list(new Node())
	{
		_list->_next = _list;
		_list->_prev = _list;
	}
	Iterator Begin()
	{
		return Iterator(_list->_next);
	}
	Iterator End()
	{
		return Iterator(_list);
	}
	void PushBack(const T& data)
	{
		Insert(End(),data);
	}
	void PopBack()
	{
		Erase(Iterator(_list->_prev));
	}
	void PushFront(const T& data)
	{
		Insert(Iterator(_list->_next),data);
	}
	void PopFront()
	{
		Erase(Iterator(_list->_next));
	}
	//取头结点的内容(元素值)
	Reference Front()
	{
		return *Begin();
	}
	Reference Back()
	{
		return *(--End());
	}
	//在当前位置的前面插入
	void Insert(Iterator pos, const T& data)
	{
		Node_p cur = pos._node;
		Node_p prev = cur->_prev;
		Node_p next = cur->_next;
		Node_p tmp = new Node(data);
		tmp->_next = cur;
		cur->_prev = tmp;
		prev->_next = tmp;
		tmp->_prev = prev;
	}
	Iterator& Erase(Iterator pos)
	{
		Node_p cur = pos._node;
		Node_p prev = cur->_prev;
		Node_p next = cur->_next;
		prev->_next = next;
		next->_prev = prev;
		delete cur;
		return Iterator(next);
	}
	bool Empty()const
	{
		if (_list->_next == _list){
			return true;
		}
		else{
			return false;
		}
	}
	size_t Size()
	{
		int size = 0;
		Node_p start = _list->_next;
		Node_p end = _list;
		while (start != end){
			++size;
			start = start->_next;
		}
		return size;
	}
	//不支持随机访问,无[]重载

protected:
	Node_p _list;
};
#endif

Test.cpp

#include <iostream>
#include "List.h"

void Test()
{
	List<int> l;
	l.PushBack(1);
	l.PushBack(2);
	l.PushBack(3);
	l.PushBack(4);
	List<int>::Iterator ite;
	for (ite = l.Begin(); ite != l.End(); ++ite){
		std::cout << *ite << std::endl;
	}
	std::cout << l.Size() << std::endl;

	ite = l.Begin();
	l.Insert(ite,100);
	std::cout << *ite << std::endl;

	/*l.PopFront();
	l.PopBack();
	l.PushFront(78);
	l.PushFront(100);*/

	/*List<int>::Iterator it = l.Begin();
	List<int>::Iterator its = l.End();
	List<int>::Iterator item;
	std::cout<<*it<<std::endl;
	++it;
	its--;
	std::cout << (it != its) << std::endl;

	int data1 = l.Front();
	int data2= l.Back();
	std::cout<<l.Size()<<std::endl;
	std::cout << !l.Empty() << std::endl;*/
}

int main()
{
	Test();

	system("pause");
	return 0;
}
时间: 2024-08-04 03:11:23

STL list的模拟实现的相关文章

利用C++ STL的vector模拟邻接表的代码

关于vector的介绍请看 https://www.cnblogs.com/zsq1993/p/5929806.html https://zh.cppreference.com/w/cpp/container/vector 下面是利用vector模拟邻接表的演示代码: 1 #include<iostream> 2 #include<stdio.h> 3 #include<vector> 4 using namespace std; 5 #define maxN 100

南京理工大学第八届程序设计大赛(校外镜像)题解报告

总体来说,这次的题目还是不错的,不过有几题竟然是原题,着实有点让人心醉... A.偷吃糖果 Time Limit: 1000Ms Memory Limit: 65536KB Description 小鱼喜欢吃糖果.他有两盒糖果,两盒糖果分别仅由小写字母组成的字符串s和字符串t构成.其中'a'到'z'表示具体的某种糖果类别.他原本打算送给他喜欢的女生,但是要送给女孩子的话两盒糖果不能有差别(即字符串s和t完全相同).所以,他决定偷吃几块,他吃糖果的策略是每次选出一盒糖果中两个连续的同种类别的糖果,

USACO5.3 IDDFS_强连通_二维树状数组_斐蜀定理_矩形切割

启发式搜索 启发式搜索的主要思想是通过评价一个状态有"多好"来改进对于解的搜索. 方法#1:启发式剪枝 估价函数最简单最普通的用法是进行剪枝.假设有一个求最小代价的一个搜索,使用一个可行的估价函数.如果搜到当前状态时代价为A,这个状态的估价函数是B,那么从这个状态开始搜所能得到的最小代价是A+B.如果当前最优解是C满足C 方法#2:最佳优先搜索 最佳搜索可以看成贪心的深度优先搜索. 与一般搜索随意扩展后继节点不同,最优优先搜索按照估价函数所给的他们的"好坏"的顺序扩

UVa 540 小团体队列

题意:队列中有小团体(队列).当入队时,如果有该团体的元素在队列中,则新元素排到该团体的尾部,否则排到队列的尾部.出队时和正常的一样,队首元素出列. 思路:这个用STL很好模拟,用纯C的话,很直接会想到用二维数组来做,每个团体是其中的一个一维数组,最多再开一个数组来对小团体编号进行排队.但是当时没有看到题目中说的每个团体最后有1000个元素,这样的话我以为要开1000X200000的数组,忒大了~ 然后用的链表来实现.这里仍然是避免了指针和动态分配内存等易出错的东西,(不过这个方法还是把自己弄晕

[C++11][数据结构]自己的双链表实现

这个双链表,是我模仿stl的list制作的,只实现了一些基本功能,像merge,transfer这些就没有实现,用户可以用基本操作来自己做外部实现. 我没有选用stl的[begin,end)迭代器模式,而是使用传统的[head,tail].不过,为了配合stl算法,我还是加了两个begin(),end()方法,模拟了一下stl容器.模拟的还算及格,至少我可以做类似for (; begin != end; ++begin)这样的事,也可以让我的容器搭配一些stl算法,这在之后的demo里可以看到.

[SinGuLaRiTy] NOIP2017 提高组

[SinGuLaRiTy-1048] Copyright (c) SinGuLaRiTy 2018. All Rights Reserved. NOIP2017过了这么久,现在2018了才找到寒假这么一个空挡来写题解.哎,没办法,谁叫学校抓的紧呢. 序 | Before 这是我的最后一次NOIP. 因为是最后一次的原因吧,考前压力就蛮大的,再加上各种模拟赛,模板练习的轮番轰炸,走进考场时整个人都是“飘飘欲仙”的感觉~ 我的NOIP2017就在这种“飘飘欲仙”的氛围下开始了. 游记 | Blogs

HDU 4028 The time of a day STL 模拟题

暴力出奇迹.. #include<stdio.h> #include<iostream> #include<algorithm> #include<vector> #include<cmath> #include<queue> #include<set> #include<map> using namespace std; #define ll __int64 #define N 42 ll n,m,ans;

108次练习之模拟实现STL中的Vector(一)

之前敲过很多遍的Vector就不算了,从现在开始,每次将敲过的次数记下来,直至108遍为止.(瑜伽做108遍拜日,在此借助瑜伽的思想) 为什么要敲这么多次?借助NLP中的一句话:最基础的就是最精华的! 为什么偏偏要敲108遍?借助瑜伽中108遍拜日的思想. 本文仅供个人学习,总结..... 废话不多说...开干! /* *文件说明:模拟STL的Vector相关声明及实现(第1遍) *作者:高小调 *日期:2016-12-18 *集成开发环境:Microsoft Visual Studio 201

UVA - 246 10-20-30 (模拟+STL)

Description  10-20-30  A simple solitaire card game called 10-20-30 uses a standard deck of 52 playing cards in which suit is irrelevant. The value of a face card (king, queen, jack) is 10. The value of an ace is one. The value of each of the other c