线性表顺序表示又称为顺序存储结构或顺序映像
定义
逻辑上相邻的数据元素存储在物理上相邻的存储单元中的存储结构(中间没有空出存储单元,是连续存储空间)
a1存储位置称作起始位置或基地址
优点:
- 存储密度大(结点本身所占存储量/结点结构所占存储量)
- 任意元素均可随机存取
缺点:
- 在插入、删除某一元素时需要移动大量元素
- 浪费存储空间
- 属于静态存储形式,数据元素的个数不能自由扩充
- 存储空间分配不灵活
- 运算的空间复杂度高
特点:
- 地址连续
- 依次存放
- 随机存取
- 类型相同
- 可以用一维数组表示顺序表
- 线性表长可变,数组长度不可动态定义
- 逻辑位序和物理位序相差1
基本操作
InittList(&L):初始化表,分配内存空间
DestroyList(&L):销毁操作,释放线性表说占用的内存空间
ClearList(&L):重置操作,将线性表重置为空表
Listlensert(&L,i,e):插入操作,在第i个位置上插入指定元素e,L长度+1
ListDelete(&L,i,e):删除操作,删除第i个位置的元素,并用e返回删除元素的值,L长度-1
LocateElem(L,e,comepare()):按值查找,在表中查找具有给定关键字值的元素。compare()是数据元素判定函数,结果返回第一个满足条件的元素位序,元素不存在返回0
GetElem(L,i,&e):按位查找,获取表中第i个位置的元素的值,1<=i<=ListLeng(L)
PriorElem(L,cur_e,&pre_e):若cur_e是L的数据元素且不是第一个,用pre_e返回他的前驱,否则pre_e无意义
NextElem(L,cur_e,&next_e):若pre_e是L的数据元素且不是最后一个,用cur_e返回他的后继,否则cur_e无意义
ListLength(L):求表长,返回线性表L的长度,即L中数据元素的个数
PrintList(L):输出,按前后顺序输出所有元素值
ListEmpty(L):判空,若L为空表,返回true,否则返回false
ListTraverse(&L,visited()):依次对线性表中每个元素调用visited()
基本操作实现
线性表L的初始化(参数用引用)
Status InitList_Sq(SqList &L) { //构造一个空的顺序表L
L.elem=new ElemType[MAXSIZE]; //为顺序表分配空间
if(!L.elem) exit(OVERFLOW); //存储分配失败
L.length=0; //空表长度为0
return OK;
}
销毁线性表L
void DestroyList(SqList &L){
if (L.elem) delete L.elem; //释放存储空间
}
清空线性表L
void ClearList(SqList &L) {
L.length=0; //将线性表的长度置为0
}
求线性表L的长度
int GetLength(SqList L) {
return(L.length);
}
判断线性表L是否为空
int IsEmpty(SqList L) {
if (L.length==0) return 1;
else return 0;
}
顺序表的取值(根据位置i获取相应位置元素的内容)
int GetElem(SqList L,int i,ElemType &e){
if (i<1|i>L.length) return ERROR; //判断i值是否合理,若不合理,返回ERROR
e=L.elem[i-1]; //第i-1的单元存储着第i个数据
return OK;
}
顺序表的查找算法
在L中查找与指定值e相同的数据元素的位置
从表一端开始逐个进行比较,找到返回该元素的位置序号,未找到返回0
int LocateElem(SqList L,ElemType e){ //在线性表L中查找值为e的数据元素,返回其序号
for(i = 0;i < L.length;i++)
if(L.elem[i]==e) return i+1; //查找成功返回序号
return 0; //查找失败返回0
}
//用while
int LocateElem(SqList L,ElemType e){ //在线性表L中查找值为e的数据元素,返回其序号
i=0;
while(i<L.length&&L.elem[i]!=e) i++;
if(i<L.length) return i+1; //查找成功返回序号
return 0; //查找失败返回0
}
平均查找长度(ASL):与给定值进行比较的关键字的个数的期望值
ASL=ΣPiCi(Pi是第i个记录被查找的概率,Ci是找到第i个记录需要比较的次数)
假设每个记录查找概率相等:Pi=1/n
ASL = ΣPiCi = 1/nΣi = (n+1)/ 2
顺序表的插入算法
算法思想:
- 判断插入位置i是否合法
- 判断顺序表的存储空间是否已满,若已满返回ERROR
- 将第n至第i位的元素依次向后移动一个位置,空出第i个位置
- 将要插入的新元素e放入第i个位置
- 表长+1,插入成功返回OK
Status ListInsert_Sq(SqList &L,int i,ElemType e){
if(i<1 || i>L.length+1) return ERROR; //i值不合法
if(L.length==MAXSIZE) return ERROR; //当前储存空间已满
for(j=L.length-1;j>=i-1;j--)
L.elem[j+1]=L.elem[j]; //插入位置及之后的元素后移
L.elem[i-1]=e; //将新元素e放入第i个位置
L.length++; //表长+1
return OK;
}
算法时间主要耗费在移动元素的操作上
插入位置在最后:无需移动(非常快)
插入位置在中间(共n+1种可能):E = 1 / ( n + 1 ) * Σ(1-->n+1) * (n - i + 1) = 1 / (n + 1) * (n + … + 1 + 0) = 1 / (n + 1) * n(n + 1) / 2 = n / 2 (位置i + 移动次数 = n + 1)
插入位置在最前:表中元素全部后移(非常慢)
故插入算法平均时间复杂度为O(n)
顺序表的删除算法
算法思想
- 判断删除位置i是否合法
- 将欲删除的元素保留在e中(若删除元素不需要再使用则不需要这一步可以直接删除)
- 将第i+1至第n为的元素依次向前移动一个位置
- 表长-1,删除成功返回OK
Status ListDelete_Sq(SqList &L,int i){
if((i<1)||(i>L.length-1)) return ERROR; //i值不合法
for(j=i;j<=L.length-1;j++)
L.elem[j-1]=L.elem[j]; //被删除元素之后的元素前移
L.length--; //表长-1
return OK;
}
算法时间主要耗费在移动元素的操作上
删除位置在最后:无需移动(特别快)
删除位置在中间(共n种可能):E = 1 / n * Σ(1-->n) * (n - i) = 1 / n * n(n - 1) / 2 = (n - 1) / 2
删除位置在最前:表中元素全部前移(非常慢)
故删除算法平均时间复杂度为O(n)
顺序表操作算法分析
时间复杂度
查找、插入、删除算法的平均时间复杂度为O(n)
空间复杂度
顺序表操作算法的空间复杂度S(n) = O(1)(没有占用辅助空间)
类C语言有关操作补充
顺序表类型定义
元素复杂类型表示
typedef struct{
float p;
int e;
}Polynomial;
typedef struct{
Polynomial* elem;
int length;
}SqList;
数组定义
数组静态分配
typedef struct{
ElemType data[MaxSize];
int length;
}SqLIST;
数组动态分配
typedef strct{
ElemType* data;
int length;
}SqList;
//可以用malloc分配
L.data=(ElemType*)malloc(sizeof(ElemType)*MaxSize);
头文件:<stdlib.h>
malloc(m)函数:开辟m字节长度的地址空间并返回这段空间的首地址
sizeof(x)运算:计算x长度
free(p)函数: 释放指针p所指变量的储存空间,即彻底删除一个变量
C++动态储存分配
new 类型名T(初值列表)
功能:申请用于存放T类型对象的内存空间,并依初值列表赋以初值结果值
成功:T类型的指针,指向新分配的内存
失败:0(NULL)
int *p1 = new int;
或 int *p1 = new int(10);
p1指向新分配的空间
delete 指针P(delete p1;)
功能:释放指针P所指向的内存,P必须是new操作返回值
C++中的参数传递
形参与实参类型、个数、顺序必须一致
参数传递两种方式:
传值方式
传地址:
- 参数为指针变量
- 参数为引用类型
- 参数为数组名