数据结构之——双向循环链表完备版(C++实现)

双向循环链表

⚪介绍

双向循环链表只是在双向链表的基础上增加了头尾节点的互相指向双向循环链表

⚪难点讲解

双向循环链表,只需要引用之前的双向链表代码的基础上部分功能进行修改
因为只对头尾节点进行了相互指向,因此只有添加、删除的函数的头尾部分需要进行修改

添加

先观察原来的双向链表

void DouLinkList<E>::add(int index, E element)		//在某节点添加元素
{
	if (index == size)		//在尾节点添加元素
	{
		Node<E> *Old_last = last;
		last = new Node<E>(Old_last, element, NULL);
		if (Old_last == NULL)		//如果是链表添加的第一个元素
		{
			first = last;
		}
		else
		{
			Old_last->next = last;
		}
	}
	else
	{
		Node<E>* next = find_node(index);
		Node<E>* prev = next->prev;
		Node<E>* p = new Node<E>(prev, element, next);
		if (prev == NULL)		//如果index==0
		{
			first = p;
		}
		else
		{
			prev->next = p;
		}
		next->prev = p;
	}

	size++;
}

以往最后添加元素的情况为例,首先要将last指针指向新添加的元素,再将新添加元素的prev指针指向原先的最后一个节点,再将原先最后一个节点的next指针指向新添加的元素 …其实这些线在双向链表中已接好,我们只需要在原有的基础上再添加部分的线即可。

1、尾

尾部添加
在尾节点添加元素要增加头节点的prev指针指向新添加节点和新添加节点的next指针指向头节点
因此要将last = new Node<E>(Old_last, element, NULL);此句代码改为last = new Node<E>(Old_last, element, first);,将新添加节点的next指针指向头节点; else{prev->next = p;}在此处增加一句first->prev=last头节点的prev指针指向新添加节点。
只有一个元素
当是链表添加的第一个元素,那么就要增加自己的prev指针和next的指针都要指向自己

if (Old_last == NULL)		//如果是链表添加的第一个元素
		{
			first = last;
		}

就将此处的代码修改为

if (Old_last == NULL)		//如果是链表添加的第一个元素
		{
			first = last;
			first->next = first;
			first->prev = first;
		}
2、头

在之前的双向链表中的除尾节点添加情况中的因头节点的prev指针为NULL而增加了头节点的讨论,而双向循环链表不存在头节点的prev指针为空的情况,因此next.prev = node这句代码是一定要执行的,所以把它放到 if()语句的前面。而对于first = node这句代码是将first头指针指向头节点是一定存在的,因此我们把if的判断语句改为next == first(index == 0也可以)

3、总代码
template<class E>
void Circle_DouLinkList<E>::add(int index, E element)//在任意位置添加元素
{
	if (index == size)
	{
		Node<E>* Old_last = last;
		last = new Node<E>(Old_last, element, first);
		if (Old_last == NULL)		//如果是链表添加的第一个元素
		{
			first = last;
			first->next = first;
			first->prev = first;
		}
		else
		{
			Old_last->next = last;
			first->prev = last;
		}
	}
	else
	{
		Node<E>* next = find_node(index);
		Node<E>* prev = next->prev;
		Node<E>* p = new Node<E>(prev, element, next);
		next->prev = p;
		prev->next = p;
		if (index==0)		
		{
			first = p;
		}	
	}

	size++;
}

删除

先观察原来的双向链表删除的代码

template<class E>
E DouLinkList<E>::remove(int index)			//删除某节点的元素
{
	Node<E>* p = find_node(index);
	Node<E>* prev = p->prev;
	Node<E>* next = p->next;
	if (prev == NULL)		//index==0
	{
		first = next;
	}
	else
	{
		prev->next = next;
	}
	if (next == NULL)		//index==size-1
	{
		last = prev;
	}
	else
	{
		next->prev = prev;
	}
	E x = p->element;
	delete p;
	return x;
}

对于尾节点的讨论和头节点都是因为增加了循环的机构而对于头尾节点讨论的代码进行了变动,无太多的差别,因此就不多赘述了。

特殊情况

而在删除节点有一种特殊情况是删除的元素为链表中的唯一元素,利用已有的讨论无法达到我们所需要的删除目的,因此要增加对于size==1这种特殊情况的讨论。
在这种情况中只需要将first和last指针全部置空即可。即增加first = NULLlast = NULL的代码。

总代码
template<class E>
E Circle_DouLinkList<E>::remove(int index)//删除某个节点并返回被删除节点的值
{
	Node<E>* p = NULL;
	if (size == 1)
	{		
		p = first;
		first = NULL;
		last = NULL;
	}
	else
	{
		p = find_node(index);
		Node<E>* prev = p->prev;
		Node<E>* next = p->next;
		prev->next = next;
		next->prev = prev;
		if (index == 0)
		{
			first = next;
		}

		if (index == size - 1)
		{
			last = prev;
		}

	}
	E x = p->element;
	delete p;
	return x;
}

⚪总代码

Circle_Double_Link_List.h

#pragma once
#pragma once
#include <iostream>
using namespace std;


template<class E>
class Node
{
public:
	E element;
	Node<E>* next;
	Node<E>* prev;
	Node(Node<E>* prev, E element, Node<E>* next)
	{
		this->element = element;
		this->next = next;
		this->prev = prev;
	}
	~Node() {}
};

template<class E>
class Circle_DouLinkList
{
private:
	int size;
	Node<E>* first = NULL;
	Node<E>* last = NULL;

	static const int ELEMENT_NOT_FOUND = -1;

	Node<E>* find_node(int index);			//获得某位置节点
public:
	void clear();							//清除所有元素
	void add(E element);						//在尾部添加元素
	void add(int index, E element);			//在任意位置添加元素
	int Size();								//求链表的长度
	int indexOf(E element);					//获取某元素所对应节点,若无则返回ELEMENT_NOT_FOUND = -1
	bool isEmpty();							//判断链表是否为空
	bool contains(E element);				//判断是否包含某个元素
	E get(int index);						//获得某个节点对应元素
	E set(int index, E element);				//修改某个节点对应元素,返回原元素值
	E remove(int index);						//删除某个节点并返回被删除节点的值
	void print();							//输出所有节点

	~Circle_DouLinkList(){}
};

Circle_Double_Link_List.cpp

#include "Circle_Double_Link_List.h"

template<class E>
void Circle_DouLinkList<E>::clear()//清除所有元素
{
	Node* q;
	Node<E>* p = first->next;
	while (p != NULL)
	{
		q = p;
		p = p->next;
		delete q;
	}
	p = NULL;
	q = NULL;
}

template<class E>
int Circle_DouLinkList<E>::Size()//求链表的长度
{
	return size;
}

template<class E>
bool Circle_DouLinkList<E>::isEmpty()//判断链表是否为空
{
	return size == 0;
}

template<class E>
bool Circle_DouLinkList<E>::contains(E element)//判断是否包含某个元素
{
	return indexOf(element) != -ELEMENT_NOT_FOUND;
}

template<class E>
void Circle_DouLinkList<E>::add(E element)//在尾部添加元素
{
	add(size, element);
}

template<class E>
int Circle_DouLinkList<E>::indexOf(E element)//获取某元素所对应节点,若无则返回ELEMENT_NOT_FOUND = -1
{
	if (element == NULL)						//讨论当传入元素本身为NULL的情况
	{
		Node<E>* node = first;
		for (int i = 0; i < size; i++)
		{
			if (node->element == NULL)
			{
				return i;
			}
			node = node->next;
		}
	}
	else
	{
		Node<E>* node = first;
		for (int i = 0; i < size; i++)
		{
			if (node->element == element)
			{
				return i;
			}
			node = node->next;
		}
	}
	return ELEMENT_NOT_FOUND;
}

template<class E>
E Circle_DouLinkList<E>::get(int index)//获得某个节点对应元素
{
	return find_node(index).element;
}

template<class E>
E Circle_DouLinkList<E>::set(int index, E element)//修改某个节点对应元素,返回原元素值
{
	Node<E>* node = find_node(index);
	E old = node->element;
	node->element = element;
	return old;
}

template<class E>
void Circle_DouLinkList<E>::add(int index, E element)//在任意位置添加元素
{
	if (index == size)
	{
		Node<E>* Old_last = last;
		last = new Node<E>(Old_last, element, first);
		if (Old_last == NULL)		//如果是链表添加的第一个元素
		{
			first = last;
			first->next = first;
			first->prev = first;
		}
		else
		{
			Old_last->next = last;
			first->prev = last;
		}
	}
	else
	{
		Node<E>* next = find_node(index);
		Node<E>* prev = next->prev;
		Node<E>* p = new Node<E>(prev, element, next);
		next->prev = p;
		prev->next = p;
		if (index==0)		
		{
			first = p;
		}	
	}

	size++;
}

template<class E>
E Circle_DouLinkList<E>::remove(int index)//删除某个节点并返回被删除节点的值
{
	Node<E>* p = NULL;
	if (size == 1)
	{		
		p = first;
		first = NULL;
		last = NULL;
	}
	else
	{
		p = find_node(index);
		Node<E>* prev = p->prev;
		Node<E>* next = p->next;
		prev->next = next;
		next->prev = prev;
		if (index == 0)
		{
			first = next;
		}

		if (index == size - 1)
		{
			last = prev;
		}

	}
	E x = p->element;
	delete p;
	return x;
}


template<class E>
void Circle_DouLinkList<E>::print()//输出所有节点
{
	Node<E>* p = first;
	while (p != NULL)
	{
		cout << p->element << "->";
		p = p->next;
	}
}

template<class E>
Node<E>* Circle_DouLinkList<E>::find_node(int index)//获得某位置节点
{
	if (index < 0 || index >= size)
	{
		throw "index不符合规范";
	}

	if (index < (size >> 1))
	{
		Node<E>* node = first;
		for (int i = 0; i < index; i++)
		{
			node = node->next;
		}
		return node;
	}
	else
	{
		Node<E>* node = last;
		for (int i = size - 1; i > index; i--)
		{
			node = node->prev;
		}
		return node;
	}
}

main.cpp

#include "Circle_Double_Link_List.h"
#include "Circle_Double_Link_List.cpp"
#include <iostream>

int main()
{
    Circle_Dou_LinkList <int>list;
    int* X;
    int n;
    cin >> n;
    X = new int[n];
    for (int i = 0; i < n; i++)
    {
        cin >> X[i];
        list.add(X[i]);
    }
    list.print();
    return 0;
}

附:
1.本博客是由学习小码哥视频所总结文章
2.代码都通过合格检测,请放心食用~

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GXM.

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

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

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

打赏作者

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

抵扣说明:

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

余额充值