顺序表
1:线性表的顺序表示又称为顺序存储结构或顺序映像
2:顺序存储定义:把逻辑上相邻的数据元素存储在物理上相邻的存储单元中的存储结构
3:只要确定了存储线性表的起始位置,线性表中任一数据元素都可随机存取,所以线性表的顺序存储结构是一种随机存取的存储结构(优点)。
4:可以用一维数组表示顺序表,但线性表长可变,而数组长度不可动态定义,所以增加一个变量表示顺序表的长度属性。
总结
1:线性表包含两项,一项是数组/动态数组(指针),一项是当前长度
2:数组可以静态分配或者动态分配
3:SqList L,L.data[i] // 普通对象用.
获取长度,判断是否为空,查询等不需要修改顺序表的,形参传入SqList
SqList L, L->data[i] // 指针对象用->
初始化,插入,删除,销毁,清空等需要修改顺序表的,形参传入SqList
4:重点
1)2.1顺序表的初始化
2)2.2顺序表的取值
3)2.3顺序表的查找
4)2.4顺序表的插入
5)2.5顺序表的删除
5:注意:逻辑位序和物理位序相差1,例如逻辑上第一个元素存储在下标为0的位置上
2.1 取值传入的参数是序号(返回元素是:数组[序号-1])
2.2 查找返回的是序号(返回序号是:数组下标+1)
#include <stdio.h>
#include <stdlib.h>
// 函数结果状态代码
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int ElemType; /* ElemType类型根据实际情况而定,这里假设为int */
#define MAXSIZE 100 // 线性表存储空间的初始分配量
typedef struct{
ElemType data[MAXSIZE]; // 数组静态分配
// ElemType *elem; 数组动态分配,存储空间的基地址
int length; // 当前长度
}SqList; // 顺序表的结构类型为SqList
/* 2.1初始化顺序线性表 */
Status InitList(SqList *L)
{
// L->elem = (ElemType*)malloc(sizeof(ElemType)*MAXSIZE); 如果用动态数组实现,初始化时需要分配一个大小为MAXSIZE的数组空间
L->length = 0;
return OK;
}
/* 2.2 顺序表的取值
初始条件:顺序线性表L已存在,1≤i≤ListLength(L)
操作结果:用e返回L中第i个数据元素的值
算法分析:顺序表取值的时间复杂度为O(1) 随机存取
注意:i是序号,第i个序号对应数组i-1的值 */
Status GetElem(SqList L, int i, ElemType *e)
{
if (i<1 || i>L.length) // 判断i值是否合理,若不合理,返回ERROR
return ERROR;
*e = L.data[i - 1]; // elem[i-1]单元存储第i个数据元素
return OK;
}
/* 2.3 顺序表的查找
初始条件:顺序线性表L已存在
操作结果:返回L中第1个与e满足关系的数据元素的位序。
若这样的数据元素不存在,则返回值为0
算法分析:
查找第0个元素:比较次数1
查找第1个元素:比较次数2
查找第i个元素:比较次数i+1
查找第n-1个元素:比较次数n
平均查找长度
1)平均值:ASL = (1+2+...+n)/n = (n+1)/2
2)期望值:ASL = ∑(pi*Ci),pi是查找第i个元素的概率1/n,Ci是查找到第i个元素的比较次数
1/n*(1+2+3+...+n) = (n+1)/2,每个元素的比较次数 * 每个元素出现概率(都是1/n)
顺序表按值查找算法的平均时间复杂度为O(n)
*/
int LocateElem(SqList L, ElemType e)
{
// 在顺序表L中查找值为e的数据元素,返回其序号(是第几个元素)
for (int i = 0; i<L.length; i++)
{
if (L.data[i] == e){ return i + 1;} // 查找成功,返回序号 i+1
}
return 0; // 查找失败, 返回0
}
/*
2.4 顺序表的插入
初始条件:顺序线性表L已存在,1≤i≤ListLength(L),
操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1
插入位置:最后、中间、最前面
插入下标:0--n
插入位置:1--n+1
算法分析:
插入第0个下标:移动次数n
插入第1个下标:移动次数n-1
插入第i个下标:移动次数n-i
插入第n个下标:移动次数0
移动次数和插入下标的和:n
1)平均值:E = (0+1+2+...+n)/n+1 = n/2
2)期望值:E = ∑(pi*(n-i+1)),pi是1/(n+1),这里的i是序号
顺序表插入算法的平均时间复杂度为O(n)
*/
Status ListInsert(SqList *L, int i, ElemType e)
{
if (i<1 || i>L->length + 1) return ERROR; // i值不合法
if (L->length == MAXSIZE) return ERROR; // 当前存储空间已满
for (int j = L->length - 1; j >= i - 1; j--){ // 直到i-1位置的值后移,将元素插入在i-1的位置上
L->data[j + 1] = L->data[j]; // 插入位置及之后的元素后移
}
L->data[i - 1] = e; // 将新元素e放入第i个位置
L->length++; // 表长加1
return OK;
}
/*
2.5 顺序表的删除
初始条件:顺序线性表L已存在,1≤i≤ListLength(L)
操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1
删除位置:最后、中间、最前面
删除下标:0--n
删除位置:1--n + 1
算法分析:
插入第0个下标:移动次数n-1
插入第1个下标:移动次数n-2
插入第i个下标:移动次数n-i-1
删除第n-1个下标:移动次数0
1)平均值:E = (0+1+2+...+n-1)/n = (n-1)/2
2)期望值:E = ∑(pi*(n-i)),pi是1/n,这里的i是序号
顺序表删除算法的平均时间复杂度为O(n)
*/
Status ListDelete(SqList *L, int i, ElemType *e)
{
if (i<1 || i>L->length){
return ERROR; // i值不合法
}
*e = L->data[i - 1];
for (int j = i; j <= L->length-1; j++){
L->data[j - 1] = L->data[j]; // 被删除元素之后的元素前移
}
L->length--; // 表长减1
return OK;
}
//
/* 销毁线性表 */
Status DestroyList(SqList *L)
{
// if (L->data!=NULL){ free(L->data); } 如果用动态数组实现,释放存储空间
L->length = 0;
return OK;
}
/* 初始条件:顺序线性表L已存在。操作结果:将L重置为空表 */
Status ClearList(SqList *L)
{
L->length = 0;
return OK;
}
/* 初始条件:顺序线性表L已存在。操作结果:返回L中数据元素个数 */
int ListLength(SqList L)
{
return L.length;
}
/* 初始条件:顺序线性表L已存在。操作结果:若L为空表,则返回TRUE,否则返回FALSE */
Status ListEmpty(SqList L)
{
if (L.length == 0){
return TRUE;
}
else{
return FALSE;
}
}
/* 打印单个元素 */
Status visit(ElemType c)
{
printf("%d ", c);
return OK;
}
/*
初始条件:顺序线性表L已存在
操作结果:依次对L的每个数据元素输出 */
Status ListTraverse(SqList L)
{
int i;
for (i = 0; i < L.length; i++){
visit(L.data[i]);
}
printf("\n");
return OK;
}
void main(){
SqList L;
ElemType e;
// 初始化测试
Status status = InitList(&L);
if (status==OK){
printf("初始化L.length=%d\n\n",L.length);
} else{
printf("顺序表初始化失败!\n");
}
// 元素插入测试(头插法)
for (int i = 1; i <= 5; i++){
status = ListInsert(&L, 1, i);
}
printf("元素插入后顺序表的值:");
ListTraverse(L);
printf("元素插入后顺序表长度:L.length=%d \n\n", L.length);
// 取值 + 根据元素查找序号
GetElem(L, 5, &e);
printf("第%d个元素的值为:%d\n\n", LocateElem(L, e),e);
// 删除第4个数据
ListDelete(&L, 4, &e);
printf("删除第4个的元素值为:%d\n", e);
printf("元素删除后顺序表的值:");
ListTraverse(L);
printf("元素删除后顺序表长度:L.length=%d \n\n", L.length);
system("pause");
}