目录
一、线性表的顺序表示
1.1定义
线性表的顺序表示又称为顺序存储结构或顺序映像。
顺序存储定义:把逻辑上相邻的数据元素存储在物理上相邻的存储单元中的存储结构。简言之,逻辑上(存储顺序)相邻,物理上(存放位置)也相邻。
注:逻辑位序和物理位序相差1,即a1存储在数组下标为0的位置,a2存储在数组下标为1的位置。
如线性表:(a1,a2,...,a(i-1),a(i),a(i+1),...a(n))
a1 a2 ... a(i-1) a(i) a(i+1) ... a(n)
线性表的第1个数据元素a1的存储位置,称作线性表的起始位置或基地址。
注:顺序存储结构必须是依次存储,地址连续的,即中间没有空出存储单元。这样才是一个典型的线性表顺序存储结构。所以我们知道某个元素的存储位置就可以计算其他元素的存储位置。
(随机存取是顺序存储结构的优点)
如线性表(1,2,3,4,5,6)的存储结构:
1 2 3 4 5 6
1 2 3 4 5 6
而这样的存储结构就不是一个线性表顺序存储结构,因为它的地址是不连续的。
1.2顺序表中元素存储位置的计算
计算方法:
假设每个元素占l个存储单元,则第i+1个元素的存储位置与第i个元素的存储位置之间满足关系:
LOC(a(i+1))=LOC(a(i))+l
由此得到公式:
LOC(a(i))=LOC(a1)+(i-1)×l,LOC(a1)为基地址
例如,
①每个元素占用8个存储单元,a(i)存储位置是2000单元,则a(i+1)存储位置是(2000+8=)2008单元。
②每个元素占用8个存储单元,a1存储位置是10单元,则a6存储位置是(10+5×8=)50单元。
1.3顺序表的顺序存储表示
顺序表(元素)是依次存放、地址连续、随机存取、类型相同的,与数组(元素)一致,所以我们就用一维数组来表示顺序表。
但线性表长可变(因为可删除,插入),而数组长度不可动态定义,所以我们用一变量表示顺序表的长度属性。
例
#define MAXSIZE 100 //多项式可能达到的最大长度
typedef struct{
ElemType *elem; //存储空间的基地址
int length; //当前长度
}SqList; //顺序表的结构类型为SqList
实例① 多项式的顺序存储结构类型定义
P(n)(x)=p1x的e1次方+p2x的e2次方+...+p(m)x的e(m)次方:
线性表P=((p1,e1),(p2,e2),...,(pm,em))
#define MAXSIZE 1000 //多项式可能达到的最大长度
typedef struct{ //多项式非零项的定义
float p; //系数
int e; //指数
}Polynomial;
typedef struct{
Polynomial *elem //存储空间的基地址
int length; //多项式中当前项的个数
}SqList; //多项式的顺序存储结构类型为SqList
实例② 图书表的顺序存储结构类型定义
#define MAXSIZE 10000 //图书表可能达到的最大长度
typedef struct{ //图书信息定义
char no[20]; //图书ISBN
char name[50]; //图书名字
float price; //图书价格
}Book;
typedef struct{
Book *elem; //存储空间的基地址
int length; //图书表中当前图书个数
}SqList; //图书表的顺序存储结构为SqList
1.4顺序表示意图
我们定义了SqList类型,还需要定义变量L,这样才会对变量分配空间。
#define MAXSIZE 100
typedef struct{
ElemType *elem;
int length;
}SqList; //定义顺序表类型
SqList L; //定义变量L,L是SqList这种类型的,L是个顺序表。
数组元素: L.elem[0] L.elem[1] L.elem[2] L.elem[3] L.elem[4] L.elem[5] ...L.elem[99]
数组元素下标: 0 1 2 3 4 5 .... 99
线性表L内容: a b c d e f 6
线性表的成员: L.elem L.length
若L是指针,则SqList *L,线性表L成员为:L-> elem L->length
二、顺序表中基本操作的实现
补充:操作算法中用到的预定义常量和类型
//函数结果状态代码:
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
//Status 是函数的类型,其值是函数结果状态代码
typedef int Status;
typedef char ElemType;
1.1线性表L的初始化
就是将内存空间分配出来并进行赋值
(参数用引用)
Status InitList_Sq(SqList &L){ //构造一个空的顺序表L
L.elem=new ElemType[MAXSIZE]; //为顺序表分配空间
if(!L.elem) exit(OVERFLOW); //存储分配失败
L.length=0; //空表长度为0
return OK;
}
补充几个基本操作
1.1.1销毁线性表L
void DestroyList(SqList &L){
if (L.elem) delete L.elem; //释放存储空间
}
1.1.2清空线性表
void ClearList(SqList &L){
L.length=0; //将线性表的长度置为0
}
1.1.3求线性表L的长度
int GetLength(SqList L){
return(L.length);
}
1.1.4判断线性表L是否为空
int IsEmpty(SqList L){
if(L.length==0) return 1;
else return 0;
}
1.2顺序表的取值
(根据位置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;
}
1.3线性表的查找
(在线性表L中查找与指定值e相同的数据元素的位置)
1.3.1算法描述
int LocateElem(SqList L,ElemType e){
//在线性表L中查找值为e的数据元素,返回其序号(是第几个元素)
for(i=0;i<L.length;i++)(0<=i<=n-1 表示下标)
if (L.elem[i]==e) return i+1; //查找成功,返回序号(序号比下标多1)
return 0; //查找失败,返回0
}
1.3.2算法分析
①基本操作:L.elem[i]==e (将记录的关键词同给定值进行比较)
如线性表 a,b,c,d,e,f,g...
②比较次数:e=a,1次;e=b,2次;e=c,3次;.......,e=g,7次;
所以平均查找长度(ASL)为:(1+2+3+4+5+6+7)/7=4
③ASL=Pi·Ci求和
=P1+2P2+3P3....+(n-1)P(n-1)+nPn
=(1/n)(1+2+...+n)
=(n+1)/2
Pi是第i个记录被查找的概率(1/n),Ci是找到第i个记录需比较的次数
④平均时间复杂度为O(n)
1.4线性表的插入
1.4.1插入不同位置的算法演示
有线性表1,2,3,4,5
·插入位置在最后——直接把元素插在最后一个位置
1 | 2 | 3 | 4 | 5 | 6 |
·插入位置在中间——插入元素的后面元素依次往后移
1 | 2 | 3 | 6 | 4 | 5 |
·插入位置在最前面——插入前的所有元素均依次往后移
6 | 1 | 2 | 3 | 4 | 5 |
1.4.2插入情况
·插入后,线性表长度+1;
·插入位置在0~n范围(下标)
·假设所有元素都占据了空间,那么再插入的话就造成了溢出。
1.4.3算法描述
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--) //j表示下标,i表示第几个元素,即元素序号
L.elem[j+1]=L.elem[j]; //插入位置及之后的元素后移
④L.elem[i-1]=e; //将新元素e放入第i个位置
⑤L.length ++; //表长增1
return OK;
}
1.4.4算法分析
①算法时间主要耗费在移动元素的操作上
·若插入在尾结点之后,则根本无需移动(快)
·若插入在首结点之前,则表中元素全部后移(慢)
·若考虑在各种位置上插入,则共有n+1种可能
②E(ins)=Pi·(n-i+1)求和
=(1/(n+1))·求和(n-i+1)
=(1/(n+1))(n+n-1+n-2+...+1+0)
=n/2
Pi是表示在任何位置上插入元素的概率:1/(n+1); (n-i+1)表示移动的次数
③平均时间复杂度为O(n)
1.5线性表的删除
1.5.1删除不同位置的算法演示
有线性表1,2,3,4,5
·删除位置在最后
1 | 2 | 3 | 4 | 5(删除) |
·删除位置在中间
1 | 2 | 3 | 4(删除) | 5 |
1 | 2 | 3 | 5 |
·删除位置在最前面
1(删除) | 2 | 3 | 4 | 5 |
2 | 3 | 4 | 5 |
1.5.2删除情况
·删除后,线性表长度-1
·删除位置是0~n-1范围(下标)
1.5.3算法描述
Status ListDelete_Sq(SqList &L,int i){
① if((i<1) || i>L.length)) return ERROR; //i值不合法
② for (j=i;j<=L.length-1;j++)
L.elem[j-1]=L.elem[j]; //被删除元素之后的元素前移
③ L.length--; //表长-1
return OK;
}
1.5.4算法分析
①算法时间主要耗费在移动元素的操作上
·若删除尾结点,则无需移动(快)
·若删除首结点,则表中n-1个元素全部前移(慢)
·若考虑在各种位置删除(共n种可能)
②E(del)=Pi·(n-i)求和
(1/n)·(n-i)求和
=(1/n)·(n(n-1)/2)
=(n-1)/2
Pi表示在任何位置上删除的概率都是1/n, (n-i)表示移动的次数
③平均时间复杂度为O(n)