資料結構---------------線性表(下篇)之單鏈表
單鏈表
特點:儲存空間不連續
結點(資料元素組成):資料域(儲存資料)和指標域(指標)A1
若用p來指向 則資料域為p->date 指標域為p->next
鏈式儲存結構: 單鏈表、迴圈連結串列、雙向連結串列根據連結串列結點所含指標個數、指標指向、指標連線方式可將連結串列分為單鏈表、迴圈連結串列、雙向連結串列、二叉連結串列、十字連結串列、鄰接表、鄰接多重表等
非線性結構:二叉連結串列、十字連結串列、鄰接表、鄰接多重表等
//-----------------單鏈表的儲存結構------------
typedef struct LNode { ElemType date; //結點資料域 struct LNode *next;//結點指標域 } LNode,*LinkList //LinkList 為指向結構體LNoded的指標型別
1)對於LNode 和 *LinkList 只寫一個就可以 兩者都是結構體的型別的名稱
區別在於第二個為指標型別 也就是說 如果定義了一個LNode *p 與定義一個LinkList p 是等價的存在;
① p為指向單鏈表中某結點的指標,是指標變數,*p代表該結點,是結點變數;
②LNode *
2)單鏈表是由表頭指標唯一確定的,換句話說,只要找到單鏈表的頭指標,就能順著找到這串鏈,所以單鏈表可以用頭指標(表中的第一個結點)的名字來命名,若頭指標名是L,則簡稱改連結串列為表L;
辨析 首元結點、頭結點、頭指標
首元結點是指連結串列中儲存第一個資料元素的結點
頭指標是指向連結串列中第一個結點的指標
頭結點是在第一個資料元素之前附近設立的一個結點,其指標域儲存首元結點的地址 作用
有頭結點時 頭指標指向頭結點 無頭結點時 頭指標就指向首元結點
特殊語句
1)p=q;
2) p=q->next;
3) p->next=q;
4) p->next=q->next;
單鏈表基本操作的實現
1)初始化
【演算法描述】
Status InitList(LinkList &L) // 構造一個空的單鏈表
{
L=new LNode; //生成的新結點作為頭結點,用頭指標L指向頭結點
L->next=NULL; //頭結點的指標置空
return 1;
}
Status InitList(LinkList &L) // 構造一個空的單鏈表
{
L=NULL; //不帶頭結點,頭指標置空
}
2)求連結串列長度
【演算法描述】
int ListLength(LinkList L)
{
LinkList p; //定義一個新指標
p=L->next; //指向第一個資料元素 沒有頭結點時 p=L;
int k=0; //計數器
while(p) //指標不為空,迴圈繼續
{
k++;
p=p->next;//指標指向下一個結點
}
return k; //返回連結串列長度
}
【演算法分析】
求連結串列長度時需要將整個鏈跑一邊 所以 時間複雜度為O(n);
3)銷燬連結串列
【演算法描述】
void DestroyList(LinkList &L)
{
LinkList p=L->next; //定義新節點並指向頭指標
while(p!=NULL) //指標不為空 繼續
{
L->next=p->next;//看下圖
delete p; //釋放該結點
p=L->next; //重複操作
}
delete L; //釋放頭結點
}
L->next=p->next; //即L的指標域存放的是下下一個結點的地址
【演算法分析】
依舊是要跑整個鏈 所以 時間複雜度為O(n);
4)取值
【演算法分析】
Status GetElem(LinkList L,int i,ElemType &e)
{ //在帶頭結點的單鏈表L中根據序號i獲得元素的值,用e返回L中第i個數據元素的值
LinkList p;int j;
p=L->next;j=1; //初始化p指向首元結點,計數器j初賦值為1
while(p&&j<i) //順鏈域向後掃描,直到p為空或p指向第i個元素,一共跑i-1次
{
p=p->next; //指向下一個結點
++j;
}
if(!p||j<i) return -2; //i值不合法i>n 或 i<=n
e=p->date; //取第i個結點的資料域
}
【演算法分析】
最好情況O(1) 最壞O(n) 所以 演算法時間複雜度為 O(n);
5)查詢
【演算法描述】
LNode *LocateEle(LinkList L,ElemType e)
{//在帶頭結點的單鏈表L中查詢元素為e的元素 返回地址
LinkList p;
p=L->next; //初始化,p指向首元結點
while(p && p->date!=e) //順鏈域向後掃描,直到p為空或p所指結點資料等於e
p=p->next; //p指向下一個結點
return p; // 查詢成功返回值為e的結點的地址,查詢失敗p為NULL
}
【演算法分析】
最好情況O(1) 最壞O(n) 所以 演算法時間複雜度為 O(n);
6)插入
插入分兩種情況 1)p之後插入新節點s
2)p之前插入新節點s 帶頭結點 不帶頭結點
1) p之後插入新節點s
先1後2
【演算法描述】
void ListAfterInsert(LinkList &L,LNode *p,LNode *s)
{//在單鏈表L中p結點之後插入一個結點s
s->date =e;
s->next =NULL; //給結點賦初值
s->next =p->next; //第一步 s的指標域存放p下一個結點的地址
p->next =s; //第二步 p的指標域存放s的
}
【演算法分析】
不需要遍歷 時間複雜度為O(1);
2)p之前插入新節點s
帶頭結點
【演算法描述】
void ListAfterInsert(LinkList &L,LNode *p,LNode *s)
{//在帶頭結點的單鏈表L中p結點之前插入結點s
LinkList q=L; //定義新指標並賦予頭指標
while(q->next!=p) //判斷是否為p結點的前驅
q=q->next; //指向下一個結點
q->next=s; //將s的地址賦給q的指標域
s->next=p; //將p的地址賦給s的指標域
}
不帶頭結點 比帶頭指標多一種判斷
【演算法描述】
void ListAfterInsert(LinkList &L,LNode *p,LNode *s)
{//在不帶頭結點的單鏈表L中p結點之前插入結點s
if(p==L) //判斷是否為頭指標
{
s->next =L; //s指標域存放頭指標地址
L=s; //s為頭指標
}
else
{
LinkList q=L; //定義新指標並賦予頭指標
while(q->next!=p) //判斷是否為p結點的前驅
q=q->next; //指向下一個結點
q->next=s; //將s的地址賦給q的指標域
s->next=p; //將p的地址賦給s的指標域
}
}
【演算法分析】
要找到插入點之前的結點 所以要遍歷 時間複雜度為O(n);
6)刪除
帶頭結點
【演算法描述】
void ListDelete(LinkList &L,LNode *p,Elemtype &e)
{//在帶頭結點的單鏈表L中刪除p結點 並用e返回p的資料元素
LinkList q=L; //定義新指標並賦予頭指標
while(q->next!=p) //判斷是否為p結點的前驅
q=q->next; //指向下一個結點
q->next=p->next; //將p下個結點的地址賦給q的指標域
e=p->date; //e 儲存p的資料元素
delete p; //釋放記憶體
}
不帶頭結點
【演算法描述】
void ListDelete(LinkList &L,LNode *p,Elemtype &e)
{//在帶頭結點的單鏈表L中刪除p結點 並用e返回p的資料元素
if(p==L) //判斷是否為頭指標
L=L->next; //L的下個結點的地址賦給L
else
{
LinkList q=L; //定義新指標並賦予頭指標
while(q->next!=p) //判斷是否為p結點的前驅
q=q->next; //指向下一個結點
q->next=p->next; //將p下個結點的地址賦給q的指標域
}
e=p->date; //e 儲存p的資料元素
delete p; //釋放記憶體
}
【演算法分析】
需要找到待刪除結點之前的結點 遍歷 時間複雜度為O(n);
單鏈表的簡單應用(int)
#include<iostream>
using namespace std;
typedef struct Lnode
{
int date;
struct Lnode *next;
}Lonode,*linklist;
void Getelem(linklist L,int i,int e)//取值
{
Lnode *p;
p=L->next;
int j=1;
while(p&&j<i)
{
p=p->next;
++j;
}
e=p->date;
cout<<"第"<<i<<"個元素的值為:"<<e<<endl<<endl;
}
void Locateelem(linklist L,int e)//查詢
{
Lnode *p;
int i=1;
p=L->next;
while(p&&p->date!=e)
{
p=p->next;
i++;
}
cout<<"查詢的元素在該連結串列的第"<<i<<"個位置"<<endl;
cout<<"查詢元素的地址為:"<<p<<endl<<endl;
}
void Maxelem(linklist L)//取最大值
{
Lnode *p;
p=L->next->next;
int max=L->next->date;
while(p)
{
max=max>p->date?max:p->date;
p=p->next;
}
cout<<"該連結串列中的最大值為:"<<max<<endl<<endl;
}
void linkInsert(linklist &L,int i,int e)//插入
{
linklist p;
p=L;
int j=0;
while(p&&j<i-1)
{
p=p->next;
++j;
}
linklist s;
s=new Lnode;
s->date =e;
s->next=p->next;
p->next=s;
cout<<"元素"<<e<<"已成功插入!!!"<<endl<<endl;
}
void linkdelete(linklist &L,int i)//刪除
{
linklist p;
p=L;
int j=0;
while(p&&j<i-1)
{
p=p->next;
++j;
}
linklist q;
q=p->next;
p->next=q->next;
delete q;
cout<<"第"<<i<<"位置上的元素已成功刪除!!!"<<endl<<endl;
}
void creatlist_h(linklist &L,int n)//頭插法
{
cout<<"請倒敘輸入資料:";
Lnode *p;
L=new Lnode;
L->next=NULL;
for(int i=n;i>0;i--)
{
p=new Lnode;
cin>>p->date;
p->next=L->next;
L->next=p;
}
}
void creatlist_d(linklist &L,int n)//尾插法
{
cout<<"請輸入資料:";
L=new Lnode;
L->next=NULL;
Lnode *p;
linklist r;
r=L;
for(int i=0;i<n;i++)
{
p=new Lnode;
cin>>p->date;
p->next=NULL;
r->next=p;
r=p;
}
}
void traverse(linklist L)//遍歷
{
cout<<"該單鏈表的資料為:";
Lnode *p=L->next;
while(p)
{
cout<<p->date<<" ";
p=p->next;
}
cout<<endl;
}
int main()
{
linklist L;
int n;
int m;
while(1)
{
cout<<"1,建立"<<endl;
cout<<"2,取值"<<endl;
cout<<"3,查詢"<<endl;
cout<<"4,取最大值"<<endl;
cout<<"5,插入"<<endl;
cout<<"6,刪除"<<endl;
cout<<"7,遍歷"<<endl;
cout<<"0,結束"<<endl;
cout<<"請輸入您的操作:";
cin>>m;
if(m==1)
{
int p;
cout<<"1,頭插法"<<endl;
cout<<"2,尾插法"<<endl;
cout<<"0,返回上一步 "<<endl<<endl;
cout<<"輸入你的選擇:";
cin>>p;
while(p)
{
if(p==1)
{
cout<<"連結串列長度:";
cin>>n;
creatlist_h(L,n);
}
else if(p==2)
{
cout<<"連結串列長度:";
cin>>n;
creatlist_d(L,n);
}
cout<<"請輸入你的選擇:";
cin>>p;
}
}
else if(m==2)
{
int i,e=0;
cout<<"請輸入待取值的位置:";
cin>>i;
Getelem(L,i,e);
}
else if(m==3)
{
int e;
cout<<"請輸入需查詢的元素:";
cin>>e;
Locateelem(L,e);
}
else if(m==4)
{
Maxelem(L);
}
else if(m==5)
{
int i,e;
cout<<"請輸入插入元素的位置:";
cin>>i;
cout<<endl<<"請輸入帶插入元素:";
cin>>e;
linkInsert(L,i,e);
}
else if(m==6)
{
int i;
cout<<"請輸入要刪除元素的位置:";
cin>>i;
linkdelete(L,i);
}
else if(m==7)
{
traverse(L);
}
else if(m==0)
{
return 0;
}
else
{
cout<<"輸入錯誤!!!"<<endl;
}
cout<<endl;
}
return 0;
}
over~~~~~~~~~~~~
才怪ヽ( ̄▽ ̄)ノ
下篇 順序表和連結串列的比較