利用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函數多看幾遍即可。)
零零散散就寫這麼多,程序自己親自跑了一遍,感覺沒什麼太大的問題。大家如果看的過程中有什麼問題,也歡迎大家相互交流!!