C++ 【list】

list的基本介绍

1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。

2. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。

3. list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高 效。

4. 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率 更好。

5. 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list 的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间 开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这 可能是一个重要的因素)

list的函数接口

std::list是C++标准模板库(STL)中的一个双向链表容器。它可以存储任何数据类型,并提供了一系列方法来方便地操作链表。

以下是std::list的一些常用方法:

push_back(数据):在链表末尾添加一个元素。

push_front(数据):在链表头部添加一个元素。

pop_back():从链表末尾删除一个元素。

pop_front():从链表头部删除一个元素。

insert(迭代器,数据):在链表中的任意位置插入一个元素。

remove():删除链表中所有与指定的元素相等的元素。

erase(迭代器):删除链表中的一个或多个元素。

clear():删除链表中的所有元素。

size():返回链表中元素的数量。

empty():检查链表是否为空。

以下是一个使用std::list的示例代码:

#include <iostream>
#include <list>

int main() {
    std::list<int> myList; // 声明一个整型链表

    // 在链表末尾添加元素
    myList.push_back(1);
    myList.push_back(2);
    myList.push_back(3);

    // 在链表头部添加元素
    myList.push_front(0);

    // 输出链表中的元素
    for (auto it = myList.begin(); it != myList.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

    // 在链表中间插入一个元素
    auto it = myList.begin();
    ++it; // 指向第二个元素
    myList.insert(it, 100);

    // 删除链表中的一个元素
    it = myList.begin();
    ++it; // 指向第二个元素
    myList.erase(it);

    // 输出链表中的元素
    for (auto& elem : myList) {
        std::cout << elem << " ";
    }
    std::cout << std::endl;

    return 0;
}

输出结果为:

0 1 2 3
0 2 3

可以看到,std::list提供了很多方便的方法来操作链表,使用起来非常灵活和方便。

list模拟实现

list_node(节点)

template <class T>
	struct list_node
	{//节点
		list_node* _prev;
		list_node* _next;
		T _data;
	};

链表迭代器

//迭代器实现
	template<class T,class Ref>
	struct list_iterator
	{
		typedef list_node<T> node;
		node* _node;
		list_iterator(node* it)
		{
			_node = it;
		}
		//先把list_node重命名,然后创建node*
		//重载++、!=、*
		list_iterator<T,Ref>& operator++()
		{//++
			_node= _node->_next;
			return *this;//这里重点看一下,我当初实现的时候各种错误
		}
		//后置++
		list_iterator<T,Ref> operator++(int)
		{
			list_iterator<T,Ref> tem(*this);
			_node = _node->_next;
			return tem;
		}
		//前置--
		list_iterator<T,Ref>& operator--()
		{
			_node = _node->_prev;
			return *this;
		}
		//后置--
		list_iterator<T,Ref> operator--(int)
		{
			list_iterator<T,Ref> tem(*this);
			_node = _node->_prev;
			return tem;
		}
		Ref operator*()
		{//*引用重载
			return _node->_data;
		}
		bool operator!=(const list_iterator<T,Ref>& it )
		{
			return _node != it._node;
		}
		//重载->
		T* operator->()
		{
			return &(_node->_data);
		}
	};

list(链表)模拟代码

 

template<class T>
	class List
	{//链表实现
	public:
		typedef list_node<T> node;//这一句要放到类中,不然就是错误模板
		typedef list_iterator<T,T&> iterator;//重命名迭代器
		typedef  list_iterator<T,const T&> const_iterator;
		List()
		{//链表构造
			_head = getnode();
		}
		//清除数据
		void clear()
		{
			iterator it = begin();
			while (it != end())
			{//足个删除
				it=erase(it);
			}
		}
		//析构函数
		~List()
		{
			clear();
			//复用clear,然后清除头节点就行了
			delete _head;
			_head = nullptr;
		}
		template<class iterator_create>
		List(iterator_create first,iterator_create last)
		{//迭代器构造- -同样也是构造函数
			_head = getnode();
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}
		//拷贝构造实现
		//List(const List<T>& L1)
		//{
		//	_head = getnode();
		//	for (auto e : L1)
		//	{//一个遍历直接尾插,e会自动去拿节点的值
		//		push_back(e);
		//	}
		//}
		void swap(List<T>& tem)
		{
			std::swap(_head,tem._head);
		}
		List(const List<T>& L1)
		{
			_head = getnode();
			List<T> tem(L1.begin(), L1.end());
			swap(tem);
		}
		//赋值重载
		List<T>& operator=(List<T> L1)
		{//这里的参数不能用引用
			swap(L1);
			return *this;
		}
		//创建节点函数
		node* getnode()
		{
			node* ret = new node;
			ret->_next = ret->_prev = ret;
			return ret;
		}
		iterator begin()
		{
			return iterator(_head->_next);
		}
		const_iterator begin()const
		{
			return const_iterator(_head->_next);
		}
		iterator end()
		{
			return iterator(_head);
		}
		const_iterator end()const //如果一个函数参数是const list,当list调用成员函数的时候,那么就需要this指针
		{					//你传参传的时候用const修饰了,但是内部的this指针如果你没有写const版本的成员函数,
			return const_iterator(_head);//就会存在一个权限放大的问题
		}
		void push_back(const T& x = T())
		{
			node* tem = getnode();//开辟空间
			tem->_data = x;
			//把节点插入链表.第一步找到尾,尾就是头的前一个
			node* tail = _head->_prev;
			tail->_next = tem;
			tem->_prev = tail;
			tem->_next = _head;
			_head->_prev = tem;
		}
		iterator insert(iterator pos,const T& x=T())
		{
			node* cur = pos._node;//先拿到目前位置的指针
			node* prev = cur->_prev;
			node* new_node = getnode();//建立新的节点
			new_node->_data = x;//赋值
			//插入节点
			prev->_next = new_node;
			new_node->_prev = prev;
			new_node->_next = cur;
			cur->_prev = new_node;
			//完成
			return pos;//迭代器不是节点,而是里面有一个节点的信息记住记住
		}
		iterator erase(iterator pos)
		{
			assert(pos._node != _head);
			node* cur = pos._node;//拿到该节点
			node* prev = cur->_prev;
			node* next = cur->_next;
			prev->_next = next;
			next->_prev = prev;
			delete pos._node;
			return iterator(next);
		}
	private:
		node* _head;
	};

        list介绍到此告一段落,这篇文章可以当作是c++手册的零食,没有看手册的那么枯燥,但同样也么有那么详细,你在学习list的时候,此时应该学习了并且熟练运用string跟vector。所有关于接口那一块直接一并带过了,你知道的,stl库中各种容器的接口都是类似的。

  • 18
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++ 中,list 是双向链表容器,可以用来存储和操作相同类型的数据。list 支持在任意位置插入/删除元素,但是不支持随机访问元素。 以下是 list 的一些常用操作: 1. push_front():在链表头部插入元素。 2. push_back():在链表尾部插入元素。 3. pop_front():删除链表头部元素。 4. pop_back():删除链表尾部元素。 5. insert():在指定位置插入元素。 6. erase():删除指定位置元素。 7. clear():清空整个链表。 8. size():返回链表中元素的个数。 9. empty():判断链表是否为空。 以下是 list 的一个简单示例: ```c++ #include <iostream> #include <list> using namespace std; int main() { list<int> mylist; // 在链表尾部插入元素 mylist.push_back(1); mylist.push_back(2); mylist.push_back(3); // 在链表头部插入元素 mylist.push_front(0); // 遍历链表并输出元素 for (auto it = mylist.begin(); it != mylist.end(); ++it) cout << *it << " "; cout << endl; // 删除链表头部元素 mylist.pop_front(); // 在指定位置插入元素 auto it = mylist.begin(); ++it; mylist.insert(it, 10); // 删除指定位置元素 it = mylist.begin(); ++it; mylist.erase(it); // 遍历链表并输出元素 for (auto x : mylist) cout << x << " "; cout << endl; // 清空整个链表 mylist.clear(); // 判断链表是否为空 if (mylist.empty()) cout << "The list is empty." << endl; return 0; } ``` 输出结果: ``` 0 1 2 3 0 2 3 10 The list is empty. ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值