1.线性表的类型定义
线性表是n个数据元素的有限序列
在稍微复杂的线性表中,一个数据元素可以由若干个数据项组成,在这种情况下,常把数据元素称为记录,含有大量记录的线性表又称文件。
若将线性表记为: (a1 ,…,ai-1 ,ai ,ai+1 …an ) 其中ai-1 是ai 的直接前驱元素,ai+1 是ai 的直接后继元素
2.线性表的顺序表示和实现
线性表的顺序表示指的是用一组地址连续的存储单元依次存储线性表的数据元素
只要确定了存储线性表的起始位置,线性表中任一数据元素都可以随机存起,所以线性表的顺序存储结构是一种随机存取的存储结构
顺序线性表的定义
#define LIST_INIT_SIZE 100
#define LIST_INCREMENT 10
typedef int ElemType;
typedef struct
{
ElemType* elem;
int length;
int listsize;
} SqList;
bool InitList_Sq ( SqList& L)
{
L. elem = ( ElemType* ) malloc ( LIST_INIT_SIZE * sizeof ( ElemType) ) ;
if ( ! L. elem) return false;
L. length = 0 ;
L. listsize = LIST_INIT_SIZE;
return true;
}
顺序线性表的插入 假设有n个元素,插入位置0移动n次,位置1移动n-1次,位置n移动0次。 所以平均插入次数为(0+1+2+3…n)= n(n+1)/2 设插入概率相同,为1/(n+1) 得到时间复杂度为: O(n/2) = O(n)
bool ListInsert_Sq ( SqList& L, int n, const ElemType& e)
{
if ( n< 0 || n> L. length) return false;
if ( L. length >= L. listsize) {
ElemType* newbase = ( ElemType* ) realloc ( L. elem, ( L. listsize + LIST_INCREMENT) * sizeof ( ElemType) ) ;
if ( ! newbase) return false;
L. elem = newbase;
L. listsize + = LIST_INCREMENT;
}
for ( int i = L. length - 1 ; i >= n; i-- )
{
L. elem[ i+ 1 ] = L. elem[ i] ;
}
L. elem[ n] = e;
++ L. length;
}
顺序线性表的删除 假设有n个元素,删除位置0移动n-1次,位置1移动n-2次,位置n-1移动0次。 所以平均插入次数为(0+1+2+3…n-1)= n(n-1)/2 设插入概率相同,为1/n 得到时间复杂度为: O((n-1)/2) = O(n)
bool ListDelete_Sq ( SqList& L, int n, ElemType& e)
{
if ( n< 0 || n> L. length) return false;
e = L. elem[ n] ;
for ( int i = L. length - 1 ; i > n; -- i)
{
L. elem[ i- 1 ] = L. elem[ i] ;
}
L. length-- ;
return false;
}
将两个有序线性表合成一个新的有序线性表,并且该线性表依然有序 该算法虽然有三个算法,但是下面两个循环只是处理第一个循环没有处理完成的情况,两者只会执行一个,所以实际是两个循环,时间复杂度为: O(Length(A)+Length(B))
void MergeList ( const SqList& la, const SqList& lb, SqList& lc)
{
InitList_Sq ( lc) ;
int i= 0 , j= 0 , k= 0 ;
while ( i <= la. length - 1 && j <= lb. length - 1 )
{
if ( la. elem[ i] < lb. elem[ j] )
{
ListInsert_Sq ( lc, ++ k, la. elem[ i] ) ;
i++ ;
}
else
{
ListInsert_Sq ( lc, ++ k, lb. elem[ j] ) ;
j++ ;
}
}
while ( i <= la. length - 1 )
{
ListInsert_Sq ( lc, ++ k, la. elem[ i] ) ;
i++ ;
}
while ( j <= lb. length - 1 )
{
ListInsert_Sq ( lc, ++ k, lb. elem[ j] ) ;
j++ ;
}
}
bool Compare ( ElemType a, ElemType b)
{
return a == b;
}
int LocateElem_Sq ( const SqList& L, const ElemType e, bool ( * compare) ( ElemType, ElemType) )
{
for ( int i = 0 ; i < L. length; ++ i)
{
if ( ( * compare) ( L. elem[ i] , e) )
return i;
}
return - 1 ;
}
求AUB存入B 该算法在对b表的遍历中嵌套了对a表的遍历,所以时间复杂度为: O(Length(a)*Length(b))
void Union ( SqList& La, const SqList& Lb)
{
int k = La. length - 1 ;
for ( int i = 0 ; i < Lb. length; i++ )
{
if ( LocateElem_Sq ( La, Lb. elem[ i] , Compare) == - 1 )
{
ListInsert_Sq ( La, ++ k, Lb. elem[ i] ) ;
}
}
}
3.优缺点
优点:逻辑关系上相邻的两个元素的物理位置也相邻,因此不仅节省内存而且可以随机存取表中任一元素。
缺点:对于插入和删除操作时间复杂度较大。