线性表---顺序表&链表

一、线性表

    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、双向循环链表

原文地址:https://www.cnblogs.com/southcyy/p/10326139.html