利用C++實現雙向鏈表的基本操作

利用C++實現雙向鏈表的基本操作

本文采用利用C++實現了對雙向鏈表的基本操作。操作包括:雙向鏈表的構建、鏈表指定位置的插入、鏈表指定位置的刪除、鏈表長度的獲取、鏈表指定位置元素的獲得及指定元素位置的獲得、整體鏈表的刪除。

雙向鏈表是鏈表的另一種形式,它的結點特點是每個結點包括兩個指針域和一個數據域,兩個指針域Prior和Next分別指向該結點的前驅和後繼元素。雙向結點的結構如下圖所示。
雙向鏈表結點
雙向鏈表除了頭結點沒有前驅和尾結點沒有後繼外,其他結點都有前驅結點和後驅結點,其結構下圖所示。
雙向鏈表結構
從圖中的結構可以清楚的看到,雙向鏈表可以從任何一個結點到達鏈表的頭結點和尾結點。雙向鏈表與單鏈表的操作過程類似,都可已進行插入、刪除、獲取、以及清空等基本操作。利用C++實現的具體代碼如下。

#include<iostream>

using namespace std;

template<typename datatype> class doubleLink;       //雙向鏈表聲明
/***************************************雙向鏈表數據結構定義*************************************************/
template<typename datatype>class doubleNode
{
public:

	//無參數構造函數,將指針域初始化爲NULL
	doubleNode()
	{
		p_prior = NULL;
		p_next = NULL;
	}
   //帶參數的構造函數,初始化數據域與指針域
	doubleNode(datatype item, doubleNode<datatype> * prior=NULL, doubleNode<datatype> * next=NULL)
	{
		data = item;
		p_prior = prior;
		p_next = next;
	}
	//析構函數
	~doubleNode()
	{
		p_prior = NULL;
		p_next = NULL;
	}

private:
	doubleNode<datatype> *p_prior;                         //指向前節點的指針
	doubleNode<datatype> *p_next;                          //指向後節點的指針
	datatype data;                                         //自身節點的數據
	int length;                                            //鏈表長度
	//定義友元類
	friend  class doubleLink<datatype>;
};
/***************************************雙向鏈表定義*************************************************/
template<typename datatype>class doubleLink
{
public:
	//雙向鏈表的構造函數,鏈表產生新頭結點
	doubleLink()
	{
		head = new doubleNode<datatype>();                  //鏈表產生新頭結點
	}
	//雙向鏈表的構造函數,鏈表產生新頭結點
	doubleLink(doubleNode<datatype>*note)
	{
		head = note;
	}
	//雙向鏈表的析構函數,鏈表刪除頭節點
	~doubleLink()
	{
		delete head;
	}
public:
	void cleandoubleLink();                                 //清空雙向鏈表
	int  getLength();                                       //獲取鏈表長度
	int  findData(datatype item);                           //尋找給定數值的結點
	bool insertNode(datatype item,int n);                   //在i個結點插入datatype類型item
	bool deleteNode(int n);                                 //刪除第i個結點的數據
	datatype getData(int n);                                //獲取第i個結點的數據
private:
	doubleNode<datatype> * head;                            //頭指針
};
/********************************************清空雙向鏈表*************************************************/
template<typename datatype>
void doubleLink<datatype>::cleandoubleLink()
{
	doubleNode<datatype> *P_move = head->p_next, *P_middle;  //設置遊標指針   
	while (P_move!=NULL)                                     //判斷頭指針後面的結點
	{
		P_middle = P_move;
		P_move = P_middle->p_next;                           //遊標指針藉助中間指針向後移
		delete P_middle;                                     //刪除中間指針,即刪除後面的結點
	}
	head->p_next = NULL;                                     //將頭指針的指向空
}
/********************************************獲取鏈表長度*************************************************/
template<typename datatype>
int doubleLink<datatype>::getLength()
{
	doubleNode<datatype> *P_move = head->p_next;             //設置遊標指針
	int length=0;
	//遍歷鏈表,計算結點數
	while(P_move!=NULL)
	{
		P_move = P_move->p_next;                            //遊標指針後移
		length++;                                           //計算length
	}
	return length;
}
/***************************************尋找給定數值的結點*************************************************/
template<typename datatype>
int doubleLink<datatype>::findData(datatype item)
{
	doubleNode<datatype> *P_move = head;             //設置遊標指針
	if (P_move->p_next==NULL)
	{
		cout << "當前鏈表爲空鏈表!" << endl;
		return 0;
	}
	int length = 0;                     
	while (P_move->data!= item)
	{
		P_move = P_move->p_next;                             //遊標指針後移
		length++;
	}
	return length;
}
/************************************在i個結點插入datatype類型item*****************************************/
template<typename datatype>
bool doubleLink<datatype>::insertNode(datatype item, int n)
{

  if (n<1)
  {
	cout << "輸入非有效位置" << endl;
	return false;
		}
  doubleNode<datatype>  * P_move = head;             //創建新指針,並設置遊標指針
  
  //找到插入位置
  for (int i = 1; i <n; i++)
  {
	  P_move = P_move->p_next;                                                                      //遊標指針後移
	  if (P_move==NULL&&i<=n)
	  {
		  cout << "插入位置無效" << endl;
		  return false;
	  }
  }
  doubleNode<datatype> * newNode = new doubleNode<datatype>(item);
  //插入新結點
  if (newNode == NULL)
  {
	  cout << "內存分配失敗,新結點無法創建" << endl;
	  return false;
  }
  newNode->p_next= P_move->p_next;   
  if (P_move->p_next!=NULL)
  {
	  P_move->p_next->p_prior = newNode;
  }
  newNode->p_prior = P_move;
  P_move->p_next = newNode;
  return true;
}
/***************************************刪除第i個結點的數據*************************************************/
template<typename datatype>
bool doubleLink<datatype>::deleteNode(int n)
{
	if (n<1||n>getLength())
	{
		cout << "輸入非有效位置" << endl;
		return false;
	}
	doubleNode<datatype> * P_move = head,* p_delete;             //設置遊標指針
	//查找刪除結點的位置
	for (int i = 1; i <= n; i++)
	{
		P_move = P_move->p_next;                                         //遊標指針後移
	}
	//刪除結點
	p_delete = P_move;      
	P_move->p_prior->p_next = p_delete->p_next;
	P_move->p_next->p_prior = p_delete->p_prior;
	delete p_delete;
	return true;
}
/***************************************獲取第i個結點的數據*************************************************/
template<typename datatype>
datatype doubleLink<datatype>::getData(int n)
{
	if (n<1|| n>getLength())
	{
		cout << "輸入非有效位置" << endl;
		return 0;
	}
	doubleNode<datatype> * P_move = head;             //設置遊標指針
	for (int i = 1; i<=n; i++)
	{
		P_move = P_move->p_next;                                         //遊標指針後移
	}
	if (P_move==NULL)
	{
		cout << "沒有所要查找的結點" << endl;
		return 0;
	}
	return P_move->data;
}
/***************************************************主函數***************************************************/
int main()
{

	doubleNode<int> Note;
	doubleLink<int> Link(&Note);
	cout << "*******************************操作選擇*******************************" << endl;
	cout << "1.產生鏈表" << endl;
	cout << "2.給鏈表中插入元素" << endl;
	cout << "3.刪除鏈表中的元素" << endl;
	cout << "4.獲取鏈表中的元素" << endl;
	cout << "5.獲取鏈表中的數據位置" << endl;
	cout << "6.清空鏈表中的元素" << endl;
	cout << "**********************************************************************" << endl;
	while (1)
	{
		int Opera_Number;
		cin >> Opera_Number;
		switch (Opera_Number)
		{
			//產生鏈表
		   case 1:
		  {
			   int doubleLink_Number;
			   cout << "輸入你需要的鏈表長度:" << endl;
			   cin >> doubleLink_Number;
			   for (int i = 1; i <=doubleLink_Number; i++)
			   {
				   Link.insertNode(i*11,i);
			   }
   cout << "*****************************當前鏈表爲********************************" << endl;
			   for (int i = 1; i <=doubleLink_Number; i++)
			   {
				   cout << Link.getData(i) << "  ";
			   }
			   break;
		            }
		  //給鏈表中插入元素
		   case 2:
		   {
			   int insert_Number, insert_Data;
			   cout << "輸入插入位置點:" << endl;
			   cin >> insert_Number;
			   cout << "輸入插入數據:" << endl;
			   cin >> insert_Data;
			   Link.insertNode(insert_Data, insert_Number);
			   cout << "*****************************當前鏈表爲********************************" << endl;
			   for (int i = 1; i <=( Link.getLength()); i++)
			   {
				   cout << Link.getData(i) << "   ";
			   }
			   break;
		   }
		   //刪除鏈表中的元素
		   case 3:
		   {
			   int delete_Number;
			   cout << "輸入刪除位置點:" << endl;
			   cin >> delete_Number;
			   Link.deleteNode(delete_Number);
			   cout << "*****************************當前鏈表爲********************************" << endl;
			   for (int i = 1; i <= (Link.getLength()); i++)
			   {
				   cout << Link.getData(i) << "  ";
			   }
			   break;
		   }
		   //獲取鏈表中的元素
		   case 4:
		   {
			   int get_Number;
			   cout << "輸入獲取位置點:" << endl;
			   cin >> get_Number;
			   cout << "獲取到的數據:" << Link.getData(get_Number) << endl;
			   break;
		   }
		  //獲取鏈表中的數據位置
		   case 5:
		   {
			   int data;
			   cout << "輸入想查詢的數據:" << endl;
			   cin >> data;
			   if ((Link.findData(data)!=0))
			   {
				   cout << "該數據在鏈表中的位置爲:" << Link.findData(data) << endl;
			   }
			   break;
		   }
		   //清空鏈表中所有的元素
		   case 6:
		   {
			   cout << "刪除前的鏈表長度:" << Link.getLength() << endl;
			   Link.cleandoubleLink();
			   cout << "刪除後的鏈表長度:" << Link.getLength() << endl;
			   break;
		   }
		   //未在操作數範圍內
		   default:
		   {
			   cout << "輸入操作數未在操作數範圍內" << endl;
			   break;
		   }
		}
	}
	return 0;
}

代碼在創建過程中,主要參照了由胡浩主編的《妙趣橫生的算法》的搭建方式與搭建方法。在編程的過程中,我認爲我遇到的比較核心的主要有兩點:
1.遊標指針的設置:通過遊標指針的後移,可以幫助我們很方便的對結點從頭結點後進行查找。
2.鏈表的插入、刪除的基本算法的理解:插入與刪除的基本算法說到底就是對前驅指針和後繼指針的設置,只要將這兩個指針域搞清楚了,基本操作也就掌握了。(ps:如果想詳細瞭解,將insertNode函數、deleteNode函數多看幾遍即可。)

零零散散就寫這麼多,程序自己親自跑了一遍,感覺沒什麼太大的問題。大家如果看的過程中有什麼問題,也歡迎大家相互交流!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章