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


    一、线性表

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

  • 相关阅读:
    BAT 批处理脚本教程
    javascript定时器
    使用命令行打开文件夹并显示
    用cmd加密文件夹
    烟波钓叟歌概述讲解
    奇门遁甲的起源
    八卦基本知识
    word2vec和word embedding有什么区别?
    Privoxy shadowscocks代理
    Elasticsearch源码分析—线程池(十一) ——就是从队列里处理请求
  • 原文地址:https://www.cnblogs.com/southcyy/p/10326139.html
Copyright © 2020-2023  润新知