目录
一、线性表的逻辑结构定义
线性表是一种最基本而且应用广泛的数据结构,其特点是结构中的各数据元素之间存在着一对一的关系,是一种最典型的线性结构。
1.线性表的定义
线性表(Linear List):是具有相同特性的数据元素的一个有限序列。
在任意一个非空线性表中,设第i个(i表示位序)元素为ai(1≤i≤n),则线性表一般可表示为:
L=(a1, a2, …, an)
★长度:线性表中所包含的数据元素的个数,用n表示(n≥0)。当 n=0 时,表示线性表是一个空表。
2.线性表的特点
(1)线性表中数据元素的相对位置是确定的。若改变了线性表中某个数据元素的位置,那么变动后和变动前的线性表就是两个不同的线性表。(2)线性表中的数据元素必须具有相同特性,即属于同一个数据对象。
二、线性表的基本操作
功能 | 操作函数 | 初始条件 | 操作结果 |
建立 | InitList(&L) | 线性表L不存在 | 构造一个空的线性表 |
销毁 | destroyList(&L) | 线性表L已存在 | 销毁线性表L |
清空 | clearList(&L) | 线性表L已存在 | 将线性表L置为空表 |
判空 | listIsEmpty(L) | 线性表L已存在 | 若L为空表,返回真,否则返回假 |
求长度 | listLength(L) | 线性表L已存在 | 返回线性表中所包含的数据元素的个数 |
取值 | getElem( L, i, &e ) | 线性表L存在 且1≤i≤listLength(L) | 用e返回线性表L中的第i个元素的值 |
按值查找 | locateElem( L, e ) | 线性表L存在 e是给定数据元素 | 返回L中第一个与e相等的数据元素的位序;若不存在,则返回0 |
插入 | listInsert( &L, i, e ) | 线性表L存在1≤i≤listLength(L)+1 | 在线性表L的第i个位置上插入一个值为e 的新元素,线性表的长度增1 |
删除 | listDelete( &L, i, &e ) | 线性表L已存在,1≤i≤listLength(L) | 删除线性表L的第i个数据元素,并用e返回其值,使线性表的长度减1 |
求前驱 | priorElem( L, cur_e, &pre_e ) | 线性表L已存在。 | cur_e是表L的一个元素,且不是 第一个,用pre_e返回它的直接前驱元素;否则,操作失败 |
求后继 | nextElem( L, cur_e, &next_e ) | 线性表L已存在 | cur_e是线性表L的一个数据元素,且不是最后一个,用 next_e返回它的直接后继元素;否则,操作失败 |
遍历 | listTraverse ( L, visit( ) ) | 线性表L已存在,visit( )是元素的访问函数。 | 依次对L中的每一个数据元素调用visit( )函数,一旦visit( )失败,则操作失败 |
三、顺序表
1.顺序表的存储结构
存储特性:逻辑相邻,存储相邻
存取特点:随机存取
2.顺序表的类型定义
#define ListSpaceIncr 20
struct {
LElemType *base;
int length;
int listSize;
} SqList ;
3.顺序表的基本操作
1).初始化-->InitSqList(&L, InitSize)
Status InitSqList(SqList &L, int InitSize)
{ L.base = (LElemType*)malloc(InitSize*sizeof(LElemType) );
if (!L.base) return OVERFLOW;
L.length = 0;
L.listSize = InitSize;
return OK;
}
2).求长度-->listLength (L)
int listLength (SqList L) {
return L.length;
}
3).判空-->listIsEmpty(L)
Status lengthIsEmpty(SqList L) {
if(!L.length) return TRUE;
else return FALSE;
}
4).清空-->clearList(&L)
void clearList(SqList &L){
L.length = 0 ;
}
5).取元素-->getElem(L, i, &e)
Status getElem(SqList L, int i, LElemType &e)
{ if( i<1||i>L.length) return ERROR;
e=L.base[i-1];
return OK;
}
6).按值查找-->locateElem(L, e)
int locateElem(SqList L, LElemType e){
int i;
for( i=0; i<L.length; i++)
if( equal( L.base[i] , e ) ) return i+1;
return 0;
}
7).插入-->listInsert(&L, i, e)
Status listInsert(SqList &L, int i, LElemType e){
int j;
if( i<1 || i>L.length+1 ) return ERROR;
if( L.length == L.listSize ){
L.base = (LElemType*)realloc( L.base,
(L.listSize+ListSpaceIncr)*sizeof(LElemType) );
if( !L.base ) return OVERFLOW;
L.listSize+=ListSpaceIncr;
}
for( j=L.length-1; j>=i-1; j-- ) L.base[j+1] = L.base[j];
L.base[i-1]=e;
L.length++;
return OK;
}
8).删除-->listDelete(&L, i, &e)
Status listDelete(SqList &L,int i, LElemType &e)
{ int j;
if( i<1 || i>L.length ) return ERROR;
e = L.base[i-1];
for( j=i; j<L.length; j++)
L.base[ j-1] = L.base[ j ];
L.length--;
return OK;
}
4.顺序表基本操作时效率分析
(1)判空、清空、求长度、取元素等操作算法的时间复杂度 —— O( 1 )
(2)查找-->算法的运行时间主要取决于元素的比较次数。
- 最好情况——查找第1个元素-->元素比较次数:1
- 最坏情况——查找最后一个元素-->元素比较次数:n
-
平均情况:查找第 i 元素:比较次数 Ci = i-->时间复杂度为 O(n)
-
平均移动次数
(3)插入-->算法的运行时间主要取决于元素的移动次数。
- 最好情况—— 尾端插入 i=n+1-->元素移动次数:0
- 最坏情况—— 头端插入 i=1-->元素移动次数:n
- 平均情况:位置 i 插入:移动次数 Ci = n-i+1-->时间复杂度为 O(n)
- 平均移动次数:
(4)删除-->算法的运行时间主要取决于元素的移动次数。
- 最好情况—— 尾端插入 i=n-->元素移动次数:0
- 最坏情况—— 头端插入 i=1-->元素移动次数:n-1
- 平均情况:位置 i 插入:移动次数 Ci = n-i-->时间复杂度为 O(n)
- 平均移动次数:
5.优缺点分析
优点:(1)实现方法简单。(2)元素访问速度快:随机存取;
缺点:(1)插入、删除时涉及大量的元素移动。(2)存储空间要求高。适用场合;
适用场合:(1)问题规模基本确定;(2)插入与删除少或在(接近)表尾端进行。