计算机基础数据结构讲解第五篇-顺序表

  本篇及下一篇文章介绍线性表,包括线性表的定义及顺序表和链表的表示和方法。有关b树的补充等到之后进行介绍。

一:线性表的定义和基本操作

  线性表是具有相同数据类型数据元素的有限序列集合,当线性表内没有元素时,是一个空表用a(i)代表第i个数据元素,第一个元素为表头,最后一个元素为表尾。除第一个元素外,每个元素都有一个直接前驱;除最后一个元素外,每个元素都有一个直接后继。
  线性表是一个逻辑结构,表示元素之间一一对应的关系;而顺序表和链式表是指存储结构。
  线性表的基本操作是最基本的操作,包括:
  InitList(&L):初始化一个空的线性表。
  Length(L):求表长。
  LocateElem(L,e):在表中查找给定关键字值的元素。
  GetElem(L,i):在表中查找第i个位置的元素的值。
  ListInsert(&L,i,e):在表中的第i个位置插入元素e。
  ListDelete(&L,i,&e):删除表中第i个位置元素,并用e返回。
  PrintList(L):输出线性表中的所有元素值。
  Empty(L):判断线性表是否为空。
  DestoryList(&L):销毁线性表,并释放线性表所占用的内存空间。
  这里的"&"表示的是c++里面的引用调用,传入指针变量的时候要对传入的指针进行改变,则会用到指针变量的引用型。在C语言的采用指针的指针也可以达到同样的效果。

二:线性表的顺序存储

1.定义

  线性表的顺序存储又称顺序表,用一组地址连续的存储单元依次存储线性表的数据元素,使逻辑上相邻的元素物理位置上也相邻。i为元素a(i)的位序,特点是表中的逻辑顺序与其物理顺序相同。
  有关顺序表的基本模型和结构这里就不详细介绍了,主要是顺序表是依靠数组实现的,要注意的是:线性表中元素的位序是从1开始的,而数组中元素的位序是从0开始的。

2.顺序存储数据类型

  由于顺序表是由数组实现的,我们知道一维数组可以是静态分配的,也可以是动态分配的。静态分配因为空间和大小有限,一旦占满,再加入新的数据将会产生溢出,导致程序崩溃;动态分配,数组空间是在需要时通过动态存储语句分配,可以不断开辟新的存储空间,扩充存储空间,所以更高效。
  顺序存储数据类型实现的代码如下:

// 顺序表的静态存储
#define MaxSize 50          //顺序表最大长度
typedef struct{
  ElemType data[MaxSize];  //顺序表数据元素
  int length;              //顺序表当前长度
}SqList;                   //顺序表结构体类型定义

//顺序表的动态存储
#define InitSize 100       //表长度的初始定义
typedef struct{
  ElemType *data;          //动态分配数组指针
  int MaxSize;length;      //数组最大容量和当前个数
}SeqList;                  //顺序表结构体类型定义

  C语言初始动态分配语句是:
L.data= (ElemType)malloc(sizeof(ElemType)InitSize);
  C++的动态分配语句是:
L.data = new ElemType(InitList);

3.顺序表基本操作的实现(代码写的是静态存储,动态存储类似)

(1)插入操作

  在顺序表L的第i个位置插入新元素e。如果i的输入不合法,则返回false,表示插入失败;否则将原顺序表的第i个元素及其后面的所有元素右移一个位置,腾出一个空间插入新元素e。顺序表的长度加一,插入成功,返回true。插入位置范围从1到L.length+1,代码如下:

bool ListInsert(SqList &L,int i,ElemType e){
  if(i < 1|| i > Length + 1)
    return false;
  if(L.length >= MaxSize)     //当前存储空间已满,不能插入
    return false;
  for(int j = L.length;j >= i;j--){     //将i及之后的元素后移
    L.data[j] = L.data[j-1];
  }
  L.data[i-1] = e;  //数组从0开始
  L.length++;
  return true;
}

  插入操作的最好情况是在表尾插,后移操作不再进行;最坏情况是在表头插,后移n次。而平均情况下,插入的平均时间复杂度是O(n)。

(2)删除操作

  删除表中的第i个位置的元素,成功返回true,并将被删除的元素用引用变量e返回,否则返回false,也需要移动元素位置。删除位置范围从1到L.length,代码如下:

bool ListDelete(SqList &L,int i,ElemType &e){
  if(i < 1|| i > Length)
    return false;
  e = L.data[i-1];
  for(int j = i;j < L.length;j++){     //将i及之后的元素前移
    L.data[j-1] = L.data[j];
  }
  L.length--;
  return true;
}

  插入操作的最好情况是在表尾插,前移操作不再进行;最坏情况是在表头插,前移n-1个数据元素。而平均情况下,删除的平均时间复杂度是O(n)。

(3)简单的按值查找

  在顺序表中查找第一个元素值等于e的元素,并返回其位序。代码如下:

int LocateElem(SqList L,ElemType e){
  int i;
  for(i = 0;i < L.length;i++)
    if(L.data[i] == e)
      return i + 1;             //位序从一开始
  return 0;
}

  最好情况在表头比较一次,在表尾或不存在比较n次,按值查找的平均时间复杂度为O(n)。

4.顺序表的特点

  优点:随机访问,在O(1)的时间内找到指定的元素。存储密度高,每个结点只存储数据元素。
  缺点:插入和删除操作需要移动大量元素。

posted @ 2020-08-28 23:00  一只帅气的IT小昂  阅读(1090)  评论(0编辑  收藏  举报