数据结构与算法学习笔记-线性表(2)

2.2线性表的实现

2.2.1线性表的顺序存储

顺序存储:把线性表的结点按逻辑顺序依次存放在一组地址连续的存储单元里。

用这种方法存储的线性表简称顺序表

顺序存储的线性表的特点:

  • 线性表的逻辑顺序与物理顺序一致;
  • 数据元素之间的关系是以元素在计算机内“物理位置相邻”来体现。

设每个元素需占用/个存储单元,以所占的第一个单元的存储地址作为数据元素的存储位置。则线性表中第i+1个数据元素的存储位置LOC(ai+1)和第i个数据元素的存储位置LOC(ai)之间满足下列关系:

​ LOC(ai+1) = LOC(ai)+ /

线性表的第i个数据元素ai的存储位置为:

​ LOC(ai) = LOC(a1)+(i-1)* /

存取结构:存取结构是在一个数据结构上对查找操作的时间性能的一种描述

  • 随机存取结构:指在一个数据结构上进行查找的时间性能是O(1),即查找任意一个数据元素的时间是相等的,均为常数时间;

    (顺序表是一种随机存储结构)

  • 顺序存取结构:指在一个数据结构上进行查找的时间性能是O(n),即查找一个数据元素的时间复杂度是线性的,与该元素在结构中的位置有关。

    (单链表是一种顺序存取结构)

    数组具有随机存取的特性,顺序表还应该有表示线性表的长度属性,所以用结构类型来定义顺序表类型。

    (1)静态结构:表一旦装满,不能扩充

#define MAX_SIZE 100
typedef int Status;
typedef int ElemType;
typedef struct sqlist{
    ElemType Elem_array[MAX_SIZE];
    int length;
}sqList;

​ (2)动态结构:可以扩充,新的大小计入数据成员maxSize中

typedef struct sqlist{
	ElemType *elem;//存储数组
    int length;//当前表元素个数
    int maxSize;//表的最大长度
}sqList;

顺序线性表的插入

​ 在线性表L = (a1,…ai-1,e,ai,ai+1,…,an)

实现步骤:

(1)将线性表L中的第i个至第n个结点后移一个位置;

(2)将结点e插入到结点ai-1之后;

(3)线性表长度加1。

如下图所示:
数据结构与算法学习笔记-线性表(2)_第1张图片

Status Insert_SqList(Sqlist *L,int i,ElemType e){
    int j;
    if (i<0||i>L->length-1)  return ERROR;
    if (L->length>=MAX_SIZE){
        printf("溢出!\n");return ERROR;
    }
    for (j=L->length-1;j>=i-1;--j)
        L->Elem_array[j+1] = L->Elem_array[j];
    /*  i-1位置以后的所有结点后移  */
    L->Elem_array[i-1] = e;/*  在i-1个位置插入  */
    L->length++;
    return OK;
}

时间复杂度分析

线性表L中的第i个元素之前插入新结点,结点的移动次数来估计算法的时间复杂度。

设在线性表L中的第i个元素之前插入结点的概率为Pi,不失一般性,设各个位置插入是等概率,则Pi = 1/(n+1),而插入时移动结点的次数为n-i+1。

总的平均移动次数:E(Insert) = ε pi *(n-i+1)(1<=i<=n)

​ 所以:E(Insert) = n / 2 。

即在顺序表上做插入运算,平均要移动表上的一半结点。当表长n较大时,算法的效率相当低。

因此算法的平均时间复杂度为O(n)。

顺序线性表的删除

在线性表L = (a1,…,ai-1,ai,ai+1,…,an)中删除结点ai(1<=i<=n),使其称为线性表:

​ L = (a1,…,ai-1,ai+1,…,an)

实现步骤:

(1)将线性表L中的第i + 1个至第n个结点依次向前移动一个位置。

(2)线性表长度减1。

如下图所示:
数据结构与算法学习笔记-线性表(2)_第2张图片

ElemType Delete_sqList(Sqlist *L,int i){
    int k;ElemType x;
    if (L->length==0){
        printf("线性表L为空!\n");
        return ERROR;
    }
    else if(i<1||i>L->length){
        printf("要删除的数据元素不存在!\n")return ERROR;
    }
    else {
        x=L->Elem_array[i-1];
        /*保存结点的值*/
        for (k=i;k<L->length;k++)
            L->Elem_array[k-1]=L->Elem_array[k];
        /*i位置以后的所有结点前移*/
        L->length--;
        return (x)
    }
}

时间复杂度分析

设在线性表L中删除第i个元素的概率为Pi,不失一般性,设删除各个位置是等概率,则Pi=1/n,而删除时移动结点的次数为n-i。

总的平均移动次数:E(delete)= ε pi * (n-i) (1<=i<=n)

​ 所以:E(delete)= (n-1)/ 2。

即在顺序表上做删除运算,平均要移动表上一半 结点。当表长n较大时,算法的效率相当低。

因此算法的平均时间复杂度为O(n)。

顺序线性表的查找定位删除

在线性表 L = (a1,a2,… ,an)中删除值为x的第一个结点。

实现步骤:

(1)在线性表L查找值为x的第一个数据元素。

(2)将从找到的位置至最后一个结点依次向前移动一个位置。

(3)线性表长度减1。

Status Locate_Delete_sqList(Sqlist *L,ElemType x)
    /*删除线性表中值为x的第一个结点*/
{
   int i=0,k;
    while (i<L->length) /*查找值为x的第一个结点*/
    {
        if (L-> Elem_array[i]!=x)i++;
        else{
            for (k=i+1;k<L->length;k++)
                L->Elem_array[k-1]=L->Elem_array[k];
            L->length--;break; }
        if (i>L->length){
            printf("要删除的数据元素不存在!\n");
            return ERROR;}
        return OK;
    } 
}

时间复杂度分析-数据元素的比较和移动操作

首先,在线性表L中查找值为x的结点是否存在;

其次,若值为x的结点存在,且在线性表L中的位置为i,则在线性表L中删除第i个元素。

设在线性表L删除数据元素概率为Pi,不失一般性,设各个位置是等概率,则Pi = 1/n。

​ 比较的平均次数:E(compare) = ε Pi * i (1<=i<=n)

​ 所以:E(compare) = (n + 1)/ 2。

​ 删除时平均移动次数:E(delete)= ε Pi * (n - 1) (1<=i<=n)

​ 所以:E(delete)= (n-1) / 2。

平均时间复杂度:E(compare)+ E(delete) = n,即为O(n)。

例1:线性表的合并问题

已知顺序表LA和LB中的数据元素按值非递减有序排列,现要将LA和LB归并为一个新表LC,且LC中的数据元素仍按值非递减有序排列。

LA = (3,5,8,9) LB = (2,6,9,11,15,20)

LC = (2,3,5,6,8,9,9,11,15,20)

/*部分核心代码*/
void MergeList(SqList La,SqList Lb,SqList *Lc){
    1. pa = La.elem;pb = La.elem;
    2. Lc->listsize = Lc.length = La.length+Lb.length;
    3. Pc = Lc->elem = (ElemType*)malloc(Lc.listsize*sizeof(ElemType));
    4. if(!Lc.elem)  exit(overfiow);
    5. pa_last = La.elem + La.length-1;
    6. pb_last = Lb.elem + Lb.length-1;
    7. while(pa<=pa_last&&pb<=pb_last){
    8.    if (*pa<=*pb)
    9.        *pc++=*pa++;
    10.    else
    11.        *pc++=*pb++;}
    12. while(pa<=pa_last) *pc++=*pa++;
    13. while(pb<=pb_last) *pc++=*pb++;  }

你可能感兴趣的:(学习笔记)