双向链表C++实现

在设计链表增删操作的方法时,要注意增删位置在链表中的位置,就只有三种情况,head位置,tail位置和中间位置,不同位置对指针的连接方式会有不同,一般都要用if进行判断,这些在代码中已经解释的很详细了。除此之外,在首尾进行操作时,也要对节点数量进行判断,也有三种情况,最简单的情形是空链表,其次是单节点,再就是一般的多节点情形,针对不同的情形用if进行判断,并做好指针维护即可,这些在代码中也有详细的注释。

#include<iostream>
using namespace std;

//DLLNode**************************************************************************************
template<typename T>
class DLLNode
{
public:
	DLLNode();
	DLLNode(T el, DLLNode* p=nullptr, DLLNode* n=nullptr);//重载构造函数,函数声明是可以带默认参数的
	~DLLNode();

	T info;//数据块,模板数据类型
	DLLNode* prev, * next;//指向前后方向的两个指针

private:

};

template<typename T>
DLLNode<T>::DLLNode()//默认构造函数
{
	T = nullptr;
	next = prev = nullptr;
}

template<typename T>
DLLNode<T>::~DLLNode()
{
}

template<typename T>
DLLNode<T>::DLLNode(T el, DLLNode* p , DLLNode* n )
{
	this->info = el;
	this->next = n;
	this->prev = p;
}

//DoubleLinkedList*****************************************************************************
template<typename T>
class DoubleLinkedList
{
public:
	DoubleLinkedList();
	~DoubleLinkedList();

	//与一般链表一样的操作集合
	int isEmpty()
	{
		return head == nullptr;
	}
	void addToHead(T el)//在首尾添加节点基本都要进行三种类型的判断,空,唯一节点和多节点
	{
		if (head == nullptr)
		{
			DLLNode<T>* node = new DLLNode<T>(el);//只传入了一个参数,该节点的前后指针都默认置空
			head = tail = node;//唯一节点的情形
		}
		else if (head!=nullptr)
		{
			DLLNode<T>* node = new DLLNode<T>(el,nullptr,head);//新head的前指针处传入nullptr,后指针接原来的head节点
			head->prev = node;//注意双向链表的prev指针的维护,不能漏掉!旧head的前指针指向node(以前是指向nullptr的),后指针不管
			head = node;//新head指向新添加的node
		}
	}
	void addToTail(T el)
	{
		DLLNode<T>* node = new DLLNode<T>(el, tail, nullptr);//新节点的前指针指向tail,后指针指向nullptr
		//其实先不用进行tail的nullptr判断,如果tail为空,则传入的tail也是nullptr的,因此新节点就是唯一节点,且前后指针为nullptr
		if (tail == nullptr)//证明传入新node前list是空的,这时要把head和tail指针都指向新的唯一的node
		{
			head = tail = node;
		}
		else//tail不空,则需要维护旧tail的指针,主要是更改next指针(以前是指向nullptr的),使其指向新的node,旧tail的前指针不管
		{
			tail->next = node;
			tail = node;//再将tail后移
		}
	}
	T deleteFromHead()//删除并且返回info,在首尾的操作都要先进行情况判断,然后注意双向的指针维护
	{
		T el=0;
		if (head == nullptr)//空表情形
		{
			cout << "空表,操作错误!返回-999!" << endl;
			return -999;
		}
		else
		{
			if (head == tail)//唯一节点情形
			{
				el = head->info;//取出数据
				delete head;//砍头
				head = tail = nullptr;//成空表
			}
			else//多节点情形
			{
				el = head->info;//取出数据
				DLLNode<T>* tmp = head->next;//临时指针tmp,用来保存第二个节点的地址,用于稍后赋值给新head
				tmp->prev = nullptr;//新的head的prev指针要置空
				delete head;//砍头,注意,head的空间被delete了,但是head指针还是存在,需要维护
				head = tmp;//将head指针移动到新头结点上
			}
		}
		return el;//别忘了返回值
	}
	T deleteFromTail()
	{
		T el=0;
		if (tail == nullptr)//现在应该熟练了,上来先判空
		{
			cout << "空表,操作错误!返回-999!" << endl;
			return -999;
		}
		else
		{
			if (head == tail)//再看看节点数量情况,是否是单一节点
			{
				el = tail->info;//取出数据
				delete tail;//去尾!
				head = tail = nullptr;//成空表,首尾置空
			}
			else//多节点情形
			{
				el = tail->info;//取出数据
				DLLNode<T>* tmp = tail->prev;//临时变量找出未来的新尾巴,就是倒数第二个节点
				tmp->next = nullptr;//新的tail的next指针要置空
				delete tail;//去尾!
				tail = tmp;//新tail指向以前的倒数第二个
			}
		}
		return el;
	}
	void deleteNode(T el)
	{
		DLLNode<T>* node;//用于标记的node,用于标记目标节点
		for (node = head; node->info != el && node != tail; node = node->next);//开始遍历
		if (node == tail)//list的tail是目标节点或者list中没有找到目标值el
		{
			if (node->info == el)//尾节点有目标值
			{
				deleteFromTail();//直接调用现成的函数
			}
			cout << "没有目标值,删除失败" << endl;
		}
		else//找到目标值,node所指的节点就是要删除的节点
		{
			if (node == head)deleteFromHead();//目标在头节点,直接调用现成的函数
			else//目标节点在中间
			{
				node->prev->next = node->next;
				node->next->prev = node->prev;//node前后节点的双向指针维护
				delete node;//再见了大兄弟
			}
		}
	}
	bool isInList(T el)const
	{
		DLLNode<T>* node;//用于标记的node,用于标记目标节点
		for (node = head; node->info != el && node != tail; node = node->next);//开始遍历
		if (node == tail)
		{
			if (node->info == el)return true;
			else
			{
				return false;
			}
		}
		else
		{
			return true;
		}

	}

private:
protected:
	DLLNode<T>* head, * tail;//注意类名称的写法

};

template<typename T>
DoubleLinkedList<T>::DoubleLinkedList()//默认构造函数,产生空list
{
	head = tail = nullptr;
	
}
template<typename T>
DoubleLinkedList<T>::~DoubleLinkedList()
{
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值