1. 程式人生 > >線性表---順序表&鏈表

線性表---順序表&鏈表

必須 first 頭指針 amp wrong 順序表 順序存儲 delet nbsp

一、線性表

    1、線性表中的元素是一對一的關系,除了第一個與最後一個元素之外其他數據元素都是首尾相連的。

如果是一對多就用樹來表示,如果是多對多就用網狀來表示。

    2、線性表的兩種存儲結構

  • 順序表:用順序結構保存數據,數據在內存中是連續的。
  • 鏈表:用鏈式存儲結構保存數據,數據在內存中是不連續的。



二、順序表

    1、順序表:

  • 順序表一般使用數組實現,順序表的相關操作與數組相關,一般都是移動數組元素
    • 順序表封裝所需要的三個屬性:
      • 存儲空間的起始位置。數組date的存儲位置就是線性表存儲空間的存儲位置。
      • 線性表的最大存儲容量。數組長度MAXSIZE.
      • 線性表的的當前長度。length

註意:數組的長度與線性表的當前長度是不一樣的。數組的長度是線性表的存儲空間的總長度,一般初始化後不變。而線性表的當前長度是線性表中元素的個數,其大小是會改變的。

    2、順序表的C++代碼實現:模板類的代碼

  •  1 #include<iostream>
     2 using namespace std;
     3 
     4 const int MaxSize = 100;
     5 template <class DataType>
     6 class SeqList
     7 {
     8 public:
     9     SeqList(){length=0;}            
    
    10 SeqList(DataType a[],int n); 11 ~SeqList(){} 12 int Length(){return length;} 13 DataType Get(int i); 14 int Locate(DataType x); 15 void Insert(int i,DataType x); 16 DataType Delete(int i); 17 void PrintList();
    18 private: 19 DataType data[MaxSize]; //順序表使用數組實現 20 int length; //存儲順序表的長度 21 }; 22 23 template <class DataType> 24 SeqList<DataType>::SeqList(DataType a[],int n) 25 { 26 if(n>MaxSize) throw "wrong parameter"; 27 for(int i=0;i<n;i++) 28 data[i]=a[i]; 29 length=n; 30 } 31 32 template <class DataType> 33 DataType SeqList<DataType>::Get(int i) 34 { 35 if(i<1 && i>length) throw "wrong Location"; 36 else return data[i-1]; 37 } 38 39 template <class DataType> 40 int SeqList<DataType>::Locate(DataType x) 41 { 42 for(int i=0;i<length;i++) 43 if(data[i]==x) return i+1; 44 return 0; 45 } 46 47 template <class DataType> 48 void SeqList<DataType>::Insert(int i,DataType x)//插入過程中應註意元素移動的方向必須從最後一個元素開始移動,如果表滿了發生上溢出,如果插入位置不合理,則引發位置異常。 49 { 50 if(length>=MaxSize) throw "Overflow"; 51 if(i<1 || i>length+1) throw "Location"; 52 for(int j=length;j>=i;j--) 53 data[j]=data[j-1]; 54 data[i-1]=x; 55 length++; 56 } 57 58 template <class DataType> 59 DataType SeqList<DataType>::Delete(int i)//註意算法中元素移動的方向,移動元素之前必須取出被刪的元素,如果表為空則引發下溢出,如果刪除位置不合理則是引發刪除位置異常 60 { 61 int x; 62 if(length==0) throw "Underflow"; 63 if(i<1 || i>length) throw "Location"; 64 x = data[i-1]; 65 for(int j=i;j<length;j++) 66 data[j-1] = data[j]; 67 length--; 68 return x; 69 } 70 71 template <class DataType> 72 void SeqList<DataType>::PrintList() 73 { 74 for(int i=0;i<length;i++) 75 cout<<data[i]<<endl; 76 } 77 78 int main() 79 { 80 SeqList<int> p; 81 p.Insert(1,5); 82 p.Insert(2,9); 83 p.PrintList(); 84 p.Insert(2,3); 85 cout<<p.Length()<<endl; 86 p.PrintList(); 87 cout<<p.Get(3)<<endl; 88 p.Delete(2); 89 p.PrintList(); 90 return 0; 91 }

    3、順序表存儲的優缺點:

  • 優點:
  • 隨機訪問特性,按位查找時間復雜度為O(1),存儲密度高
  • 邏輯上相鄰的元素物理上也相鄰,即在內存中存儲是連續的
  • 無需為表中元素之間的邏輯關系而增加額外的存儲空間。
  • 缺點:
  • 插入和刪除需要移動大量元素
  • 當線性表長度長度變化較大時,難以確定存儲空間的容量
  • 造成存儲空間的碎片



三、鏈表

    1、為什麽要使用鏈表:

  • 順序表的長度是固定的,如果超出分配的長度就會造成溢出,如果存放的數據太少就會造成空間浪費。
  • 在插入元素和刪除元素時(尤其是插入和刪除的位置不在尾部時),會移動大量元素,造成性能和效率低下。
  • 使用鏈表可以很好的避免順序表中出現的問題。

    2、鏈表在內存中的存儲是不連續的,大小不固定。鏈表根據構造方式的不同可以分為

      • 單向鏈表
      • 單向循環鏈表
      • 雙向鏈表
      • 雙向循環鏈表

    3、鏈式存儲的實現方式

  • template<typename DateType>
    struct Node
    {
    DateType date;//存儲數據
    Node<DateType> *next;//存儲下一個結點得到地址
    }

    4、單鏈表的模板類的C++代碼實現:

  • 頭指針:把指向第一個節點的指針稱為頭指針,每次訪問鏈表時都可以從這個頭指針依次遍歷鏈表中的每個元素
  • 1 struct node firs;2 struct node *head=&first; 這個head指針就是頭指針。
      • 頭指針的意義在於:當訪問鏈表時,總要知道鏈表存儲在什麽位置(從何處開始訪問),由於鏈表的特性(next指針),知道了頭指針那麽整個鏈表的元素都能夠被訪問,所以頭指針的存在是很必要的。
  • 單鏈表的結構:單鏈表的模板類的結構:
    • template<class DataType>
      class LinkList
      {
      public:
          LinkList();                     
          LinkList(DataType a[], int n);  
          ~LinkList();                    
          int Length();                   
          DataType Get(int i);            
          int Locate(DataType x);         
          void Insert(int i, DataType x); 
          DataType Delete(int i);         
          void PrintList();               
      private:
          Node<DataType> *first;          
      };

      特點:用一組任意的存儲單元存儲線性表的數據元素,這組存儲單元可以在內存中未被占用的任意位置

    • 順序存儲結構每個數據元素只需要一個存儲位置就可以了,而在鏈式存儲結構中,除了要存儲數據信息外還要存儲它的後繼元素的存儲地址
    • 單鏈表中即使知道節點位置也不能直接訪問,需要從頭指針開始逐個節點向下搜索,平均時間復雜度是O(n).
    • 刪除操作時需要註意表尾的特殊情況,此時雖然被刪節點不存在,但其前驅結點卻存在。因此僅當被刪節點的前驅結點存在且不是終端結點時,才能確定被刪節點存在,時間復雜度為O(n).

  •   1 #include<iostream>
      2 using namespace std;
      3 
      4 template<class DataType>
      5 struct Node
      6 {
      7     DataType data;
      8     Node<DataType> *next;
      9 };
     10 
     11 template<class DataType>
     12 class LinkList
     13 {
     14 public:
     15     LinkList();                     
     16     LinkList(DataType a[], int n);  
     17     ~LinkList();                    
     18     int Length();                   
     19     DataType Get(int i);            
     20     int Locate(DataType x);         
     21     void Insert(int i, DataType x); 
     22     DataType Delete(int i);         
     23     void PrintList();               
     24 private:
     25     Node<DataType> *first;          
     26 };
     27 
     28 template<class DataType>
     29 LinkList<DataType>::LinkList()
     30 {
     31     first = new Node<DataType>;
     32     first->next = NULL;
     33 }
     34 
     35 template<class DataType>
     36 LinkList<DataType>::LinkList(DataType a[], int n)
     37 {
     38     first = new Node<DataType>;
     39     first->next = NULL;
     40     for (int i = 0; i < n; i++)
     41     {
     42         Node<DataType> *s = new Node<DataType>;
     43         s->data = a[i];
     44         s->next = first->next;
     45         first->next = s;
     46     }
     47 }
     48 
     49 template<class DataType>
     50 LinkList<DataType>::~LinkList()
     51 {
     52     while (first != NULL)
     53     {
     54         Node<DataType>* q = first;
     55         first = first->next;
     56         delete q;
     57     }
     58 }
     59 
     60 template<class DataType>
     61 int LinkList<DataType>::Length()
     62 {
     63     Node<DataType>* p = first->next;
     64     int count = 0;
     65     while (p != NULL)
     66     {
     67         p = p->next;
     68         count++;
     69     }
     70     return count;
     71 }
     72 
     73 template<class DataType>
     74 DataType LinkList<DataType>::Get(int i)
     75 {
     76     Node<DataType>* p = first->next;
     77     int count = 1;
     78     while (p != NULL && count<i)
     79     {
     80         p = p->next;
     81         count++;
     82     }
     83     if (p == NULL) throw "Location";
     84     else return p->data;
     85 }
     86 
     87 template<class DataType>
     88 int LinkList<DataType>::Locate(DataType x)
     89 {
     90     Node<DataType> *p = first->next;
     91     int count = 1;
     92     while (p != NULL)
     93     {
     94         if (p->data == x) return count;
     95         p = p->next;
     96         count++;
     97     }
     98     return 0;
     99 }
    100 
    101 template<class DataType>
    102 void LinkList<DataType>::Insert(int i, DataType x)
    103 {
    104     Node<DataType> *p = first;
    105     int count = 0;
    106     while (p != NULL && count<i - 1)
    107     {
    108         p = p->next;
    109         count++;
    110     }
    111     if (p == NULL) throw "Location";
    112     else {
    113         Node<DataType> *s = new Node<DataType>;
    114         s->data = x;
    115         s->next = p->next;
    116         p->next = s;
    117     }
    118 }
    119 
    120 template<class DataType>
    121 DataType LinkList<DataType>::Delete(int i)
    122 {
    123     Node<DataType> *p = first;
    124     int count = 0;
    125     while (p != NULL && count<i - 1)
    126     {
    127         p = p->next;
    128         count++;
    129     }
    130     if (p == NULL || p->next == NULL) throw "Location";
    131     else {
    132         Node<DataType> *q = p->next;
    133         int x = q->data;
    134         p->next = q->next;
    135         return x;
    136     }
    137 }
    138 
    139 template<class DataType>
    140 void LinkList<DataType>::PrintList()
    141 {
    142     Node<DataType> *p = first->next;
    143     while (p != NULL)
    144     {
    145         cout << p->data << endl;
    146         p = p->next;
    147     }
    148 }
    149 
    150 int main()
    151 {
    152     LinkList<int> p;
    153     p.Insert(1, 6);
    154     p.Insert(2, 9);
    155     p.PrintList();
    156     p.Insert(2, 3);
    157     p.PrintList();
    158     cout << p.Get(2) << endl;
    159     cout << p.Locate(9) << endl;
    160     cout << p.Length() << endl;
    161     p.Delete(1);
    162     p.PrintList();
    163     return 0;
    164 }
  • 鏈表存儲的優缺點:
      • 優點:
      • 插入刪除不需要移動其他元素,只需要改變指針。
      • 鏈表各個結點在內存中的存儲空間不要求連續,空間利用率高
      • 缺點:查找需要遍歷操作,比較麻煩。



四、其他線性表

    1、單向循環鏈表

    2、雙向鏈表

    3、雙向循環鏈表

線性表---順序表&鏈表