C++教程:鏈表類
2020-05-23 14:25:51
供稿:網友
鏈表結點類編寫好了,我們可以向鏈表類進軍了。鏈表是由一個個鏈表結點組成的,所以我們會在鏈表類中使用到鏈表結點類。鏈表結點類是一個很簡單的類,鏈表類是一個功能更為強大的類。正是將一個個類不斷地組合與擴充,使得面向對象的程序功能越來越強大。
讓我們感興趣的是,假設我們編寫的鏈表需要有一個頭結點作為成員數據,那么是先有鏈表呢,還是先有頭結點?我們又該如何在給鏈表作初始化的同時初始化頭結點呢?
當一個對象中包含別的對象時,我們可以在它的構造函數定義中用以下格式調用其成員對象的構造函數:
類名::構造函數名(參數表):成員對象名1(參數表)[,……成員對象名n(參數表)]
前一段和普通的構造函數一樣,冒號之后則表示該類中的成員對象怎樣調用各自的構造函數。
下面我們來看一個簡單的面向對象的鏈表程序:(程序15.3)
//node.h同程序15.2.2
//linklist.h
#include "node.h"//需要使用鏈表結點類
#include <iostream>
using namespace std;
class Linklist
{
public:
Linklist(int i,char c);//鏈表類構造函數
bool Locate(int i);//根據整數查找結點
bool Locate(char c);//根據字符查找結點
bool Insert(int i=0,char c='0');//在當前結點之后插入結點
bool Delete();//刪除當前結點
void Show();//顯示鏈表所有數據
void Destroy();//清除整個鏈表
private:
Node head;//頭結點
Node * pcurrent;//當前結點指針
};
Linklist::Linklist(int i,char c):head(i,c)//類名::構造函數名(參數表):成員對象名1(參數表),鏈表類構造函數,調用head對象的構造函數重載1,詳見Node.h文件
{
cout<<"Linklist constructor is running..."<<endl;
pcurrent=&head;
}
bool Linklist::Locate(int i)
{
Node * ptemp=&head;
while(ptemp!=NULL)
{
if(ptemp->readi()==i)
{
pcurrent=ptemp;//將當前結點指針指向找到的結點
return true;
}
ptemp=ptemp->readn();//查找下一個結點
}
return false;
}
bool Linklist::Locate(char c)
{
Node * ptemp=&head;
while(ptemp!=NULL)
{
if(ptemp->readc()==c)
{
pcurrent=ptemp;
return true;
}
ptemp=ptemp->readn();
}
return false;
}
bool Linklist::Insert(int i,char c)
{
if(pcurrent!=NULL)
{
Node * temp=new Node(i,c,pcurrent,pcurrent->readn());//調用Node類構造函數重載2
if (pcurrent->readn()!=NULL)
{
pcurrent->readn()->setp(temp);
}
pcurrent->setn(temp);
return true;
}
else
{
return false;
}
}
bool Linklist::Delete()
{
if(pcurrent!=NULL && pcurrent!=&head)//head結點不能刪除
{
Node * temp=pcurrent;
if (temp->readn()!=NULL)
{
temp->readn()->setp(pcurrent->readp());
}
temp->readp()->setn(pcurrent->readn());//先連
pcurrent=temp->readp();
delete temp;//后斷
return true;
}
else
{
return false;
}
}
void Linklist::Show()
{
Node * ptemp=&head;
while (ptemp!=NULL)//鏈表的遍歷
{
cout <<ptemp->readi() <<'/t' <<ptemp->readc() <<endl;
ptemp=ptemp->readn();
}
}
void Linklist::Destroy()
{
Node * ptemp1=head.readn();
while (ptemp1!=NULL)
{
Node * ptemp2=ptemp1->readn();
delete ptemp1;
ptemp1=ptemp2;
}
head.setn(NULL);//頭結點之后沒有其他結點
}
//main.cpp
#include "Linklist.h"
#include <iostream>
using namespace std;
int main()
{
int tempi;
char tempc;
cout <<"請輸入一個整數和一個字符:" <<endl;
cin >>tempi >>tempc;
Linklist a(tempi,tempc);//創建一個鏈表,頭結點數據由tempi和tempc確定
a.Locate(tempi);
a.Insert(1,'C');
a.Insert(2,'B');
a.Insert(3,'F');
cout <<"After Insert" <<endl;
a.Show();
a.Locate('B');
a.Delete();
cout <<"After Delete" <<endl;
a.Show();
a.Destroy();
cout <<"After Destroy" <<endl;
a.Show();
return 0;
}
運行結果:
請輸入一個整數和一個字符:
4 G
Node constructor is running...
Linklist constructor is running...
Node constructor is running...
Node constructor is running...
Node constructor is running...
After Insert
4 G
3 F
2 B
1 C
After Delete
4 G
3 F
1 C
After Destroy
4 G
根據程序的運行結果,我們發現頭結點的構造函數比鏈表的構造函數優先運行。這也不難理解:構造函數的目的是要初始化成員數據,初始化成員數據的時候這個成員數據是必須存在的。所以當一個成員數據是一個對象的時候,應當先產生這個成員對象,于是就先調用了成員對象的構造函數。