【數據結構 筆記00】C++鏈表的創建與操作

C++鏈表的創建與操作

我們知道,數組式計算機根據事先定義好的數組類型與長度自動爲其分配一連續的存儲單元,相同數組的位置和距離都是固定的,也就是說,任何一個數組元素的地址都可一個簡單的公式計算出來,因此這種結構可以有效的對數組元素進行隨機訪問。但若對數組元素進行插入和刪除操作,則會引起大量數據的移動,從而使簡單的數據處理變得非常複雜,低效。

爲了能有效地解決這些問題,一種稱爲“鏈表”的數據結構得到了廣泛應用。

鏈表概述

鏈表是一種動態數據結構,他的特點是用一組任意的存儲單元(可以是連續的,也可以是不連續的)存放數據元素。

鏈表中每一個元素成爲“結點”,每一個結點都是由數據域和指針域組成的,每個結點中的指針域指向下一個結點。Head是“頭指針”,表示鏈表的開始,用來指向第一個結點,而最後一個指針的指針域爲NULL(空地址),表示鏈表的結束。

可以看出鏈表結構必須利用指針才能實現,即一個結點中必須包含一個指針變量,用來存放下一個結點的地址。

實際上,鏈表中的每個結點可以用若干個數據和若干個指針。結點中只有一個指針的鏈表稱爲單鏈表,這是最簡單的鏈表結構。

再c++中實現一個單鏈表結構比較簡單。例如,可定義單鏈表結構的最簡單形式如下

structNode{
int Data;
Node *next;
};


這裏用到了結構體類型。其中,*next是指針域,用來指向該結點的下一個結點;Data是一個整形變量,用來存放結點中的數據。當然,Data可以是任何數據類型,包括結構體類型或類類型。

在此基礎上,我們在定義一個鏈表類list,其中包含鏈表結點的插入,刪除,輸出等功能的成員函數。

classlist{
Node *head;
public:
list(){head=NULL;}
void insertlist(int aDate,int bDate); //鏈表結點的插入
void Deletelist(int aDate); //鏈表結點的刪除
void Outputlist(); //鏈表結點的輸出
Node*Gethead(){return head;}
};


鏈表結點的訪問

由於鏈表中的各個結點是由指針鏈接在一起的,其存儲單元文筆是連續的,因此,對其中任意結點的地址無法向數組一樣,用一個簡單的公式計算出來,進行隨機訪問。只能從鏈表的頭指針(即head)開始,用一個指針p先指向第一個結點,然後根據結點p找到下一個結點。以此類推,直至找到所要訪問的結點或到最後一個結點(指針爲空)爲止。

下面我們給出上述鏈表的輸出函數;

voidlist::Outputlist(){
Node *current = head;
while(current != NULL){
cout << current->Data <<" ";
current = current->next;
}
cout<<endl;
}


鏈表節點的插入

如果要在鏈表中的結點a之前插入結點b,則需要考慮下面幾點情況。

(1) 插入前鏈表是一個空表,這時插入新結點b後。

(2) 若a是鏈表的第一個結點,則插入後,結點b爲第一個結點。

(3) 若鏈表中存在a,且不是第一個結點,則首先要找出a的上一個結點a_k,然後使a_k的指針域指向b,在令b的指針域指向a,即可完成插入。

(4) 如鏈表中不存在a,則插在最後。先找到鏈表的最後一個結點a_n,然後使a_n的指針域指向結點b,而b指針的指針爲空。

以下是鏈表類的結點插入函數,顯然其也具有建立鏈表的功能。

voidlist::insertlist(int aDate,int bDate) //設aDate是結點a中的數據,bDate是結點b中的數據
{
Node *p,*q,*s; //p指向結點a,q指向結點a_k,s指向結點b
s=(Node*)new(Node); //動態分配一個新結點
s->Data=bDate; //設b爲此結點
p=head;
if(head==NULL) {//若是空表,使b作爲第一個結點
head=s;
s->next=NULL;
} else{
if(p->Data==aDate){ //若a是第一個結點
s->next = p;
head = s;
}else{
while(p->Data != aDate &&p->next != NULL) {//查找結點a
q=p;
p=p->next;
}
if(p->Data == aDate) {//若有結點a
q->next = s;
s->next=p;
} else{ //若沒有結點a
p->next = s;
s->next = NULL;
}
}
}
}

鏈表節點的刪除

如果要在鏈表中刪除結點a並釋放被刪除的結點所佔的存儲空間,則需要考慮下列幾種情況。

(1) 若要刪除的結點a是第一個結點,則把head指向a的下一個結點。

(2) 若要刪除的結點a存在於鏈表中,但不是第一個結點,則應使a得上一個結點a_k-1的指針域指向a的下一個結點a_k+1。

(3) 空表或要刪除的結點a不存在,則不做任何改變。

以下是鏈表類的結點刪除函數。

voidlist::deletelist(int aDate) {//設aDate是要刪除的結點a中的數據成員
Node *p,*q; //p用於指向結點a,q用於指向結a的前一個結點
p = head;
if(p==NULL) { //若是空表
return;
}
if(p->Data==aDate) { //若a是第一個結點
head = p->next;
delete p;
}else{
while( p->Data != aDate &&p->next != NULL) { //查找結點a
q = p;
p = p->next;
}
if(p->Data == aDate) { //若有結點a
q->next=p->next;
delete p;
}
}
}

voidlist::deletelist(int aDate) {//aDate是要刪除的結點a中的數據成員

Node *p,*q; //p用於指向結點a,q用於指向結a的前一個結點

p = head;

if(p==NULL) { //若是空表

return;

}

if(p->Data==aDate) { //a是第一個結點

head = p->next;

delete p;

}else{

while( p->Data != aDate &&p->next != NULL) { //查找結點a

q = p;

p = p->next;

}

if(p->Data == aDate) { //若有結點a

q->next=p->next;

delete p;

}

}

}

例題:利用以上三個鏈表操作成員函數insertlist,deletelist,outputlist可形成以下的簡單鏈表操作程序。

#include"iostream.h"
structNode{
int Data;
Node*next;
};
classlist{
Node*head;
public:
list(){head=NULL;}
void insertlist(int aData,int bData);
void deletelist(int aData);
void outputlist();
Node*gethead(){return head;}
};
voidlist::insertlist(int aData,int bData) {//設aData是結點a中的數據,bData是結點b中的數據
Node *p,*q,*s; //p指向結點a,q指向結點a_k,s指向結點b
s=(Node*)new(Node); //動態分配一個新結點
s->Data=bData; //設b爲此結點
p=head;
if(head==NULL) { //若是空表,使b作爲第一個結點
head=s;
s->next=NULL;
}else{
if(p->Data==aData) { //若a是第一個結點
s->next=p;
head=s;
}else{
while(p->Data!=aData &&p->next!=NULL) {//查找結點a
q=p;
p=p->next;
}
if(p->Data==aData) {//若有結點a
q->next=s;
s->next=p;
}else{ //若沒有結點a;
p->next=s;
s->next=NULL;
}
}
}
}
voidlist::deletelist(int aData) { //設aData是要刪除的結點a中的數據成員
Node*p,*q; //p用於指向結點a,q用於指向結a的前一個結點
p=head;
if(p==NULL) //若是空表
return;
if(p->Data==aData) {//若a是第一個結點
head=p->next;
delete p;
}else{
while(p->Data!=aData&&p->next!=NULL){//查找結點a
q=p;
p=p->next;
}
if(p->Data==aData) {//若有結點a
q->next=p->next;
delete p;
}
}
}
voidlist::outputlist(){
Node*current=head;
while(current!=NULL){
cout<<current->Data<<"";
current=current->next;
}
cout<<endl;
}
voidmain(){
list A, B;
int Data[10]={25,41,16,98,5,67,9,55,1,121};
A.insertlist(0,Data[0]); //建立鏈表A首結點
for(int i=1;i<10;i++){
A.insertlist(0,Data[i]); //順序向後插入
}
cout<<"/n鏈表A:";
A.outputlist();
A.deletelist(Data[7]);
cout<<"刪除元素Data[7]後";
A.outputlist();
B.insertlist(0,Data[0]); //建立鏈表B首結點
for(i=0;i<10;i++){
B.insertlist(B.gethead()->Data,Data[i]);//在首結點處順序向後插入
}
cout<<"/n鏈表B:";
B.outputlist();
B.deletelist(67);
cout<<"刪除元素67後";
B.outputlist();
}

程序運行結果爲

鏈表A:25,41,16,98,5,67,9,55,1,121

刪除元素Data[7]後;

25,41,16,98,5,67,9,1,121

鏈表B;121,1,55,9,67,5,98,16,41,25,

刪除元素67後;

121,1,55,9,5,98,16,41,25,

 

下面是楊輝三角的代碼:

#include<iostream>
#include<iomanip>
using namespacestd;
int main(){
const int n=11;
int i,j,a[n][n];
for(i=1;i<n;i++){
a[i][i]=1;
a[i][1]=1;
}
for(i=3;i<n;i++){
for(j=2;j<=i-1;j++)
a[i][j]=a[i-1][j-1]+a[i-1][j];
}
for(i=1;i<n;i++){
for(j=1;j<=i;j++)
cout<<setw(5)<<a[i][j]<<"";
cout<<endl;
}
cout<<endl;
return 0;
}


發佈了54 篇原創文章 · 獲贊 28 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章