线性表的顺序表示和实现

线性表的顺序表示指的是用一组地址连续的存储单元一次存储线性表的数据元素。

假设线性表的每个元素需要占用个存储单元,并以所占的第一个但愿的存储地址作为数据元素的存储位置。则线性表中第个数据元素的存储位置和第个数据元素的存储位置之间满足下列关系:

一般来说,线性表的第个数据元素的存储位置为:


线性表的这种机内表示称作线性表的顺序存储结构顺序映像,通常,称这种存储结构的线性表为顺序表。它的特点是:以元素在计算机内“物理位置相邻”来表示线性表中数据元素之间的逻辑关系。所以,只要确定了存储线性表的起始位置,线性表中任一数据元素都可以随机存取,所以线性表的顺序存储结构是一种随机存取的存储结构。

在高级程序设计语言中的数组类型也有随机存取的特性,因此,通常都用数组来描述数据结构中的顺序存储结构。


//线性表以及相关算法的代码实现:
#define LIST_INIT_SIZE 100 ///线性表存储空间的初始分配量
#define LISTINCREMENT 10   ///线性表存储空间的分配增量

typedef int ElemType;
typedef int Status;
const int OK = 1;
const int OVERFLOW = -1;
const int ERROR = 0;

///线性表的动态分配的顺序存储结构
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(-1);
    }
    L.length = 0;
    L.listsize = LIST_INIT_SIZE;
    return OK;
}

///线性表的插入
Status ListInsert_Sq(SqList& L,int i,ElemType e)
{
    ElemType* newBase;
    ElemType* q; ///q为插入位置
    ElemType* p;
    ///在顺序线性表L中第i个位置之前插入新的元素e
    ///i的合法值是1<=i<=L.listLength
    if(i<1||i>L.length+1)   ///如果插入位置不合法
    {
        return ERROR;
    }
    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;
    }
    q = &(L.elem[i-1]);
    for(p = &(L.elem[L.length-1]);p >= q;--p)
    {
        *(p+1) = *q;
    }
    *q = e;
    ++L.length;
    return OK;
}

///线性表元素的删除
Status ListDelete_Sq(SqList &L,int i,ElemType &e)
{
    ElemType* p;
    ElemType* q;
    ///在顺序线性表L中删除第i个元素,并用e返回其值
    if((i<1)||(i>L.length))
    {
        return ERROR;
    }
    p = &(L.elem[i-1]);
    e = *p;
    q = L.elem + L.length - 1;
    for(++p; p<=q; p++)
    {
        *(p-1) = *p;
    }
    --L.length;
    return OK;
}

///显示顺序表的元素
void showList(SqList L)
{
    ElemType* p;
    ElemType* q;
    p = &L.elem[0];
    q = &L.elem[L.length-1];
    for(p;p<=q;p++)
    {
        cout<<*p<<" ";
    }
}

///顺序表的合并
void MergeList_Sq(SqList La,SqList Lb,SqList &Lc)///归并La,Lb得到新的顺序线性表Lc
{
    ElemType* pa;
    ElemType* pb;
    ElemType* pc;
    ElemType* pa_last;
    ElemType* pb_last;

    pa = La.elem;
    pb = Lb.elem;
    Lc.listsize = La.length + Lb.length;
    Lc.length = Lc.listsize;
    pc = Lc.elem = (ElemType *)malloc(Lc.listsize*sizeof(ElemType));
    if(!Lc.elem)
    {
        exit(OVERFLOW);
    }

    pa_last = La.elem + La.length - 1;
    pb_last = Lb.elem + Lb.length - 1;

    while(pa <= pa_last && pb <= pb_last)
    {
        if(*pa <= *pb)
        {
            *(pc++) = *(pa++);
        }
        else
        {
            *(pc++) = *(pb++);
        }
    }

    while(pa <= pa_last)
    {
        *(pc++) = *(pa++);
    }

    while(pb<=pb_last)
    {
        *(pc++) = *(pb++);
    }
}



算法分析:

当在顺序存储结构的线性表中某个位置上掺入或删除一个数据元素的时候,其时间主要消耗在移动元素上。

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

线性表的顺序表示和实现_第1张图片

假设qi是删除第i个元素的概率,则在长度为n的线性表中删除一个元素时所需移动元素次数的期望值(平均次数)为:


我们假定,在线性表的任何位置上插入或者删除元素的概率都是相等的,即:

线性表的顺序表示和实现_第2张图片

所以和可以简化为:

线性表的顺序表示和实现_第3张图片

所以,在顺序存储结构的线性表中插入或删除一个数据元素,平均约移动表中的一般元素,若表长n,则插入和删除元素算法的时间复杂度为O(n)。



你可能感兴趣的:(数据结构)