數據結構:線性表(鏈表)


1、鏈表

(1)概念

  • 結點在存儲器中的位置是任意的,即邏輯上相鄰的數據元素在物理上不一定相鄰
  • n 個結點由指針鏈組成一個鏈表。它是線性表的鏈式存儲映像,稱為線性表的鏈式存儲結構

(2)結點組成

  • 數據域:存儲元素數值數據
  • 指針域:存儲直接后繼結點的存儲位置

(3)單鏈表、雙鏈表與循環鏈表:

  • 結點只有一個指針域的鏈表,稱為單鏈表或線性鏈表
  • 有兩個指針域的鏈表,稱為雙鏈表。雙向鏈表能夠克服單鏈表查詢前驅結點必須從表頭出發的問題,雙向鏈表有兩個指針域分別指向自己的前驅結點和后繼結點,查找的時間復雜度為O(1)
  • 首尾相接的鏈表稱為循環鏈表,從循環鏈表中的任何一個結點的位置都可以找到其他所有結點,而單鏈表做不到 

(4)頭指針、頭結點和首元結點 

  • 頭指針是指向鏈表中第一個結點的指針
  • 首元結點是指鏈表中存儲第一個數據元素a1的結點
  • 頭結點是在鏈表的首元結點之前附設的一個結點,數據域內只放空表標志和表長等信息。頭結點的數據域可以為空,也可存放線性表長度等附加信息,但此結點不能計入鏈表長度值。

       

 

 

 (5)在鏈表中設置頭結點有什么好處

  • 便於首元結點的處理:首元結點的地址保存在頭結點的指針域中,所以在鏈表的第一個位置上的操作和其它位置一致,無須進行特殊處理
  • 便於空表和非空表的統一處理:無論鏈表是否為空,頭指針都是指向頭結點的非空指針,因此空表和非空表的處理也就統一了

 (6)特點

  • 結點在存儲器中的位置是任意的,即邏輯上相鄰的數據元素在物理上不一定相鄰
  • 訪問時只能通過頭指針進入鏈表,並通過每個結點的指針域向后掃描其余結點,所以尋找第一個結點和最后一個結點所花費的時間不等

(7)優缺點

優點:

  • 數據元素的個數可以自由擴充
  • 插入、刪除等操作不必移動數據,只需修改鏈接指針,修改效率較高

缺點:

  • 存儲密度小
  • 存取效率不高,必須采用順序存取,即存取數據元素時,只能按鏈表的順序進行訪問

(8)結構定義

typedef struct Lnode
{
     ElemType   data;       //數據域
     struct LNode  *next;   //指針域
}LNode,*LinkList;   // *LinkList為Lnode類型的指針

(9)初始化

Status InitList_L(LinkList &L){ 
   L=new LNode;  //生成新結點作頭結點,用頭指針L指向頭結點。                      
   L->next=NULL; //頭結點的指針域置空    
   return OK; 
} 

 

2、鏈表的基本操作

(1)銷毀

Status DestroyList_L(LinkList &L)
{
    LinkList p;
       while(L)
        {
            p=L;  
            L=L->next;
            delete p;  
        }
     return OK;
 }

(2)清空

Status ClearList(LinkList & L){
  // 將L重置為空表 
   LinkList p,q;
   p=L->next;   //p指向第一個結點
   while(p)       //沒到表尾 
   { 
q=p->next;
delete p;
p=q;
} L
->next=NULL; //頭結點指針域為空 return OK; }

與銷毀不同,清空的時候會保留頭結點

(3)求表長

p=L->next;  
i=0;             
while(p)
{i++;
p=p->next;
}
int  ListLength_L(LinkList L){
//返回L中數據元素個數
    LinkList p;
    p=L->next;  //p指向第一個結點
     i=0;             
     while(p){//遍歷單鏈表,統計結點數
           i++;
           p=p->next;    
}
return i; }

(4)判斷是否為空

int ListEmpty(LinkList L)
{ 
    //若L為空表,則返回1,否則返回0 
   if(L->next)   //非空 
     return 0;
   else
     return 1;
 }

 

3、對鏈表的操作

(1)添加元素:在L中第i個元素之前插入數據元素e 

Status ListInsert_L(LinkList &L,int i,ElemType e){ 
     p=L;j=0; 
      while(p&&j<i−1){p=p->next;++j;}    //尋找第i−1個結點 
      if(!p||j>i−1)return ERROR;    //i大於表長 + 1或者小於1  
      s=new LNode;            //生成新結點s 
      s->data=e;                         //將結點s的數據域置為e 
      s->next=p->next;                     //將結點s插入L中 
      p->next=s; 
      return OK; 
}//ListInsert_L 

時間復雜度:O(1)

(2)刪除元素:將線性表L中第i個數據元素刪除

 Status ListDelete_L(LinkList &L,int i,ElemType &e){
    p=L;j=0; 
    while(p->next &&j<i-1){                  //尋找第i個結點,並令p指向其前驅 
        p=p->next; ++j; 
    } 
    if(!(p->next)||j>i-1) return ERROR; //刪除位置不合理 
    q=p->next;                                        //臨時保存被刪結點的地址以備釋放 
    p->next=q->next;                       //改變刪除結點前驅結點的指針域 
    e=q->data;                                     //保存刪除結點的數據域 
    delete q;                                     //釋放刪除結點的空間 
 return OK; 
}//ListDelete_L 

時間復雜度:O(1)

(3)查找:在線性表L中查找值為e的數據元素

int LocateELem_L (LinkList L,Elemtype e) {
 //返回L中值為e的數據元素的位置序號,查找失敗返回0 
  p=L->next; j=1;
  while(p &&p->data!=e)  
        {p=p->next;  j++;}                  
  if(p) return j; 
  else return 0;
} 

時間復雜度:O(n)

 

4、單鏈表的創建

(1)前插法

void CreateList_F(LinkList &L,int n){ 
     L=new LNode; 
      L->next=NULL; //先建立一個帶頭結點的單鏈表 
      for(i=n;i>0;--i){ 
        p=new LNode; //生成新結點 
        cin>>p->data; //輸入元素值 
        p->next=L->next;L->next=p;     //插入到表頭 
     } 
}//CreateList_F 
  • 生成新結點
  • 將讀入數據存放到新結點的數據域中
  • 將該新結點插入到鏈表的前端

(2)尾插法

void CreateList_L(LinkList &L,int n){ 
      //正位序輸入n個元素的值,建立帶表頭結點的單鏈表L 
      L=new LNode; 
      L->next=NULL;     
      r=L;                                     //尾指針r指向頭結點 
      for(i=0;i<n;++i){ 
        p=new LNode;                //生成新結點 
        cin>>p->data;                  //輸入元素值 
        p->next=NULL; r->next=p;       //插入到表尾 
        r=p;                                       //r指向新的尾結點 
      } 
}//CreateList_L 
  • 從一個空表L開始,將新結點逐個插入到鏈表的尾部,尾指針r指向鏈表的尾結點
  • 初始時,r同L均指向頭結點。每讀入一個數據元素則申請一個新結點,將新結點插入到尾結點后,r指向新結點

 

5、線性表和鏈表的比較

(1)空間

  • 存儲空間:順序表需要預先分配,會導致空間閑置或溢出現象,鏈表動態分配,不會出現存儲空間閑置或溢出現象
  • 存儲密度:線性表等於1,鏈表小於1

(2)時間

  • 取數據:順序表是隨機存取,時間復雜度為O(1),鏈表是順序存取,時間復雜度為O(n)
  • 插入刪除:順序表需要移動元素,時間復雜度為O(n),鏈表不需要,時間復雜度為O(1)

(3)適用范圍

線性表

 表長變化不大,且能事先確定變化的范圍
很少進行插入或刪除操作,經常按元素位置序號訪問數據元素

鏈表

長度變化較大
頻繁進行插入或刪除操作

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM