线性表

顺序表简述

线性表的顺序存储结构

顺序映象

  —— 以x的存储位置和y的春初位置之间某种关系表示逻辑关系

最简单的一种顺序映象方式是:

  令 y 的存储位置和 x 的存储位置相邻。用一组==地址连续==的存储单元==依次存放==线性表中的元素。==线性表的起始地址==,称作线性表的基地址。也就是第一个元素。

以“存储位置相邻”表示有序对$$,即:$LOC(a~i~) = LOC(a~i-1~) + C$;

  所有数据元素的存储位置。$LOC(a~i~) = LOC(a~1~) + (i - 1) \times C$,其中LOC(a~1~)就是基地址。

  • 存取结构:与存储结构是两个不同的概念。
  • 存取结构是在一个数据结构上对查找操作的时间性能的一种描述。
  • 通常由两种存取结构;随机存取结构和顺序存取结构。

    • 随机存取结构是指在一个数据结构上进行查找的时间性能是$O(1)$,即查找任意一个数据元素的时间时候相等的,均为常数时间,例如顺序表示一种随机存期结构。
    • 顺序存取结构是指在一个数据结构上进行查找的时间性能是$O(n)$,即查找一个数据元素的时间复杂度是线性的,与该元素在结构中的位置有关,例如单链表是一种顺序存储结构。

顺序映象的C语言描述

#define LISTSIZE 100  //存储空间最大分配量
typedef struct {
    ElemType elem[LISTSZIE];
    int length;  //当前长度
}Sqlist; 
//Sqlist,代表线性表;
  • 在线性表的静态分配顺序存储结构中,线性表的最多数据元素个数为LSITSIZE,元素数量不能随意增加,这是以数组方式描述线性表的缺点。

  为了实现线性表最大存储数据元素数可随意变化,可以使用一个动态的数组来取代上面的固定长度数组,如下描述。

线性表的动态分配顺序储存结构:

#define LIST_INIT_SIZE 100  //初始分配量
#define LISTINCREMENT 10 //分配分配增量

typedef struct {
    ElemType *elem;  //储存空间基址
    int length; //当前长度
    int listsize; //当前分配的存储容量
}SqList;// 俗称 顺序表

线性表操作

1.InitList(&L);

  InitList(&L); 的实现是一个加工型的运算,因此,将L设为引用参数,首先动态分配存储空间,然后,将length设置为0,表示表中没有数据元素。

代码实现:

Status InitList_Sq (SqList &L){
    L.elem = (ElemType* )malloc(LIST_INIT_SIZE * sizeof (ElemType));
    if (!L.elem){
        exit (1);//储存分配失败
    }
    L.length = 0;
    L.listsize = LIST_INIT_SIZE;//初始储存容量;
    return OK;
}

2.LocateElme(L,x,compare());

  • 线性表中的按置操作是指在线性表中查找与给定值X相等的数据元素。
  • 顺序表中完成该运算最简单的方法是:从第一个元素a~1~起依次和X比较,直到找到一个与X相等的数据元素,则返回它在顺序表中的存储下标记或序号(二者差1);或者查遍整个表都没有找到与X相等的元素,返回ERROR。

代码实现:

Status LocateElem_Sq (SqList L, ElemType x){
    int i = 0;
    while (i <= L.length-1 && L.elem[i] != x){
        i++;
    }
    if(i > L.length - 1){
        return ERROR;
    }
    else return i;
}

本算法的主要运算是比较,显然比较的次数与x在表中的位置有关,也与表长有关。当a~1~ = x时,比较一次成功,当a~n~ = x时比较n次成功,按值查找的平均比较次数为 $\frac{(N+1)}{2}$,时间性能为$O(n)$。

3. ListInsert(&L, i, e)

代码实现:

Status ListInsert_Sq (SqList &L, int i, ElemType e){
    //在顺序表L的第i个元素之前插入新的元素e
    //i的合法范围为 1 <=i<=L.length+1
    ElemType *q = &(L.elem[i-1]);//q指示插入位置
    ElemType *p;
    for (p = &(L.elem[L.length-1]); p >= q; --p){
            *(p + 1) = *p;//插入位置及之后的元素右移
            *q = e;//插入e
        ++L.length;//表长增1
    }
}

算法时间复杂度为:$O(ListLength(L))$

if (i < 1 || i > L.length + 1){
    return ERROR;//插入位置不合法
}

if (L.length >= L.listsize){
    return OVERFLOW;//当前存储空间已满
}

考虑移动元素的平均情况:

  假设在第i个元素之前插入的概率为p~i~,则在长度为n的线性表中插入一个元素为所需移动元素次数的期望值为:

所有为位置的概率的累加和。

  若假定在线性表中任何一个位置上进行插入的概率都是相等的,则移动元素的期望值为:

4. ListDelete(&L, i, &e)的实现:

代码实现:

Status LsitDelet_Sq (SqList &L, int i, ElemType &e){
    if((i < 1) || (i > L.length)){
        return ERROR;//删除位置不合法
    }
    p = &(L.elem[i-1]);//p为被删除元素的位置
    e = *p;//被删除元素的值赋给e,可以查看被删元素
    q = L.elem + L.length-1;//表尾元素的位置,基址加上一个整数值
    for (++p; p <= q; ++p){
        *(p-1) = *p;//被删除元素之后的元素左移
        --L.length;//表长减一
    }
    return OK;
}

算法时间复杂度为:$O(ListLength(L))$

考虑移动元素的平均情况:

  假设删除第i个元素的概率为$q_i$,则在长度为$n$的线性表中删除一个元素所需移动元素次数的期望值为:

  假设定在线性表中任何一个位置上进行删除的概率都是相等的,则移动元素的期望值为:


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!