双向线性链表

双向线性链表
双向线性链表中每个节点有一个数据域和两个指针,一个指向前向节点,另一个指向后向节点,第一个节点的前指针为空指针,最后一个节点的后指针为空指针。
双向链表的主要优点是对于任意给定的结点,可以很容易地获取其前结点和后结点,主要缺点是每个结点都需要保存prev和next两属性,因此需要更多的空间开销,同时结点的插入与删除操作也会变得更加耗时,需要更多指向操作。
见如下程序,构建一个双向线性链表及其相关函数:

#include <cstring>
#include <iostream>
#include <stdexcept>
using namespace std;
// 双向线性链表
template<typename T>
class List {                          //做成一个类模板
public:
   // 构造、析构、拷贝构造、拷贝赋值
   List(void) : m_head(NULL), m_tail(NULL) {}
   //一开始构造时为空指针,因为指针成员如果没有初始化的话就会变成野指针
   ~List(void) {
   	clear();        //把元素全部删掉
   }
   List(List const& that) :    //实现一个支持深拷贝的拷贝构造函数
   	m_head(NULL), m_tail(NULL) {
   	for (Node* node = that.m_head;
   		node; node = node->m_next)
   		push_back(node->m_data);
   }
   List& operator= (List const& rhs) {   //拷贝赋值函数
   	if (rhs != this) {
   		List list = rhs;
   		swap(m_head, list.m_head);  //交换,当调用析构函数后,既拿到了新的副本,又清除了原有的资源
   		swap(m_tail, list.m_tail);
   	}
   	return *this;
   }
   // 获取首元素的引用
   T& front(void) {
   	if (empty())
   		throw underflow_error(
   			"链表下溢!");
   	return m_head->m_data;
   }
   T const& front(void) const {  //常版本
   	return const_cast<List*> (
   		this)->front();
   }
   // 向首部压入
   void push_front(T const& data) {
   	m_head = new Node(data, NULL,
   		m_head);
   	if (m_head->m_next)
   		m_head->m_next->m_prev =
   		m_head;
   	else
   		m_tail = m_head;
   }
   // 从首部弹出
   void pop_front(void) {
   	if (empty())
   		throw underflow_error(
   			"链表下溢!");
   	Node* next = m_head->m_next;
   	delete m_head;
   	m_head = next;
   	if (m_head)
   		m_head->m_prev = NULL;
   	else
   		m_tail = NULL;
   }
   // 获取尾元素
   T& back(void) {
   	if (empty())
   		throw underflow_error(
   			"链表下溢!");
   	return m_tail->m_data;
   }
   T const& back(void) const {
   	return const_cast<List*> (
   		this)->back();
   }
   // 向尾部压入
   void push_back(T const& data) {
   	m_tail = new Node(data, m_tail);
   	if (m_tail->m_prev)
   		m_tail->m_prev->m_next =
   		m_tail;
   	else
   		m_head = m_tail;
   }
   // 从尾部弹出
   void pop_back(void) {
   	if (empty())
   		throw underflow_error(
   			"链表下溢!");
   	Node* prev = m_tail->m_prev;
   	delete m_tail;
   	m_tail = prev;
   	if (m_tail)
   		m_tail->m_next = NULL;
   	else
   		m_head = NULL;
   }
   // 删除所有匹配元素
   void remove(T const& data) {
   	for (Node* node = m_head, *next; node; node = next) {
   		next = node->m_next;
   		if (node->m_data == data) {
   			if (node->m_prev)
   				node->m_prev->m_next = node->m_next;
   			else
   				m_head = node->m_next;
   			if (node->m_next)
   				node->m_next->m_prev = node->m_prev;
   			else
   				m_tail = node->m_prev;
   			delete node;
   		}
   	}
   }
   // 清空
   void clear(void) {
   	while (!empty())
   		pop_back();
   }
   // 判空
   bool empty(void) const {
   	return !m_head && !m_tail;
   }
   // 大小
   size_t size(void) const {
   	size_t nodes = 0;
   	for (Node* node = m_head; node; node = node->m_next)
   		++nodes;
   	return nodes;
   }
   // 插入输出流
   friend ostream& operator<< (
   	ostream& os, List const& list) {
   	for (Node* node = list.m_head; node; node = node->m_next)
   		os << *node;
   	return os;
   }
private:
   // 节点
   class Node {
   public:
   	Node(T const& data, Node* prev = NULL,Node* next = NULL) :
   		m_data(data), m_prev(prev),m_next(next) {}
   	friend ostream& operator<< (ostream& os,Node const& node) { //输出
   		return os << '(' << node.m_data << ')';
   	}
   	T     m_data; // 数据
   	Node* m_prev; // 前指针
   	Node* m_next; // 后指针
   };
   Node* m_head; // 头指针
   Node* m_tail; // 尾指针
};
// 测试用例
void test(void) {
   List<int> li;
   li.push_front(30);
   li.push_front(20);
   li.push_front(10);
   li.push_front(0);
   cout << li << endl;
   ++li.front();
   cout << li << endl;
   li.pop_front();
   cout << li << endl;
   li.push_back(60);
   cout << li << endl;
   li.back()++;
   cout << li << endl;
   li.pop_back();
   cout << li << endl;
   li.remove(30);
   cout << li << endl;
}
// 进程入口
int main(void) {
   test();
   return 0;
}

执行结果如下:

(0)(10)(20)(30)
(1)(10)(20)(30)
(10)(20)(30)
(10)(20)(30)(60)
(10)(20)(30)(61)
(10)(20)(30)
(10)(20)
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值