C++list

  list是个双向链表。      

C++list_第1张图片

底层是带头双向循环链表。

元素访问没有[]了,意味着以后大部分需要使用迭代器进行访问。

C++list_第2张图片

 先试着写一下代码。

#include
using namespace std;
void test1()
{
	list lt;
	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);
	list::iterator it = lt.begin();
	while(it != lt.end())
	{
		cout << *it << endl;
		it++;
	}
	for (auto c : lt)
	{
		cout << c << endl;
	}
}
int main()
{
	test1();
	return 0;
}

到着遍历可以用反向迭代器。

C++list_第3张图片

 const对象调用const迭代器。


C++list_第4张图片

没有reserve和resize了,因为链表是按需要申请和释放空间的。 


获取头和尾的数据 。


如果pop_back的数量大于结点数量,会报错。

C++list_第5张图片

C++list_第6张图片


list中没有find()模板,需要调用algorithm库中的find。

#include
#include
#include
using namespace std;
void test2()
{
	list lt;
	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);
	auto pos = find(lt.begin(), lt.end(), 3);
	if (pos != lt.end())
	{
		lt.insert(pos, 30);
	}
	for (auto i : lt)
	{
		cout << i <<" ";
	}
	cout << endl;
}
int main()
{
	test2();
	return 0;
}

 C++list_第7张图片

不失效。 

 但erase后,pos会失效,因为此时pos位置结点已经没了。


底层是快速排序。 

C++list_第8张图片

链表sort底层是归并排序。

为什么链表有自己的sort? 

C++list_第9张图片

 vector和string属于随机。 

C++list_第10张图片

底层是快速排序。 

它俩能够相减,需要迭代器是连续的,而链表迭代器不连续。

链表list要排序只能使用list的sort了。

用库里面sort对vector排序要比list中的sort对链表排序快。

C++list_第11张图片

平时头插和头删最好不用vector 。


remove一个对象中没有的数,不会报错。

C++list_第12张图片


利用unique进行去重,必须先保证链表数据有序。

C++list_第13张图片


合并

C++list_第14张图片

但在合并前,需要保证两个列表数据都是有序的,否则会报错。 


void test3()
	{
		list lt;
		lt.push_back(1);
		lt.push_back(2);
		lt.push_back(3);
		lt.push_back(4);
		lt.push_front(5);
		lt.push_front(6);

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

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

		lt.clear();
		for (auto e : lt)
		{
			cout << e << " ";
		}
		cout << endl;
	}

这个代码,我们需要写个深拷贝构造函数,因为默认拷贝构造函数是个浅拷贝,lt被clear后,地址被释放了一次,lt1出函数时,地址又被释放了一次,它俩是相同的地址,被释放两次,所以会报错。


简单模拟实现下list 

#include
#include
#include
#include
#include

namespace bit
{
	using namespace std;

	template
	struct list_node
	{
		list_node* _next;
		list_node* _prev;
		T _data;
		list_node(const T& x)
			:_next(nullptr)
			, _prev(nullptr)
			, _data(x)
		{}
	};
	template
	struct list_iterator
	{
		typedef list_node  node;
		typedef list_iterator self;
		node* _pnode;
		list_iterator(node* p)
			:_pnode(p)
		{}
		Ref operator*()
		{
			return _pnode->_data;
		}
		self& operator++()
		{
			_pnode = _pnode->_next;
			return *this;
		}
		self& operator--()
		{
			_pnode = _pnode->_prev;
			return *this;
		}
		bool operator!=(const self& e)
		{
			return _pnode != e._pnode;
		}
	};
	template
	class list
	{
	public:
		typedef list_node node;
		typedef list_iterator iterator;
		typedef list_iterator const_iterator;
		list()
		{
			empty_initialize();
		}

		const_iterator begin()const
		{
			return const_iterator(_head->_next);
		}
		const_iterator end()const
		{
			return const_iterator(_head);
		}
		iterator begin()
		{
			return iterator(_head->_next);
		}
		iterator end()
		{
			return iterator(_head);
		}
		iterator insert(iterator pos, const T& n)
		{
			node* newnode = new node(n);
			node* cur = pos._pnode;
			node* prev = cur->_prev;
			newnode->_next = cur;
			newnode->_prev = prev;
			prev->_next = newnode;
			cur->_prev = newnode;
			return iterator(newnode);
		}
		iterator erase(iterator pos)
		{
			assert(pos != end());

			node* prev = pos._pnode->_prev;
			node* next = pos._pnode->_next;
			prev->_next = next;
			next->_prev = prev;
			delete pos._pnode;

			return iterator(next);
		}
		list& operator=(const list& lt)
		{
			if (this != <)
			{
				clear();
				for (const auto& e : lt)
				{
					push_back(e);
				}
			}
			return *this;
		}
		void push_front(const T& x)
		{
			insert(begin(), x);
		}
		void  pop_front()
		{
			erase(begin());
		}
		void pop_back()
		{
			erase(--end());
		}
		void clear()
		{
			iterator it = begin();
			while (it != end())
			{
				it = erase(it);
			}
		}
		/*list(const list& lt)
		{
			_head = new node(T());
			_head->_next = _head;
			_head->_prev = _head;
			for (const auto &e : lt)
			{
				push_back(e);
			}
		}*/
		void empty_initialize()
		{
			_head = new node(T());
			_head->_next = _head;
			_head->_prev = _head;
		}
		~list()
		{
			clear();
			delete _head;
			_head = NULL;
		}
		void push_back(const T& e)
		{
			/*node* NEW = new node(e);
			node* tail = _head->_prev;
			tail->_next = NEW;
			NEW->_next = _head;
			_head->_prev = NEW;
			NEW->_prev = tail;*/
			insert(end(), e);

		}


	private:
		node* _head;
	};
	void test1_1(const list& lt1)
	{
		list::const_iterator it1 = lt1.begin();
		cout << "lt1::";
		while (it1 != lt1.end())
		{
			cout << *it1 << " ";
			++it1;
		}
		cout << endl;
	}
	void test1()
	{
		list lt1;
		lt1.push_back(1);
		lt1.push_back(2);
		lt1.push_back(3);
		lt1.push_back(4);
		lt1.push_back(5);

		list::iterator it = lt1.begin();

		cout << "lt1:";
		while (it != lt1.end())
		{
			cout << (*it)++ << " ";
			++it;
		}
		cout << endl;
		cout << "lt1:";
		for (auto e : lt1)
		{
			cout << e;

		}

		lt1.insert(lt1.end(), 7);

		cout << endl;
		cout << "lt1:";
		for (auto e : lt1)
		{
			cout << e;
		}
		cout << endl;
		list lt2 = lt1;
		lt1.erase(--lt1.end());
		lt1.erase(--lt1.end());
		cout << "lt1::";
		for (auto e : lt1)
		{
			cout << e;
		}
		cout << endl;
		cout << "lt2::";
		for (auto e : lt2)
		{
			cout << e;
		}
		cout << endl;

		lt2 = lt1;
		cout << "lt1::";
		for (auto e : lt1)
		{
			cout << e;
		}
		cout << endl;
		cout << "lt2::";
		for (auto e : lt2)
		{
			cout << e;
		}
		cout << endl;
		test1_1(lt1);
		lt1.push_front(8);
		cout << "lt1::";
		for (auto e : lt1)
		{
			cout << e;
		}
		cout << endl;

		lt1.pop_front();
		cout << "lt1::";
		for (auto e : lt1)
		{
			cout << e;
		}
		cout << endl;
		lt1.pop_back();
		cout << "lt1::";
		for (auto e : lt1)
		{
			cout << e;
		}
		cout << endl;
		lt2.clear();
		cout << "lt2::";
		for (auto e : lt2)
		{
			cout << e;
		}
		cout << endl;
	}

}
int main()
{
	bit::test3();
	return 0;
}

C++list_第15张图片

 C++list_第16张图片

构造函数名和类名相同,list是类名,所以不写list,因为这是个类型。 

在类模板内部类型等同于类名,但了解就行,我们尽量不用。

C++list_第17张图片


C++list_第18张图片

 c++中的cout起到了针对自定义类型输出的作用。


因为这个,所以需要提供默认构造。

C++list_第19张图片

C++list_第20张图片


C++list_第21张图片  

C++list_第22张图片

写两个箭头反而是错的。

C++list_第23张图片

 可以这样写

C++list_第24张图片


当我们用const迭代器对数据修改时,发现它可以修改。这就出现了问题。

C++list_第25张图片

 C++list_第26张图片

 这是因为我们的->运算符重载返回的是T*,我们需要把返回值变为const T*,这样结构体内的数据就不能修改了。

注意T*const,时是指针指向不能修改,而指针指向的结构体中的数据能被修改。

C++list_第27张图片

我们再加个模板参数就能解决。

 C++list_第28张图片

 C++list_第29张图片

 从上述过程,我们也看出了typedef的优势。

来看下完整代码。

#include
#include
#include
#include
#include

namespace bit
{
	using namespace std;

	template
	struct list_node
	{
		list_node* _next;
		list_node* _prev;
		T _data;
		list_node(const T& x)
			:_next(nullptr)
			, _prev(nullptr)
			, _data(x)
		{}
	};
	template
	struct list_iterator
	{
		typedef list_node  node;
		typedef list_iterator self;
		node* _pnode;
		list_iterator(node* p)
			:_pnode(p)
		{}
		Ref operator*()
		{
			return _pnode->_data;
		}
		self& operator++()
		{
			_pnode = _pnode->_next;
			return *this;
		}
		self& operator++(int)
		{
			self tmp(*this);
			_pnode = _pnode->_next;
			return tmp;
		}
		self& operator--()
		{
			_pnode = _pnode->_prev;
			return *this;
		}
		Ptr operator->()
		{
			return &_pnode->_data;
		}
		bool operator!=(const self& e)
		{
			return _pnode != e._pnode;
		}
	};
	template
	class list
	{
	public:
		typedef list_node node;
		typedef list_iterator iterator;
		typedef list_iterator const_iterator;
		list()
		{
			empty_initialize();
		}	

		const_iterator begin()const
		{
			return const_iterator(_head->_next);
		}
		const_iterator end()const
		{
			return const_iterator(_head);
		}
		iterator begin()
		{
			return iterator(_head->_next);
		}
		iterator end()
		{
			return iterator(_head);
		}
		iterator insert(iterator pos, const T& n)
		{
			node* newnode = new node(n);
			node* cur = pos._pnode;
			node* prev = cur->_prev;
			newnode->_next = cur;
			newnode->_prev = prev;
			prev->_next = newnode;
			cur->_prev = newnode;
			return iterator(newnode);
		}
		iterator erase(iterator pos)
		{
			assert(pos != end());

			node* prev = pos._pnode->_prev;
			node* next = pos._pnode->_next;
			prev->_next = next;
			next->_prev = prev;
			delete pos._pnode;
			pos._pnode;
			return iterator(next);
		}
		/*list& operator=(const list& lt)
		{
			if (this != <)
			{
				clear();
				for (const auto& e : lt)
				{
					push_back(e);
				}
			}
			return *this;
		}*/
		void push_front(const T& x)
		{
			insert(begin(), x);
		}
		void  pop_front()
		{
			erase(begin());
		}
		void pop_back()
		{
			erase(--end());
		}
		void clear()
		{
			iterator it = begin();
			while (it != end())
			{
				it = erase(it);
			}
		}
		/*list(const list& lt)
		{
			_head = new node(T());
			_head->_next = _head;
			_head->_prev = _head;
			for (const auto &e : lt)
			{
				push_back(e);
			}
		}*/
		template 
		list(inter begin, inter end)
		{
			_head = new node(T());
			_head->_next = _head;
			_head->_prev = _head;
			while (begin != end)
			{
				push_back(*begin);
				++begin;
			}	
		}
		void swap(list& tmp)
		{
			std::swap(_head, tmp._head);
		}
		list(const list& lt)
		{
			empty_initialize();
			list tmp(lt.begin(), lt.end());
			swap(tmp);
		}
		list operator=(list lt)
		{
			swap(lt);
			return *this;
		}
		void empty_initialize()
		{
			_head = new node(T());
			_head->_next = _head;
			_head->_prev = _head;
		}
		~list()
		{
			clear();
			delete _head;
			_head = NULL;
		}
		void push_back(const T& e)
		{
			/*node* NEW = new node(e);
			node* tail = _head->_prev;
			tail->_next = NEW;
			NEW->_next = _head;
			_head->_prev = NEW;
			NEW->_prev = tail;*/
			insert(end(), e);

		}


	private:
		node* _head;
	};
	struct Pos
	{
		
		Pos(int row = 0, int col = 0)
			:row(row)
			, col(col)
		{}
		int row;
		int col;
	};
	void test1_2(const list& lt1)
	{
		list::const_iterator it1 = lt1.begin();
		cout << "lt1::";
		while (it1 != lt1.end())
		{
			cout << it1->row << ":" << (*it1).col;
			cout << endl;
			++it1;
		}
		
	}
	void testpos()
	{
		list p1;
		p1.push_back(Pos(1, 1));
		p1.push_back(Pos(2, 2));
		p1.push_back(Pos(3, 3));
		p1.push_back(Pos(4, 4));
		list::iterator it = p1.begin();
		while (it != p1.end())
		{
			//cout << (*it).row << ":" << (*it).col;
			cout << it->row << ":" << (*it).col;

			cout << endl;
			++it;
		}
		test1_2(p1);
	}
	

	
}
int main()
{
	bit::testpos();
	return 0;
}

C++list_第30张图片

初始化列表如果不显示初始化, 自定义类型会调用默认构造函数,内置类型需要自己给缺省值,或在初始化列表显示初始化,否则会被初始化为随机值。

对于析构而言,编译器对自定义类型调用析构函数,对于内置类型不处理。编译器也不敢处理。

比如list的头指针。因为list它不仅有头结点。只处理头结点会出错。

C++list_第31张图片


迭代器我们没有写析构函数,_pnode也不会自动释放。 

C++list_第32张图片

另外之前我们自己模拟实现的迭代器的拷贝构造 其实是浅拷贝。

两个容器指向同一个空间。因为_pnode并不释放,所以浅拷贝不会出问题。

不需要显示写析构,就不需要显示写拷贝构造和赋值。

C++list_第33张图片

你可能感兴趣的:(C++,c++,开发语言)