C/C++ list模拟

模拟准备

避免和库冲突,自己定义一个命名空间

namespace yx
{
	template<class T>
	struct ListNode
	{
		ListNode<T>* _next;
		ListNode<T>* _prev;

		T _data;
	};

	template<class T>
	class list
	{
		typedef ListNode<T> Node;
	public:
	

	private:
		Node* _head;
	};

	
}

这里的ListNode类为什么用struct呢?

知识点:

        class:如果类里有公有,有私有,建议用

        struct:如果一个类,全部成员不做访问限定,全公有,建议用

因为下面的list类是要经常访问ListNode的,所以建议用struct

模拟实现

 模板ListNode的构造

封装节点的数据

template<class T>
struct ListNode
{
	ListNode<T>* _next;
	ListNode<T>* _prev;

	T _data;

	ListNode(const T& data)
		:_next(nullptr)
		, _prev(nullptr)
		,_data(data)
	{

	}
};

list的构造

void list()
{
	//哨兵位
	_head = new Node;
	_head->next = _head;
	_head->prev = _head;
}

定义一个哨兵位,自己指向自己。


 

push_back( )

尾插

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 和 tail都是哨兵位(head)

迭代器

说起迭代器,我们先考虑如何遍历链表吧。

我们是否可以像vector那样呢?

typedef Node* iterator;

当然是不可以的。

vector的空间是连续的,而list的空间不连续,那我们如何获取Node*呢?

定义迭代器类

我们可以定义一个类,把节点_node封装起来,来弥补空间不连续的缺陷,能像vector那样一样来进行访问。

template<class T>
class ListIterator
{
	typedef ListNode<T> Node;

	Node* _node;
};

template定义的模板参数只能供当前类或当前函数用

而且我们可以在这个类里重载想要的东西

使用时,我们就可以给每个类规范这个迭代器使用的名字,方便我们使用

typedef ListIterator<T> iterator;
template<class T>
class ListIterator
{
	typedef ListNode<T> Node;
	typedef ListIterator<T> self; // 返回自己

	Node* _node;

	self& operator++()
	{
		_node = _node->_next;
		return *this;//返回节点自己
	}

	T& operator*()
	{
		return _node->_data;//返回数据,数据类型为T
	}

	bool operator!=(const self& it)
	{
		return _node != it._node;
	}

};

iterator begin( ) 、 iterator end( )

我们实现了迭代器,我们来实现一下链表的头指针和尾指针吧

在list类里

iterator begin()
{
	//iterator it(_head->_next);
	//return it;
	
	//我们采用匿名对象
	return iterator(_head->_next);
}
iterator end()
{
	return iterator(_head;
}

测试通过

operator->( )

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

我们来测试一下下面的代码

struct pos
{
	int _row;
	int _col;

	pos(int row = 0, int col = 0)
		:_row(row)
		, _col(col)
	{
	}
};

void test2()
{
	list<pos> lt1;
	lt1.push_back(pos(100, 100));
	lt1.push_back(pos(200, 100));
	lt1.push_back(pos(300, 100));

	list<pos>::iterator it = lt1.begin();
	while (it != lt1.end())
	{
		cout << (*it)._row << ":" << (*it)._col << " ";
		cout << it->_row << ":" << it->_col << " ";

		++it;

	}cout << endl;

}

第一种用的是对象.成员

第二种指针->成员

第一种比较好理解,it调用operator*(),返回data数据,也就是pos,然后pos._row,pos._col来访问

第二种比较绕,这里为了可读性,省略可一个->,但如果写两个的话不符合语法,于是

cout << it.operator->()->_row << ":" << it.operator->()->_col << " ";

        第一个->是operator重载的,而第二个是原生指针的解引用

const迭代器

不能是普通迭代器前面+const修饰。

如:const iterator const 

const迭代器目标本身可以修改,指向的内容不能修改 , 

类似:const T* p

p可以修改,*p不能修改

因为T* 和 T&,这里我们可以写一个和迭代器一样的const迭代器类,但我们也可以类模板,传不同的参数,形成不同的类,让编译器帮我们实现。避免了写连个差不多重复的类,减少代码量

insert( )

//在pos前插入val
iterator insert(iterator pos, const T& val)
{
	Node* pNewNode = new Node(val);
	Node* pCur = pos._node;

	pNewNode->_prev = pCur->_prev;
	pNewNode->_next = pCur;
	pNewNode->_prev->_next = pNewNode;
	pCur->_prev = pNewNode;

	return iterator(pNewNode);
}

erase( )

//删除pos节点
iterator erase(iterator pos)
{
	Node* pDel = pos._node;
	Node* pRet = pDel->_next;

	pDel->_prev->_next = pDel->_next;
	pDel->_next->_prev = pDel->_prev;
	delete pDel;

	return iterator(pRet);
}

clear()

void clear()
{
	Node* cur = _head->_next;

	while (cur != _head)
	{
		//从头开始删(从左向右)
		_head->_next = cur->_next;
		delete cur;
		cur = _head->_next;
	}

	_head->_next = _head->_prev = _head;
}

~list()

~list()
{
	clear();
	delete _head;
	_head = nullptr;
}

相关推荐

  1. MFC CList<CRect, CRect&> m_listRect;的用法

    2024-07-11 06:28:01       26 阅读
  2. 蒙特卡洛模拟

    2024-07-11 06:28:01       19 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-11 06:28:01       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-11 06:28:01       71 阅读
  3. 在Django里面运行非项目文件

    2024-07-11 06:28:01       58 阅读
  4. Python语言-面向对象

    2024-07-11 06:28:01       69 阅读

热门阅读

  1. Scikit-Learn 教程1

    2024-07-11 06:28:01       24 阅读
  2. 数据库系统安全

    2024-07-11 06:28:01       18 阅读
  3. 【技术点】嵌入式技术考点一:C语言

    2024-07-11 06:28:01       15 阅读
  4. 【Spring Boot 异常处理】

    2024-07-11 06:28:01       17 阅读
  5. Linux离线安装redis

    2024-07-11 06:28:01       24 阅读
  6. Memcached介绍和详解

    2024-07-11 06:28:01       20 阅读
  7. Python的入门知识(上)

    2024-07-11 06:28:01       22 阅读
  8. Scikit-learn高级教程:深入理解机器学习算法

    2024-07-11 06:28:01       18 阅读
  9. pip install sklearn 的错误定位与解决办法

    2024-07-11 06:28:01       20 阅读
  10. sklearn 基础教程

    2024-07-11 06:28:01       22 阅读
  11. 使用 Qt 实现自定义拖动窗口

    2024-07-11 06:28:01       23 阅读