C++實現雙向循環鏈表


本次博文是關於利用C++模板的方式實現的雙向循環鏈表以及雙向循環鏈表的基本操作,在之前的博文C++語言實現雙向鏈表中,已經給大家分析了雙向循環鏈表的結構,並以圖示的方式給大家解釋了雙向循環鏈表的基本操作。本篇文章利用C++實現了雙向循環鏈表的基本操作,其中包括:

雙向循環鏈表 實現的功能
頭部插入結點建立鏈表 尾部插入結點建立鏈表
實現指定位置插入結點 查找給定數值是否存在
刪除指定位置的結點 修改指定位置的結點
雙向鏈表的長度 打印雙向鏈表

定義雙向鏈表的結點

雙向循環鏈表的結點由三部分構成,用於指向當前節點的直接前驅節點指針域,用於存儲數據元素數據域 ,以及用於指向當前節點的直接后繼節點指針域

在之前的C++語言實現雙向鏈表時已經給大家解釋了封裝的結點的特點,不需要作太大的改變,我們需要封裝一個結點類,定義了結點的三個要素,並利用構造函數實現初始化,另外,考慮到在雙向循環鏈表中要用到結點類,所以將雙向鏈表類定義為結點的友元類。

template<class T> 
class doubleCircularLinkedList;//聲明一下雙向循環鏈表,以免定義友元時報錯
template <class T>
class doubleCircularLinkedListNode
{
	private:
		doubleCircularLinkedListNode<T> *prior;//雙向結點前驅指針指向該結點的前驅結點
		T data;//儲存結點數據
		doubleCircularLinkedListNode<T> *next;//雙向結點的后驅指針指向該結點的后繼結點
		//將雙向循環鏈表類定義為結點的友元類
		friend  class doubleCircularLinkedList<T>;
	public:
		//結點的無參構造函數,將結點指針域初始化為NULL
		doubleCircularLinkedListNode()
		{
			prior = NULL;
			next = NULL;
		}
		//結點的有參構造函數,初始化指針域和數據域
		doubleCircularLinkedListNode(T _data,doubleCircularLinkedListNode<T> *_prior = NULL,doubleCircularLinkedListNode<T> *_next = NULL)
		{
			prior = _prior;//初始化前驅指針
			data = _data;//初始化數據域
			next = _next;//初始化后繼指針
		}
		~doubleCircularLinkedListNode()
		{
			prior = NULL;
			next = NULL;
		}
};

雙向鏈表的基本操作

本次實現的操作跟雙向鏈表實現的操作基本一樣,實現了雙向循環鏈表頭部插入結點, 尾部插入結點,指定位置插入結點建立鏈表, 查找給定數值的指定位置,刪除指定位置的結點,修改指定位置的結點,雙向循環鏈表的長度,打印雙向循環鏈表,接下來逐一進行講解實現:

頭部插入結點建立鏈表

實現雙向循環鏈表的頭部插入結點,之前的雙向鏈表因為在頭部和尾部的指針都是指向NULL的,所以需要分情況來處理,然而雙向循環鏈表沒有元素時這兩個指針都是指向自身的,因此並不需要分情況處理,都需要修改四個指針。
因此,頭部插入結點實現如下:

template<class T>
bool doubleCircularLinkedList<T>::insertNodeByhead(T item)
{
	//創建一個新的結點
	doubleCircularLinkedListNode<T>* newNode = new doubleCircularLinkedListNode<T>(item);
	if (newNode == NULL){
		cout << "內存分配失敗,新結點無法創建" << endl;
		return false;
	}
	else{
		newNode->prior = headNode;
		newNode->next = headNode->next;
		headNode->next->prior=newNode;
		headNode->next = newNode;
		return true;
	}
}

尾部插入結點建立鏈表

在尾部插入結點,當然第一步需要找到最后一個結點,然后在其后進行插入,調整四個指針即可。

template<class T>
bool doubleCircularLinkedList<T>::insertNodeBytail(T item)
{
	//創建一個新的結點
	doubleCircularLinkedListNode<T>* newNode = new doubleCircularLinkedListNode<T>(item);
	if (newNode == NULL){
		cout << "內存分配失敗,新結點無法創建" << endl;
		return false;
	}
	//首先找到最后一個結點
	doubleCircularLinkedListNode<T>* lastNode = headNode;
	while(lastNode->next != headNode)
	{
		lastNode = lastNode->next;//沒找到就一直循環
	}
	//找到之后調整四個指針
	headNode->prior = newNode;
	newNode->next = headNode;
	lastNode->next = newNode;
	newNode->prior = lastNode;
	return true;
}

實現指定位置插入結點

在指定位置插入只需要兩步走,首先也是找到指定的位置,然后就是插入新結點的指針的調整,中間插入是最復雜的,都需要調整四個指針,最后讓新結點與前繼結點建立關系,實現新結點的插入。

template<class T>
bool doubleCircularLinkedList<T>::insertNode(T item,int n)
{
	if(n<1){
		cout<<"輸入的非有效位置!"<<endl;
		return false;
	}
	doubleCircularLinkedListNode<T>* pMove = headNode;//創建一個新的指針,設置為游標指針
	//首先找到插入位置
	for(int i=1;i<n;i++)
	{
		pMove = pMove->next;
		if(pMove == NULL&& i<=n)
		{
			cout<<"插入位置無效!"<<endl;
			return false;
		}
	}
	//創建一個新的結點
	doubleCircularLinkedListNode<T>* newNode = new doubleCircularLinkedListNode<T>(item);
	if (newNode == NULL){
		cout << "內存分配失敗,新結點無法創建" << endl;
		return false;
	}
	//插入新的結點
	newNode->next = pMove->next;   
	if (pMove->next != headNode)
	{
		pMove->next->prior = newNode;
	}
	newNode->prior = pMove;
	pMove->next = newNode;
	return true;
}

查找給定數值是否存在

查找給定元素,也就是一個遍歷雙向循環鏈表的過程,從頭結點的下一個結點開始遍歷,畢竟第一個頭結點是沒有儲存數據項的。

template<class T>
bool doubleCircularLinkedList<T>::findData(T item)
{
	doubleCircularLinkedListNode<T> *pMove = headNode->next; //設置游標指針
	doubleCircularLinkedListNode<T> *pMoveprior = headNode;//指定結點前一個結點的指針
	//找到指定位置
	while(pMove->data != item)
	{
		pMoveprior = pMove;
		pMove = pMoveprior->next;
		//如果沒有找到特殊處理
		if(pMove == headNode)
		{
			return false;
		}
	}
	return true;
}

刪除指定位置的結點

刪除指定的結點,第一步查找到刪除的結點,需要定義一個刪除指針臨時指向將要刪除的結點,最后指針處理刪除之后別忘了釋放該結點空間。

template<class T>
bool doubleCircularLinkedList<T>::deleteData(int n)
{
	if (n<1||n>getLength())
	{
		cout << "輸入非有效位置" << endl;
		return false;
	}
	doubleCircularLinkedListNode<T> * pMove = headNode;//設置游標指針
	doubleCircularLinkedListNode<T> * pDelete;             
	//查找刪除結點的位置
	for (int i = 1; i <= n; i++)
	{
		pMove = pMove->next;                                         //游標指針后移
	}
	//刪除結點
	pDelete = pMove;      
	pMove->prior->next = pDelete->next;
	pMove->next->prior = pDelete->prior;
	delete pDelete;//釋放空間
	return true;
}

修改指定位置的結點

修改指定位置的結點數據,當然還是得找到指定位置,然后對其進行修改,修改之后將原來的數據以引用的形式返回。

template<class T>
bool doubleCircularLinkedList<T>::changeListElements(int n,T item,T &x)
{
	if (n<1||n>getLength())
	{
		cout << "輸入非有效位置" << endl;
		return false;
	}
	doubleCircularLinkedListNode<T> *pMove = headNode->next;  //設置游標指針
	for(int i=1;i<n;i++)//找到指定位置1
	{
		pMove = pMove->next;
	}
	x = pMove->data;
	pMove->data = item;
	return true;
}

雙向循環鏈表的長度

計算雙向鏈表的長度的函數,在雙向鏈表的私有成員封裝了一個變量length,以此來記錄雙向鏈表的長度,遍歷雙向鏈表,逐一進行計算結點數就是雙向鏈表的長度。

template<class T>
int doubleCircularLinkedList<T>::getLength()
{
	doubleCircularLinkedListNode<T> *pMove = headNode->next;  //設置游標指針
	int length=0;
	//遍歷鏈表,計算結點數
	while(pMove != headNode)
	{
		pMove = pMove->next;  //游標指針后移
		length++;       //計算length
	}
	return length;
}

打印雙向循環鏈表

template<class T>
void doubleCircularLinkedList<T>::printLinkedlist()
{
	//從第二個結點開始打印,表頭不含數據
	doubleCircularLinkedListNode<T>* pMove = headNode->next;
	while(pMove !=headNode)//如果pMove->next != headNode這樣寫,最后一個結點是不會打印的
	{
		cout<<pMove->data<<" ";
		pMove = pMove->next;//移動指針
	}
	cout<<endl;
}

以上就是我簡要的給大家分享的C++實現雙向循環鏈表,因為實現了雙向鏈表,所以基本上實現思路差不多,唯一的不同就是在循環一詞不同,這一不同就是頭結點的前驅指針和尾結點的后驅指針指向不同,要是還是不太清楚的可以去那篇博客看看。本次的完整代碼已經全部上傳到github! (C++實現雙向循環鏈表),還想了解其他的數據結構實現的可以去我的博客,我們一起討論啊,一起進步!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM