C++之list

list是链表的意思,由一个个节点组成

一、基本接口使用:

(1)与vector相同,有个尾插,也可以使用迭代器遍历:

cpp 复制代码
void test_list1()
{
	list<int> lt;
	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);

	list<int>::iterator it = lt.begin();
	while (it != lt.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;

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

	//假如要删除指定位置的数据:
	//it = lt.begin();
	//lt.erase(it + 3);//物理空间不连续找不到指定位置
}

(2)emplace_back:也是插入,但是和尾插有区别:

假设有一个类A:

cpp 复制代码
struct A
{
public:
	A(int a1 = 1, int a2 = 1)
		:_a1(a1)
		,_a2(a2)
	{}
	int _a1;
	int _a2;

};

插入A对象的数据:

cpp 复制代码
void test_list2()
{
	list<A> lt1;
	A aa1(1, 1);
	lt1.push_back(aa1);
	lt1.push_back(A(2,2));
	lt1.emplace_back(aa1);
	lt1.emplace_back(A(2, 2));
}

但是emplace_back支持直接传构造A对象的参数,push_back不支持:

cpp 复制代码
void test_list2()
{
	list<A> lt1;
	A aa1(1, 1);
	lt1.push_back(aa1);
	lt1.push_back(A(2,2));
	lt1.emplace_back(aa1);
	lt1.emplace_back(A(2, 2));

	//lt.push_back(3, 3);//不支持这样写
	lt1.emplace_back(3, 3);
}

(3)查询某个值并删除:

cpp 复制代码
void test_list3()
{
	list<int> lt;
	lt.push_back(1);
	lt.emplace_back(2);
	lt.emplace_back(3);
	lt.emplace_back(4);
	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;

	//删除某个值:
	int x;
	cin >> x;
	//找到x:
	auto it = find(lt.begin(), lt.end(), x);
	if (it != lt.end())
	{
		lt.erase(it);
	}

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

(4)排序:sort()默认是升序,要实现降序可以使用仿函数greater<int> ls,less<int> ls用于升序。lt.sort(ls),这样就可以实现降序。也可以直接传匿名对象lt.sort(greater<int>())。

cpp 复制代码
void test_list4()
{
	list<int> lt;
	lt.push_back(1);
	lt.push_back(20);
	lt.push_back(3);
	lt.push_back(5);
	lt.push_back(4);
	lt.push_back(6);
	lt.push_back(1);

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

	//排序:
	lt.sort();//默认实现升序

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

	//降序,使用仿函数
	//less<int> ls;//用于升序
	//greater<int> ls;//用于降序
	//两个都是类模板
	//lt.sort(ls);//这样就实现了降序
	//也可以直接传匿名对象:
	lt.sort(greater<int>());

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

(5)两个链表合并:使用merge函数传合并的对象,最后传的对象内部会空。

cpp 复制代码
void test5()
{
	//两个链表合并:
	list<double> first, second;
	first.push_back(3.1);
	first.push_back(2.2);
	first.push_back(2.9);

	second.push_back(3.7);
	second.push_back(7.1);
	second.push_back(1.4);

	first.sort();
	second.sort();

	//合并:
	first.merge(second);//取小的尾插,second最后空了
}

(6)去重:

cpp 复制代码
void test_list6()
{
	list<int> lt;
	lt.push_back(1);
	lt.push_back(20);
	lt.push_back(5);
	lt.push_back(5);
	lt.push_back(4);
	lt.push_back(6);
	lt.push_back(1);

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

	//去重,先排序:
	lt.sort();
	lt.unique();

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

(7)剪切:有两个链表对象1和2,将2的值剪切到1里面去,最后2会空。

cpp 复制代码
void test_list7()
{
	list<int> mylist1,mylist2;
	list<int>::iterator it;

	for (int i = 1; i <= 4; i++)
		mylist1.push_back(i);
	for (int i = 1; i <= 4; i++)
		mylist2.push_back(i * 10);



	it = mylist1.begin();
	it++;

	mylist1.splice(it, mylist2);//将2的所有值剪切到1里面去

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

二、实现一个链表:

(1) 一个链表需要一个类来表示节点,还要一个类来实现链表的链接。

cpp 复制代码
template <class T>
struct list_node//节点
{
	T _data;
	list_node<T>* _next;
	list_node<T>* _prev;

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

};
template <class T>
class list
{
	typedef list_node<T> Node;
public:
	list()
	{
		empty_init();
	}

	void empty_init()
	{
		_head = new Node();
		_head->_next = _head;
		_head->_prev = _head;
		_size = 0;
	}
	size_t size()const 
	{
		return _size;
	}
	bool empty()const
	{
		return _size == 0;
	}
private:
	Node* _head;
	size_t _size;
};

用_size来记录节点的个数。

(2)基本的实现:

cpp 复制代码
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;
}

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

void insert(iterator pos, const T& x)
{
	Node* cur = pos._node;
	Node* prev = cur->_prev;

	Node* newnode = new Node(x);

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

	++_size;

}

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

void front_back()
{
	erase(begin);
}

(3)迭代器实现:由于链表在内存内部是不连续的,所以用迭代器的指针无法去直接++或者--,想要实现迭代器的基本功能必须对其他的运算符进行重载。需要写一个专门的类去封装迭代器。使用struct去定义类默认的成员都是公有,这样可以省事很多,方便之后的调用。

首先是重载*,需要返回内部的值,++则是返回下一个节点,--则是返回前一个节点。++和--分为前置和后置,后置则要返回原来的值。

cpp 复制代码
struct list_iterator//默认是公有
{
	typedef list_node<T> Node;
	typedef list_iterator<T> Self;
	Node* _node;

	list_iterator(Node* node)
		:_node(node)
	{}
	
	T& operator*()//重载*
	{
		return _node->_data;
	}

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

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

	bool operator !=(const Self& s)//两个迭代器比较
	{
		return _node != s._node;
	}
};
相关推荐
蜡笔小新..11 分钟前
R语言和RStudio安装
开发语言·r语言
ALPH_12 分钟前
R语言的基础命令及实例操作
开发语言·数据分析·r语言·perl·r语言-4.2.1
咩咩觉主16 分钟前
C# &Unity 唐老狮 No.6 模拟面试题
开发语言·unity·面试·c#·游戏引擎·唐老师
*.✧屠苏隐遥(ノ◕ヮ◕)ノ*.✧3 小时前
C语言_数据结构总结8:链式队列
c语言·开发语言·数据结构·链表·visualstudio·visual studio
千里码aicood3 小时前
[含文档+PPT+源码等]精品基于Python实现的校园小助手小程序的设计与实现
开发语言·前端·python
大麦大麦3 小时前
深入剖析 Sass:从基础到进阶的 CSS 预处理器应用指南
开发语言·前端·css·面试·rust·uni-app·sass
hhw1991124 小时前
c#面试题整理6
java·开发语言·c#
Icomi_4 小时前
【神经网络】0.深度学习基础:解锁深度学习,重塑未来的智能新引擎
c语言·c++·人工智能·python·深度学习·神经网络
蠟筆小新工程師4 小时前
Deepseek可以通过多种方式帮助CAD加速工作
开发语言·python·seepdeek