【C++ 第七章】模拟实现 list 类模板

0、前言:

类中的 list 是双向带头循环链表

我们这里模拟实现的 list 也是 双向带头循环链表


1、list 的核心框架实现(list 类模板)

1.1 节点类模板  和  链表类模板

1.1.1 节点类

双向链表节点(含有 prev 指针 和 next 指针)

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

	Node* _next;
	Node* _prev;
	T _data;

	// 构造函数
	ListNode(const T& data = T())
		:_data(data)
		, _next(nullptr)
		, _prev(nullptr)
	{}
};
【思考】为什么 节点类 用的是 struct ,而不是 class?

先说明:struct 和 class 的区别

因为 struct 在 C++语法中,和 class 都可以表示类

struct 是C++兼容 C语言的 语法

在 C++中 struct 的类,没有访问限定符的限制

所有成员一律 视为公有

再说明:为什么节点类要用 struct

        依据C语言学过的链表,在一个链表节点中,指向前后节点的指针和存储该节点数据的变量 都需要频繁的被外界访问(_next、_prev、_data),与其在 class 中使用 public 访问限定符,不如干脆直接使用 struct ,使该类中的所有成员都可被外界直接,提高便捷性


1.1.2 链表类

带头链表:含有一个 哨兵位节点,成员变量 _head 指向该哨兵位节点

template<class T>
class list
{
	typedef ListNode<T> Node; // 将节点类型重命名


private:
	Node* _head; 
};

1.2 构造函数

作用:初始化一个 头节点(即哨兵位)

// 构造函数:创建头节点

list() {
	empty_list();
	_head = new Node();
	_head->_next = _head;
	_head->_prev = _head;

	// 注意:_next 和 _prev 都是指向 _head,不是 nullptr !!!,否则 push_back 时会 有访问空指针的问题

}

2. 迭代器类模板(重点:理解迭代器思想)

2.1 迭代器思想与封装思想

        你一个内置类型,无法完成的操作与行为,可以将该类型封装成一个类,在类里面重载各种运算,使这个内置类型间接拥有之前没有 “功能”

例如:

在链表中,有指向一个节点的指针 Node* _node;

        这个指针是不能直接通过 ++ 操作,跳转到下一个节点的(链表空间不连续,不能像 vector 一样通过 原生指针 T* 的 ++操作 到达下一个元素位置)

        此时可以将该指针封装成一个类,在类里面重载++操作,间接的使指针 _ node 有了 [ 指针++ ] 就跳转到下个节点的 功能(因为重载函数中的操作:_node = _ node-> _next; 使 _node 指向下一个节点位置)

 
template<class T>
 struct NewPtr
 {
     typedef ListNode<T> Node;
     typedef NewPtr<T> Self;  // 自己这种类型
 ​


     
     Node* _node;   // 核心还是 一个链表节点指针
 ​  


 ​
     // 构造函数
     // 这里的 p 不用给 const ,否则权限放大
     NewPtr(Node* p = nullptr)
         :_node(p)
     {}
 ​
 ​
     Self& operator++() {
         _node = _node->_next;
         return *this;
     }
 };

小结:

内置类型不能直接使用的行为,我们可以将这个内置类型封装成一个类型,在类型中通过重载运算符控制它的行为

因此:将 list 的节点指针 封装成一个迭代器类,使该指针拥有某些之前无法单独实现的 功能

迭代器的表面上是一个类型的壳

在内心实际上是一个节点的指针


2.2 链表的迭代器 ListIterator

按上面的逻辑:设计链表的迭代器 ListIterator

// 迭代器就是将指向一个节点的指针 node 封装成一个类

template<class T>
struct ListIterator
{
	typedef ListNode<T> Node;
	typedef ListIterator<T> Self;  // 自己这种类型



	Node* _node;



	// 构造函数
	// 这里的 p 不用给 const ,否则权限放大
	ListIterator(Node* p = nullptr)
		:_node(p)
	{}



	// ++  --
	Self& operator++() {
		_node = _node->_next;
		return *this;
	}
};
面向对象程序设计课程作业 1. 请创建一个数据类型为T的链表类模板List实现以下成员函数: 1) 默认构造函数List(),将该链表初始化为一个空链表(10分) 2) 拷贝构造函数List(const List& list),根据一个给定的链表构造当前链表(10分) 3) 析构函数~List(),释放链表中的所有节点(10分) 4) Push_back(T e)函数,往链表最末尾插入一个元素为e的节点(10分) 5) operator<<()友元函数,将链表的所有元素按顺序输出(10分) 6) operator=()函数,实现两个链表的赋值操作(10分) 7) operator+()函数,实现两个链表的连接,A=B+C(10分) 2. 请编写main函数,测试该类模板的正确性: 1) 用List模板定义一个List类型的模板类对象int_listB,从键盘读入m个整数,调用Push_back函数将这m个整数依次插入到该链表中;(4分) 2) 用List模板定义一个List类型的模板类对象int_listC,从键盘读入n个整数,调用Push_back函数将这n个整数依次插入到该链表中;(4分) 3) 用List模板定义一个List类型的模板类对象int_listA,调用List的成员函数实现A = B + C;(4分) 4) 用cout直接输出int_listA的所有元素(3分) 5) 用List模板定义List类型的模板类对象double_listA, double_listB, double_listC,重复上述操作。(15分) 3. 输入输出样例: 1) 输入样例 4 12 23 34 45 3 56 67 78 3 1.2 2.3 3.4 4 4.5 5.6 6.7 7.8 2) 输出样例 12 23 34 45 56 67 78 1.2 2.3 3.4 4.5 5.6 6.7 7.8
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值