线性表:可以在任意位置插入和删除数据元素操作,有n(n>=0)个相同类型数据a0,a1,a2,a3。
1.顺序存储结构
实现顺序存储结构的方法是使用数组。数组把线性表的数据元素存储在一块连续地址空间的内存单元中,这样线性表中逻辑上相邻的数据元素在物理存储地址上也相邻。数据元素间的逻辑上的前驱、后继逻辑关系就表现在数据元素的存储单元的物理前后位置上。
(1)定义:实际上时对数组进行封装,多一个当前长度的变量而已。
需要三个属性:存储空间的的起始位置,数组Data;数组最大的存储容量,Maxsize;线性表当前的长度:length。
数组的长度是存放线性表的存储空间的总长度,一般初始化后不变。而线性表当前长度是线性表中的元素个数,是变化的。
typedef int DataType;//定义抽象数据类型。
#define MaxSize 100 //宏定义
//节点结构
typedef struct
{
int Data[MaxSize];//数组的最大存储单元个数
DataType size; //当前存储的数据元素个数。
}SeqList ;
假设DataType占用c个字节,则第i+1个元素和第i个元素的存储关系为:Loc(ai+1)=Loc(ai)+c
,其中Loc表示获得存储位置的函数。
第i个元素ai的存储位置可以得Loc(ai)=Loc(a1)+(i-1)*c
,任意元素的存储位置都可以计算得到,所以时间复杂度为O(1), 称为随机储存结构。
(2)常见操作:
//初始化ListInitiate(L)
void ListInitiate(SeqList *L)
{
L->size = 0; /*定义初始数据元素个数*/
}
//求当前数据元素个数ListLength(L)
int ListLength(SeqList L)
{
return L.size;
}
//插入数据元素ListInsert(L, i, x)
int ListInsert(SeqList *L, int i, DataType x)
{
int j;
for (j = L->size; j > i; j--)
L->Data[j] = L->Data[j - 1];
/*依次后移*/
L->Data[i] = x; /*插入x*/
L->size++; /*元素个数加1*/
return 1;
}
//删除数据元素ListDelete(L, i, x)
int ListDelete(SeqList *L, int i, DataType *x)
{
int j;
*x = L->Data[i]; /*保存删除的元素到x中*/
for (j = i + 1; j <= L->size - 1; j++)
L->Data[j - 1] = L->Data[j];
/*依次前移*/
L->size--; /*数据元素个数减1*/
return 1;
}
//取数据元素ListGet(L, i, x)
int ListGet(SeqList L, int i, DataType *x)
{
if (i < 0 || i > L.size - 1)
{
printf("参数i不合法! \n");
return 0;
}
else
{
*x = L.Data[i];
return 1;
}
}
注意:在顺序表中插入和删除操作的时间复杂度为:O(n),其他操作的时间复杂度都为O(1)。
优点:
不需要为元素之间的逻辑关系而增加额外的存储空间;
可以快速地存取任意位置的元素。
缺点:
插入和删除需要移动大量的元素。
长度变化较大时,无法确定存储空间的容量
容易造成存储空间的“碎片”