文章目录
线性表的顺序表示
1线性表和顺序表的定义
**(1)线性表:**线性表是具有相同数据类型的 n(n≥0)个数据元素的有限序列。
**(2)顺序表:**用顺序存储的方式实现线性表 顺序存储。把逻辑上相邻的元素存储在物理位置上也相邻的存储单元中,元素之间的关系由存储单元的邻接关系来体现。
2静态分配和动态分配
2.1静态分配
(1)没有反映元素个数n和表的内在联系
#define MAX 100
ElemType elem[MAX]; //表
int n; //数据元素个数n<MAX
(2)用结构体将顺序表的相关信息封装起来
#define MAX 100 //最大元素个数
typedef struct
{
ElemType elem[MAX];
int length; //元素个数,即表长
}Sqlist;
2.2动态存储
#define LIST_INIT_SIZE 100 //存储空间的初始分配量
#define LISTINCREMENT 10 //分配增量
typedef struct
{
ElemType *elem; //存储区域的基址
int length; //当前表的长度
int listsize; //当前已分配的存储容量
)SqList; //顺序表类型
(1)动态申请和释放内存空间
(2)C——malloc、free函数
L.data = (ElemType *) malloc (sizeof(ElemType) * InitSize
malloc 函数的参数,指明要分配多大的连续内存空间;malloc 函数返回一个指针,需要强制转型为自己定义的数据元素类型指针。
(3)C++ —— new、delete 关键字
2.3顺序表基本操作的实现
1.初始化顺序表 InitList_Sq( &L )
操作结果:构造一个空的顺序表 L。
Status InitList_Sq (SqList &L) //构造一个空的顺序表 L
{
L.elem=(ElemType*)malloc(LIST_INIT_SIZE*sizeof(ElemType));
if(!L.elem)
exit(OVERFLOW); //存储空间分配失败
L.length=0;
L.listsize=LIST_INIT_SIZE;
return OK;
} //InitList_sq
算法的时间复杂度:O(1)。
2.销毁顺序表 DestroyList_Sq (&L):
操作结果:释放 L 占用的内存空间。
void DestroyList_Sq(SqList &L)
{
free(L.elem);
L.elem=NULL;
L.length=0;
L.listsize=0;
}
3.判定是否为空表 ListEmpty_Sq( L ):
操作结果:若 L 为空表,则返回 1,否则返回 0。
int ListEmpty_Sq(SqList L)
{
return(L.length == 0);
}
4.输出顺序表 DispList_Sq ( L ):
操作结果:当 L 不为空时,顺序显示 L 中各元素的值。
Status DispList_Sq(SqList L)
{
if(ListEmpty_Sq(L))
return ERROR;
for(i=0; i<L.length; i++)
printf(L.elem[i]);
return OK;
}
5.插入数据元素 ListInsert_Sq (&L, i, e):
操作结果:在顺序表 L 的第 i 个位置(1≤i≤L.length+1)前插入新元素 e。
Status ListInsert_Sq(SqList &L, int i, ElemType e)
{ //在顺序表 L 中第 i 个位置之前插入数据元素 e
if(i<1||i>L.length+1)
return ERROR; //i 值不合法
if(L.Length>=L.listsize){ //上溢时,增加空间
newbase=(ElemType*)realloc(L.elem, (L.listsize+LISTINCREMENT)*sizeof(ElemType));
if(!newbase)
exit(OVERFLOW); //存储分配失败
L.elem=newbase;
L.listsize+=LISTINCREMENT;
} //if
for(j=L.length; j>=i; j--)
L.elem[j]=L.elem[j-1]; //元素后移(从最后一个元素开始)
L.elem[i-1]=e; //在位置 i 处插入元素 e(注意位序与 elem 下标)
++L.length; //顺序表长度增 1
return OK;
}
时间复杂度:
最好情况: 新元素插入到表尾,不需要移动元素 i = n+1,循环 0 次;最好时间复杂度= O(1)
最坏情况: 新元素插入到表头,需要将原有的 n 个元素全都向后移动 i = 1,循环 n 次;最
坏时间复杂度= O(n);
平均情况: 假设新元素插入到任何一个位置的概率相同,则长度为 n 的线性表中插入一个
结点时,所需节点的移动次数为:
∑
i
=
1
n
+
1
p
i
(
n
−
i
+
1
)
=
∑
i
=
1
n
+
1
1
n
+
1
(
n
−
i
+
1
)
=
1
n
+
1
∑
i
=
1
n
+
1
(
n
−
i
+
1
)
=
1
n
+
1
n
(
n
+
1
)
2
=
n
2
\sum_{i=1}^{n+1} p_{i}(n-i+1) = \sum_{i=1}^{n+1}\frac{1}{n+1}(n-i+1) = \frac{1}{n+1}\sum_{i=1}^{n+1}(n-i+1) = \frac{1}{n+1}\frac{n(n+1)}{2} = \frac{n}{2}
i=1∑n+1pi(n−i+1)=i=1∑n+1n+11(n−i+1)=n+11i=1∑n+1(n−i+1)=n+112n(n+1)=2n
平均时间复杂度= O(n)
6.删除数据元素 ListDelete_Sq ( &L, i, &e):
操作结果:删除顺序表 L 中的第 i(1≤i≤L.length)个元素,用引用变量 e 返回删除的元素。
Status ListDelete_Sq(SqList &L, int i, ElemType &e)
{
if(i<1||i>L.length)
return ERROR; //合法位置?
e=L.elem[i-1];
for(j=i; j<L.length; j++)
L.elem[j-1]=L.elem[j]; //元素前移(从第 i+1 个位置开始)
--L.length; //顺序表长度减 1
return OK;
}
时间复杂度:
最好情况: 删除表尾元素,不需要移动其他元素 i = n,循环 0 次;最好时间复杂度=O(1)
最坏情况: 删除表头元素,需要将后续的 n-1 个元素全都向前移动 i = 1,循环 n-1 次;最
坏时间复杂度=O(n);
平均情况: 假设删除任何一个元素的概率相同,则长度为 n 的线性表中插入一个结点时,
所需节点的移动次数为:
∑
i
=
1
n
p
i
(
n
−
i
)
=
∑
i
=
1
n
1
n
(
n
−
i
)
=
1
n
n
(
n
−
1
)
2
=
n
−
1
2
\sum_{i=1}^{n}p_i(n-i)=\sum_{i=1}^{n}\frac{1}{n}(n-i)=\frac{1}{n}\frac{n(n-1)}{2}=\frac{n-1}{2}
i=1∑npi(n−i)=i=1∑nn1(n−i)=n12n(n−1)=2n−1
平均时间复杂度=O(n)
7.按位查找操作 GetElem(L,i):
操作结果:获取表 L 中第 i 个位置的元素的值。
ElemType GetElem(SeqList L, int i)
{
return L.data[i-1];
}
时间复杂度:O(1)
8.按值查找操作 LocateElem(L,e):
操作结果:在表 L 中查找具有给定关键字值的元素(第一个)。
//在顺序表 L 中查找第一个元素值等于 e 的元素,并返回其位序
int LocateElem(SeqList L,ElemType e)
{
for(int i=0;i<L.length;i++)
if(L.data[i]==e)
return i+1; //数组下标为 i 的元素值等于 e,返回其位序 i+1
return 0; //退出循环,说明查找失败
}
时间复杂度:
最好情况: 目标元素在表头,循环 1 次;最好时间复杂度=O(1)
最坏情况: 目标元素在表尾,循环 n 次;最坏时间复杂度=O(n);
平均情况: 假设目标元素出现在任何一个位置的概率相同,则在长度为 n 的线性表中
查找值为 e 元素所需的平均次数为:
∑
i
=
1
n
p
i
×
i
=
∑
i
=
1
n
1
n
×
i
=
1
n
n
(
n
+
1
)
2
=
n
+
1
2
\sum_{i=1}^{n}p_i×i=\sum_{i=1}^{n}\frac{1}{n}×i=\frac{1}{n}\frac{n(n+1)}{2}=\frac{n+1}{2}
i=1∑npi×i=i=1∑nn1×i=n12n(n+1)=2n+1
平均时间复杂度=O(n)