【C++】实现双向循环链表

双向链表有两个指针域,一个指向下一个节点(_next),一个则指向上一个节点(_pre)。而双向循环链表则是在双向链表的基础上,其头结点的_pre域为尾节点,尾节点的_next域则为头结点。如下图所示:

/*双向循环链表的实现*/
#include <iostream>
#include <assert.h>
using namespace std;
typedef int DataType;
typedef struct Node
{
	Node(const DataType& d)
	: _pre(NULL)
	, _next(NULL)
	, _data(d)
	{}
	Node* _pre;
	Node* _next;
	DataType _data;
}Node;
class List
{
public:
	friend ostream& operator<<(ostream& _cout, const List& list)//输出运算符的重载
	{
		Node* pcur = list._pHead;
		if (pcur == NULL)//空链表
			_cout << "over";
		else
		{
			while (pcur->_next != list._pHead)//循环少最后一个节点,需在循环外加一句
			{
				_cout << pcur->_data << "-";
				pcur = pcur->_next;
			}
			_cout << pcur->_data << "-";
			_cout << "over";
		}
		return _cout;
	}

	List()//构造函数
		:_pHead(NULL)
	{}

	List(DataType*arr, int size)//构造函数的重载
		:_pHead(NULL)
	{
		for (int i = 0; i < size; i++)
			PushBack(arr[i]);//尾插函数
	}

	List(const List& list)//拷贝构造函数
	{
		if (list._pHead == NULL)
			return;
		else
		{
			Node* pcur = list._pHead;
			while (pcur->_next != list._pHead)
			{
				PushBack(pcur->_data);
				pcur = pcur->_next;
			}
			PushBack(pcur->_data);
		}
	}

	List& operator=(const List& list)//赋值运算符的重载
	{
		if (this != &list)
		{
			Node* pcur = list._pHead;
			while (pcur->_next != list._pHead)
			{
				PushBack(pcur->_data);
				pcur = pcur->_next;
			}
			PushBack(pcur->_data);
		}
		return *this;
	}

	~List()//析构函数
	{
		Clear();//清空函数
	}

	void Clear()//清空函数
	{
		Node* pcur = _pHead;
		if (pcur == NULL)//空
			return;
		_pHead->_pre->_next = NULL;//将循环链表的最后一个节点的next置空
		Node* pre = NULL;
		while (pcur)
		{
			pre = pcur;
			pcur = pcur->_next;
			delete pre;
		}
		_pHead = NULL;
	}

	void PushBack(const DataType data)//尾插
	{
		if (NULL == _pHead)//空链表
		{
			_pHead = new Node(data);
			_pHead->_pre = _pHead;
			_pHead->_next = _pHead;
		}
		else//非空
		{
			Node* pcur = _pHead;
			pcur = pcur->_pre;
			//while (pcur->_next != _pHead)
			//	pcur = pcur->_next;
			Node* pNewNode = new Node(data);//创建节点
			pcur->_next = pNewNode;
			pNewNode->_pre = pcur;
			pNewNode->_next = _pHead;
			_pHead->_pre = pNewNode;
		}
	}

	void PopBack()//尾删
	{
		if (_pHead == NULL)//空
			return;
		else if (_pHead->_next == _pHead)//只有一个节点
		{
			delete _pHead;
			_pHead = NULL;
		}
		else//有多个节点
		{
			Node* pTailNode = _pHead->_pre;
			pTailNode->_pre->_next = _pHead;
			_pHead->_pre = pTailNode->_pre;
			delete pTailNode;
		}
	}

	void PushFront(const DataType data)//头插
	{
		if (NULL == _pHead)//空链表
		{
			_pHead = new Node(data);
			_pHead->_next = _pHead;
			_pHead->_pre = _pHead;
		}
		else//非空
		{
			Node* pNewNode = new Node(data);
			Node* pTailNode = _pHead->_pre;
			_pHead->_pre = pNewNode;
			pNewNode->_next = _pHead;
			_pHead = pNewNode;
			_pHead->_pre = pTailNode;
			pTailNode->_next = _pHead;
		}
	}

	void PopFront()//头删
	{
		if (_pHead == NULL)//空链表
			return;
		else if (_pHead->_next == _pHead)//只有一个节点
		{
			delete _pHead;
			_pHead = NULL;
		}
		else//有多个节点
		{
			/*Node* pcur = _pHead->_next;
			pcur->_pre = _pHead->_pre;
			_pHead->_pre->_next = pcur;
			delete _pHead;
			_pHead = pcur;*///将第二个节点保存
			Node* pTailNode = _pHead->_pre;//将尾节点保存,两种都可以
			_pHead = _pHead->_next;
			delete _pHead->_pre;
			_pHead->_pre = pTailNode;
			pTailNode->_next = _pHead;
		}
	}

	Node* Find(DataType data)//查找,没找到返回空
	{
		Node* pcur = _pHead;
		if (pcur == NULL)
			return NULL;
		while (pcur->_next != _pHead)//最后一个节点数据不会进入循环
		{
			if (pcur->_data == data)
				return pcur;
			pcur = pcur->_next;
		}
		if (pcur->_data == data)//最后一个节点的查找
			return pcur;
		return NULL;
	}
指定位置插入:


	Node* Insert(Node* pos, const DataType& data)//插入
	{
		assert(pos);//对插入点进行断言,避免插入点为空
		Node* pNewNode = new Node(data);
		/*pNewNode->_next = pos;//1
		pNewNode->_pre = pos->_pre;//2
		pos->_pre->_next = pNewNode;//3
		pos->_pre = pNewNode;//4*/
		/*两种都可以*/
		Node* pcur = pos->_pre;//将pos的前一个节点保存,方便插入
		pNewNode->_next = pos;
		pos->_pre = pNewNode;
		pcur->_next = pNewNode;
		pNewNode->_pre = pcur;
		if (pos == _pHead)//如果新插入的节点为头节点,将新节点设为_pHead
			_pHead = pNewNode;
		return pNewNode;
	}

	Node* Erase(Node* pos)//清除指定节点,返回该节点的下一个节点
	{
		assert(pos);//对删除点断言,要删除的节点不应该为空
		if (pos->_next == pos)
		{
			delete pos;
			pos = NULL;
			return NULL;
		}
		Node* pcur = pos->_next;
		pos->_pre->_next = pos->_next;
		pos->_next->_pre = pos->_pre;
		if (pos == _pHead)
			_pHead = _pHead->_next;
		delete pos;
		return pcur;
	}
	
	size_t Size()const//链表节点的个数
	{
		Node* pcur = _pHead;
		size_t count = 1;
		while (pcur->_next != _pHead)
		{
			count++;
			pcur = pcur->_next;
		}
		return count;
	}

	bool Empty()const//判断链表是否为空,空链表返回1
	{
		return _pHead == NULL;
	}

private:
	Node* _pHead;
};

void test2()
{
	int arr[5] = { 1,2,3,4,5 };
	List list1(arr, sizeof(arr) / sizeof(arr[0]));
	cout << list1 << endl;
	list1.Insert(list1.Find(5), 8);
	cout << list1 << endl;
	//cout << list1.Size() << endl;
	List list2;
	cout << list2.Empty()<<endl;
	list1.Erase(list1.Find(5));
	cout << list1 << endl;
	List list3 = list1;
	cout << list3 << endl;
}
void test1()
{
	List list1;
	list1.PushFront(1);
	list1.PushFront(2);
	//cout << list1 << endl;
	int arr[5] = { 1, 2, 3, 4, 5 };
	List list2(arr, sizeof(arr) / sizeof(arr[0]));
	//cout << list2 << endl;
	//list2.PopBack();
	//cout << list2 << endl;
	//list2.PopBack();
	//cout << list2 << endl;
	//list2.PopBack();
	//cout << list2 << endl;
	//list2.PopBack();
	//cout << list2 << endl;
	//list2.PopBack();
	//cout << list2 << endl;
	//list2.Clear();
	//cout << list2 << endl;
	//list2.PushFront(1);
	//list2.PushFront(2);
	//list2.PushFront(3);
	//list2.PushFront(4);
	//list2.PushFront(5);
	//cout << list2 << endl;
	List list3(list2);
	cout << list3 << endl;
	list3.PopFront();
	cout << list3 << endl;
	list3.PopFront();
	cout << list3 << endl;
	list3.PopFront();
	cout << list3 << endl;
	list3.PopFront();
	cout << list3 << endl;
	list3.PopFront();
	cout << list3 << endl;
}
int main()
{
	//test1();
	test2();
	return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值