线性表的顺序映像
含义:用一组地址连续的存储单元依次存放线性表中的数据元素
a 1 a_1 a1 | a 2 a_2 a2 | … \dots … | a i − 1 a_{i-1} ai−1 | a i a_i ai | … \dots … | a n a_n an |
---|
a 1 a_1 a1是线性表的起始地址,称作线性表的基地址
-
以“存储位置相邻”表示有序对< a i − 1 , a i a_{i-1},a_i ai−1,ai>,即: L O C ( a i ) = L O C ( a i − 1 ) + C LOC(a_i)=LOC(a_{i-1})+C LOC(ai)=LOC(ai−1)+C其中C为一个数据元素所占的存储量。
-
所有元素的位置取决于第一个数据元素的存储位置: L O C ( a i ) = L O C ( a 1 ) + ( i − 1 ) × C LOC(a_i)=LOC(a_1)+(i-1)\times C LOC(ai)=LOC(a1)+(i−1)×C其中 L O C ( a i ) LOC(a_i) LOC(ai)为基地址
顺序映像的C语言描述
#define LIST_INIT_SIZE 80 //线性表存储空间的初始分配量
#define LISTINCREMENT 10 //线性表存储空间的分配增量
typedef struct{
ElemType *elem; //存储空间基址
int length; //当前长度
int listsize; //当前分配的存储容量
}Sqlist; //顺序表
线性表的初始化操作
Status InitList_Sq(SqList&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
线性表操作LocateElem(L,e,compare())
的实现:
int LocateElem_Sq(SqList L, ElemType e,
Status(*compare)(ElemType, ElemType)){
// 时间复杂度为O(表长)
i = 1; //i的初值为第1元素的位序
p = L.elem; //p的初值为第一元素额存储位置
while(i<=L.length && !(*compare)(*p++, e)) ++i;
if(i<=L.length) return i;
else return 0;
}//LocateElem_Sq
线性表操作ListInsert(&L,i,e)
的实现:
- 插入元素时,线性表的逻辑关系发生了什么变化?
( a 1 , … , a i − 1 , … , a n ) (a_1,\dots,a_{i-1},\dots,a_n) (a1,…,ai−1,…,an)改变为 ( a 1 , … , a i − 1 , e , a i … , a n ) (a_1,\dots,a_{i-1},e,a_i\dots,a_n) (a1,…,ai−1,e,ai…,an)
e前面的元素不变,后面的元素后移,表的长度增加1
Status ListInsert_Sq(SqList &L, int pos,ElemType e){
//时间复杂度为O(ListLength(L))(最坏情况)
if(pos<1 || pos>L.length+1) return ERROR; //输入位置不合法
if(L.length>=L.listsize){ //当前存储空间已满,增加分配
newbase = (ElemType *)realloc(L.elem,(L.liatsize+LISTINCRMENT)*sizeof(ElemType);
if(!newbase) exit(OVERFLOW); //存储分配失败
L.elem = newbase; //新基址
L.listsize = LISTINCREMENT; //增加存储容量
}
q = &(L.elem[pos-1]); //q指示插入位置
for(p=&(L.elem[L.length-1]);p>=q; --p)
*(p+1)=*p; //插入位置及之后的元素右移
*q = e; //插入e
++L.length; //表长增1
return OK;
}//ListInsert_Sq
- 最坏情况下时间复杂度为O(ListLength(L))
- 考虑平均的情况:
假设在第i个元素之前插入的概率为 p i p_i pi,则在第i个元素之前插入需移动的次数为n-i+1,则在长度为n的线性表中插入一个元素所需移动元素次数的期望值为: E = ∑ i = 1 n + 1 p i ( n − i + 1 ) E=\sum_{i=1}^{n+1}p_i(n-i+1) E=i=1∑n+1pi(n−i+1)
若假定在线性表中任何一个位置上进行插入的概率都是相等的,则移动元素的期望值为 E = 1 n + 1 ∑ i = 1 n + 1 ( n − i + 1 ) = n 2 E=\frac{1}{n+1}\sum_{i=1}^{n+1}(n-i+1)=\frac{n}{2} E=n+11i=1∑n+1(n−i+1)=2n
线性表操作Listelete(&L,i,&e)
的实现:
- 删除元素时,线性表的逻辑结构发生了什么变化?
( a 1 , … , a i − 1 , a i , a i + 1 , … , a n ) (a_1,\dots,a_{i-1},a_i,a_{i+1},\dots,a_n) (a1,…,ai−1,ai,ai+1,…,an)改变为 ( a 1 , … , a i − 1 , a i + 1 , … , a n ) (a_1,\dots,a_{i-1},a_{i+1},\dots,a_n) (a1,…,ai−1,ai+1,…,an)
被删除元素之前的数据元素不变,后面的元素前移
Status ListDelete_Sq(SqList &L, int pos, ElemType &e){
if((pos<1)||(pos>L.length)) return ERROR; //删除位置不合法
p = &(L.elem[pos-1]) //p设为被删除元素的位置
e = *p; //被删除元素的值赋给e
q = L.elem+L.length-1 //表尾元素的位置
for(++p; p<=q; ++p) *(p-1) = *p; //被删除元素之后的元素左移
--L.length; //表长减1
return OK;
}//ListDelete_Sq
- 算法的时间复杂度为O(ListLength(L))
- 考虑平均的情况:
假设删除第i个元素的概率为 q i q_i qi,则在长度为n的线性表中删除一个元素所需移动元素次数的期望值为: E d l = ∑ i = 1 n q i ( n − i ) E_{dl}=\sum_{i=1}^nq_i(n-i) Edl=i=1∑nqi(n−i)
若假定在线性表中任何一个位置上进行删除的概率是相等的,则移动元素的期望值为: E d l = 1 n ∑ i = 1 n ( n − i ) = n − 1 2 E_{dl}=\frac{1}{n}\sum_{i=1}^n(n-i)=\frac{n-1}{2} Edl=n1i=1∑n(n−i)=2n−1
顺序表的优缺点
- 优点:可以对每个数据元素进行随机存取,表长是显值
- 缺点:在进行元素插入或删除时要进行数据元素的移动,每次大致要移动表的一般的元素