双向链表List类模板的实现

双向链表List类模板的实现

1.考虑设计时需提供的类
  • List类本身,它包含连接到表两端的链、表的大小,以及一些方法。
  • Node类,可能是一个私有的内嵌类。一个节点包含数据和指向前后两个节点的两个指针,以及一些适当的构造函数。
  • const_iterator类,它抽象了位置的概念,是一个公有的内嵌类。该const_iterator存储一个指向“当前”节点的指针,并提供基本迭代器操作的实现,所有的操作,像=、==、!= 和 ++ 等,均以重载运算符的形式出现。
  • iterator类,它抽象了位置的概念,是一个公有的内嵌类。该iterator有着与const_iterator相同的功能,但operator* 返回的是所指项的引用,而不是对该项的常量引用。一个重要的技术问题是,iterator可以用在任何需要const_iterator的例程中,但反之不真。换句话说,iterator是一个const_iterator
2.List中的附加节点设计

头节点(header node): 在表的前端创建一个附加节点,逻辑上代表开始标志。
尾节点(tail node): 在表的终端创建一个终端标记(endmarker)。
使用这些附加节点的好处在于,它们通过排除一些特殊情况大大地简化了编码过程。例如,如果我们不使用头节点,那么删除第一个节点就变成了一种特殊情形,因为我们在删除期间必须重新安置链表对第一个节点的连接,还因为删除算法一般需要访问正在被删除的节点前面的节点(而没有头节点,则第一个节点就没有在它前面的节点)。

#pragma once
#include<algorithm>
template<typename Object>
class List {
private:
	struct Node {
		Object element;
		Node* pre;
		Node* next;
		Node(const Object& e=Object{ }, Node* p = nullptr, Node* n = nullptr)
			:element{e},pre{p},next{n}{}
		Node(Object&& e, Node*& p = nullptr, Node*& n = nullptr)
			:element{ std::move(e)}, pre{p}, next{n}{}
	};
	int theSize;
	Node* head;
	Node* tail;

	void init() {
		theSize = 0;
		head = new Node;
		tail = new Node;
		head->next = tail;
		tail->pre = head;
	}

public:
	//List类的内嵌const_iterator类
	class const_iterator {
	protected:
		Node* current;
		Object& retrieve()const { return current->element; };
		const_iterator(Node*p):current{p}{}

		friend class List<Object>; //赋予List类访问const_iterator的非公有成员的权力

	public:
		const_iterator():current{nullptr}{}
		const Object& operator*()const {
			return retrieve();
		}
		const_iterator& operator++() { //重载前缀自增运算符
			current = current->next;
			return *this;
		}
		/**
		*  C++规定,通过为前缀形式指定空参数表而为后缀形式指定(匿名的)单参数int来赋予他它们不同的
		* 特征。即,++itr调用零参数的operator++,而itr++调用单参数operator++。可以看出,在存在选用
		* 前缀或后缀operator++的许多场合下,前缀形式要比后缀形式更快。
		*/
		const_iterator& operator++(int) {
			const_iterator old = *this;
			++(*this);
			return old;
		}

		bool operator==(const const_iterator& rhs)const {
			return current == rhs.current;
		}
		bool operator!=(const const_iterator& rhs)const {
			return !(*this == rhs);
		}
	};

	//List类的嵌套iterator类
	class iterator :public const_iterator {
	protected:
		iterator(Node*p):const_iterator{p}{}
		friend class List<Object>;
	public:
		iterator(){}
		Object& operator*() {
			return const_iterator::retrieve();
		}
		const Object& operator*()const {
			return const_iterator::operator*();
		}
		iterator& operator++() {
			this->current = this->current->next;
			return *this;
		}
		iterator& operator++(int) {
			iterator old = *this;
			++(*this);
			return old;
		}
	};

public:
	List() { init();}
	List(const List& rhs) {
		init();
		for (auto& x : rhs)
			push_back(x);
	}
	List(List&& rhs) :theSize{ rhs.theSize }, head{ rhs.head }, tail{ rhs.tail }
	{
		rhs.theSize = 0;
		rhs.head = rhs.tail = nullptr;
	}

	~List() {
		clear();
		delete head;
		delete tail;
	}
	List& operator=(const List& rhs) {
		List copy = rhs;
		std::swap(*this, copy);
		return *this;
	}
	
	List& operator=(List&& rhs) {
		std::swap(theSize, rhs.theSize);
		std::swap(head, rhs.head);
		std::swap(tail, rhs.tail);
		return *this;
	}

	iterator begin() {
		return { head->next };
	}
	const_iterator begin()const {
		return { head->next };
	}
	iterator end() {
		return tail;
	}
	const_iterator end()const {
		return tail;
	}

	int size()const { return theSize;}
	bool empty()const { return theSize == 0;}

	void clear() {
		while (!empty())
			pop_front();
	}
	Object& front() { return *begin();}
	const Object& front()const { return *begin();}

	Object& back() { return *--end();}
	const Object& back()const { return *--end();}

	void push_front(const Object& x) {
		insert(begin(), x);
	}
	void push_front(Object&& x) {
		insert(begin(), std::move(x));
	}

	void push_back(const Object& x) {
		insert(end(), x);
	}
	void push_back(Object&& x) {
		insert(end(), std::move(x));
	}

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

	//获取一个新节点,按顺序修改指针再将新节点插入双向链表
	//在itr前插入x
	iterator insert(iterator itr, const Object& x) {
		Node* p = itr.current;
		theSize++;
		return { p->pre = p->pre->next = new Node{x,p->pre,p} };
	}
	iterator insert(iterator itr, Object&& x) {
		Node* p = itr.current;
		theSize++;
		return { p->pre = p->pre->next = new Node{std::move(x),p->pre,p}};
	}

	//从双向链表中删除由itr处的项
	iterator erase(iterator itr) {

		Node* p = itr.current;
		iterator retVal{ p->next }; //返回删除后指向该位置的迭代器,原来的itr失效
		p->pre->next = p->next;
		p->next->pre = p->pre;
		delete p;
		theSize--;
		return retVal;
	}
	iterator erase(iterator from, iterator to) {
		for (iterator itr = from; itr != to;)
			itr = erase(itr);
		return to;
	}
};
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
面向对象程序设计课程作业 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
发出的红包

打赏作者

zhugenmi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值