C++ 制作自己的双向链表List,高效的模拟C# List一些主要方法

C++ 拥有自己的很多容器vector,list ,set ,map,queue,但是不少大神做了很多比较之后结论就是每一个容器都有自己适用的场景,在自己适用的场景下效率将变的很高,反之差,这几个容器虽然大致适用方式类似,但是缺多少存在一些不完美,有的不能索引,有的不方便遍历或插入,std::list已经算是比较平衡的一个容器了,但是他也没提供按索引访问,所以是时候实现了一个自己的模板了,是的没错,在C++开发中你需要一个像C#的List这样的强势集合,或者说容器模板,那么废话不多说,直接分享一下我以前项目中经过实战考研的我自己写的一个双向链表模板了

直接贴出完整实现代码实用案例:

案例用法:(未来将把对List高效的排序和分组以及去重也统统实现)

PBList<int> ggg;
	ggg.Add(1);//压入等效于RPush右侧压入
	ggg.Add(2);
	ggg.Add(3);
	ggg.Add(4);
	int a;
	ggg.LPop(a);//左侧弹出

	int &aa = ggg.Last();//取最后一个值
	aa = 8;//改变最后一个值

	int *ggh = ggg[2];//按索引取值
	PBList<int>::queue_block * block = ggg.at(2);//安索引取值
	//正向遍历输出
	ggg.ForEach([](int index, int &val, PBList<int>::queue_block * p){
		printf("%d", val);
	});
	//移除该移除的
	ggg.RemoveAll([](int &val, PBList<int>::queue_block * p){
		return val == 2;
	});

实现文件:

#pragma once

#ifndef   PBLIST_H_
#define  PBLIST_H_

#include <iostream>
#include <mutex>


template <typename T>
class  PBList{

private:
	int _size;
public:

	struct queue_block
	{
		T val;
		queue_block *next;//指向下一个
		queue_block *prev;//指向上一个

		queue_block(const T & _val)
		{
			val = _val;
			next = NULL;
		}

	};

	queue_block *first, *last;

	queue_block * at(uint32_t index){

		uint32_t _half_size = _size / 2;

		queue_block *p = NULL;

		if (index <= _half_size)
		{
			ForEach([&p,index](int i, T &a, queue_block * ent){
				if (i == index){ p = ent;  return; }
			});
		}

		else	if (index > _half_size&&index < _size)
		{
			RForEach([&p,index](int i, T &a, queue_block * ent){
				if (i == index){ p = ent;  return; }
			});
		}


		return p;
	}

	void remove(queue_block * tmp)
	{
		if (tmp->prev != NULL)tmp->prev->next = tmp->next;
		else first = tmp->next;

		if (tmp->next != NULL)tmp->next->prev = tmp->prev;
		else last = tmp->next;

		//架空tmp之后马上删除他释放之
		delete tmp;
		_size--;//长度减小
	}

public:

	PBList()
	{
		first = last = NULL;
		_size = 0;
	}

	~PBList()
	{
		queue_block * p = first;
		while (p != NULL)
		{
			queue_block *tmp = p;
			p = p->next;
			delete tmp;
		}
	}

public:

	void RPush(const T &data)
	{
		if (_size == 0)
		{
			queue_block * tmp = new queue_block(data);
			first = last = tmp;
		}
		else
		{
			queue_block * cur = last;
			queue_block * tmp = new queue_block(data);
			tmp->prev = cur;
			last = tmp;
			cur->next = tmp;
		}
		_size++;
	}

	void LPush(const T &data)//等效于AddFirst
	{
		if (_size == 0)
		{
			queue_block * tmp = new queue_block(data);
			first = last = tmp;
		}
		else
		{
			queue_block * cur = first;
			queue_block * tmp = new queue_block(data);
			tmp->next = cur;
			first = tmp;
			cur->prev = tmp;
		}
		_size++;
	}

	bool LPop(T& data)
	{
		if (_size == 0) return false;
		if (_size == 1)
		{
			queue_block * cur = first;
			first = last = NULL;
			data = cur->val;
			delete cur;
		}
		else
		{
			queue_block * cur = first;

			first = cur->next;//first转而指向下一个
			first->prev = NULL;//且指向后把上一个设为空

			data = cur->val;
			delete cur;
		}

		_size--;
		return true;
	}

	bool RPop(T& data){

		if (_size == 0) return false;
		if (_size == 1)
		{
			queue_block * cur = last;
			first = last = NULL;
			data = cur->val;
			delete cur;
		}
		else
		{
			queue_block * cur = last;

			last = cur->prev;//first转而指向下一个
			last->next = NULL;//且指向后把上一个设为空

			data = cur->val;
			delete cur;
		}

		_size--;
		return true;

	}

	void Add(const T &data){
		RPush(data);
	}

	//根据index和size比较决定正向查还是反向查
	T* operator [](uint32_t index)
	{
		queue_block * tmp = at(index);

		if (tmp == NULL)return  NULL;
		else return &tmp->val;

	}

	T& First(){
		return first->val;
	}

	T& Last(){
		return last->val;
	}

	int Length(){
		return _size;
	}

	//正向遍历
	template<typename ForEachCallback>
	void ForEach(ForEachCallback callback){

		queue_block * p = first;
		int index = 0;
		while (p != NULL)
		{
			queue_block *tmp = p;
			callback(index, p->val, tmp);
			p = p->next;
			index++;
		}
	}

	//反向遍历
	template<typename ForEachCallback>
	void RForEach(ForEachCallback callback){

		queue_block * p = last;
		int index = _size - 1;
		while (p != NULL)
		{
			queue_block *tmp = p;
			callback(index, p->val, tmp);
			p = p->prev;
			index--;
		}
	}

	//查询符合条件第一个对象,并返回对象和索引
	template<typename CondionCallback>
	T*  FindFirst(CondionCallback callback, int *resindex = NULL)
	{
		queue_block * p = first;
		int index = 0;
		while (p != NULL)
		{
			queue_block *tmp = p;
			if (callback(index, p->val) == true)
			{
				*resindex = index;
				return &p->val;
			}
			p = p->next;
			index++;
		}
		return NULL;
	}

	//查询符合条件最后一个对象,并返回对象和索引
	template<typename CondionCallback>
	T*  FindLast(CondionCallback callback, int *resindex = NULL)
	{
		queue_block * p = last;
		int index = _size - 1;
		while (p != NULL)
		{
			queue_block *tmp = p;
			if (callback(index, p->val) == true)
			{
				*resindex = index;
				return &p->val;
			}

			p = p->prev;
			index--;
		}
		return NULL;
	}


	//查询符合条件的所有对象
	template<typename CondionCallback>
	PBList<T*>	FindAll(CondionCallback callback){
		PBList<T*> hh;
		queue_block * p = first;
		while (p != NULL)
		{
			queue_block *tmp = p;
			if (callback(index, p->val) == true)
			{
				hh.Add(&p->val);
			}
			p = p->next;
		}
	}

	//删除符合条件的所有对象
	template<typename CondionCallback>
	int RemoveAll(CondionCallback callback)
	{
		queue_block * p = first;
		int count = 0;
		while (p != NULL)
		{
			queue_block *tmp = p;
			queue_block *next = p->next;
			if (callback(tmp->val, tmp) == true)
			{
				remove(tmp);
				count++;
			}
			p = next;
		}
		return count;
	}

	//删除指定索引的元素队列,根据index大小和size大小决定从哪一头
	bool RemoveAt(int index)
	{
		queue_block* tmp = at(index);
		remove(tmp);
		return true;
	}

};

#endif

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++中实现双向链表,可以按照以下步骤: 1. 定义链表节点的结构体,包括数据成员和指向前一个和后一个节点的指针。 ```c++ struct ListNode { int val; ListNode *prev; ListNode *next; ListNode(int x) : val(x), prev(nullptr), next(nullptr) {} }; ``` 2. 定义双向链表类,包括头节点和尾节点指针,以及一些基本的操作方法,如插入节点、删除节点、查找节点等。 ```c++ class DoublyLinkedList { public: DoublyLinkedList() : head(nullptr), tail(nullptr) {} void insertFront(int val) { ListNode* newNode = new ListNode(val); if (!head) { head = tail = newNode; } else { head->prev = newNode; newNode->next = head; head = newNode; } } void insertBack(int val) { ListNode* newNode = new ListNode(val); if (!tail) { head = tail = newNode; } else { tail->next = newNode; newNode->prev = tail; tail = newNode; } } void deleteNode(int val) { ListNode* cur = head; while (cur) { if (cur->val == val) { if (cur == head) { head = cur->next; if (head) head->prev = nullptr; } else if (cur == tail) { tail = cur->prev; if (tail) tail->next = nullptr; } else { cur->prev->next = cur->next; cur->next->prev = cur->prev; } delete cur; break; } cur = cur->next; } } ListNode* findNode(int val) { ListNode* cur = head; while (cur) { if (cur->val == val) return cur; cur = cur->next; } return nullptr; } private: ListNode *head; ListNode *tail; }; ``` 这样就可以通过调用双向链表方法来实现插入、删除、查找等功能了。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值