线性表的顺序存储结构

3.1 线性表的顺序存储结构

3.1.1 顺序存储定义

线性表的顺序存储结构指的是,用一段地址连续的存储单元依次存储线性表的数据元素。

3.1.2 顺序存储方式

顺序存储的代码:

#define MAXSIZE 20              /*定义顺序表的最大容量*/
typedef int ElemType;
typedef struct{
    ElemType data[MAXSIZE];     /*存储数据元素*/
    int length;                  /*线性表当前长度*/
}SqlList;

描述顺序结构需要三个属性:

  • 存储空间的起始位置:数组data,它的存储位置就是存储空间的存储位置。
  • 线性表的最大存储容量:数组长度MAXSIZE。
  • 线性表的当前长度:length。

3.1.3 数组长度与线性表长度的区别

数组的长度:存放线性表的存储空间长度,空间分配后一般不可变

线性表长度:线性表中数据元素的个数,随着线性表的插入和删除操作的进行,这个量是变化的。

注意:在任意时刻线性表的长度 <= 数组长度

3.1.4 地址计算方法

有线性表a1,a2,a3,···ai,假设每个元素占用的是c个存储单元,则ai的位置用以下方法计算:

LOC(ai)=LOC(a1)+(i-1)*c

通过这个公式,可以随时算出线性表任意位置的地址,不管他是第一个还是最后一个,都是相同的时间。那么我们对每个线性表位置的存入或者取出数据,对于计算机来说都是相等的时间,也就是一个常数,其存取数据的时间复杂度是O(1),我们通常把具有这一特点的存储结构称为随机存取结构

3.2 顺序存储结构的插入与删除

3.2.1 获得元素操作

实现GetElem操作,即将线性表第i个位置元素返回,只要i的数值在数组下标范围内,把第i-1下标的值返回即可。代码如下:

/*Status是函数的类型,其值是函数返回结果的状态码,如OK*/
typedef int Status;

/*初始条件:顺序线性表L已存在,1<=i<=ListLength(L)*/
/*操作结果:用e返回L中第i个数据元素的值,注意i是指位置,第1个位置的数组是从0开始的*/
Status GetElem(SqlList L,int i,ElemType *e){
    if(L.length==0 || i<1 || i>L.length)
        return ERROR;
    *e=L.data[i-1];

    return OK;
}

把指针*e的值给修改成L.data[i-1],这是真正要返回的数据。

3.2.2 插入操作

我们需要实现ListInsert(L,i,e),即在线性表L的第i个位置插入新元素e。

插入算法的思路:

  1. 如果插入位置不合理,抛出异常。
  2. 如果线性表长度大于等于数组长度,则抛出异常或动态增加容量。
  3. 从最后一个元素开始向前遍历到第i个位置,分别将他们都向后移动一个位置。
  4. 将要插入的元素填入位置i处。
  5. 表长加1。

代码如下:

/*初始条件:顺序线性表L已存在,1<=i<=ListLength(L)*/
/*操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1*/
Status ListInsert(SqlList *L,int i,ElemType e){
    int k;
    if (L->length==MAXSIZE)                 /*线性表已满*/
        return ERROR;
    if (i<1 || i>L->length+1)                 /*i位置判断,比第一位置小,比最后位置大*/
        return ERROR;
    
    if (i<=L->length){                      /*如果插入位置不在表尾*/
        for(k=L->length-1;k>=i-1;k--)       /*将要插入位置后的元素向后移一位*/
            L->data[k+1]=L->data[k]; 
    }
    L->data[i-1]=e;                         /*将新元素插入*/
    L->length++;                            /*线性表长度加1*/

    return OK;
}

3.2.3 删除操作

我们需要实现ListDelete(&L,i,&e),将线性表L第i个位置的数据删除,并将其放入指针e中

删除算法的思路:

  1. 如果删除位置不合理,抛出异常。
  2. 取出删除元素。
  3. 从删除元素位置开始遍历到最后一个元素的位置,分别将他们都向前移动一个位置。
  4. 表长减1。

实现代码:

/*初始条件:顺序表L已存在,1<=i<=ListLength*/
/*操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1*/
Status ListDelete(SqlList *L,int i,ElemType *e){
    int k;
    if (L->length==MAXSIZE)                  /*线性表已满*/
        return ERROR;
    if (i<1 || i>L->length)                  /*删除位置不正确*/
        return ERROR;
    *e=L->data[i-1];
    if (i<L->length){                        /*如果删除不是最后位置*/
        for(k=i;k<L->length;k++)             /*将删除后继元素前移*/
            L->data[k-1]=L->data[k];       
    }
    L->length--;
    return OK;
}

3.2.4 根据值找位置

实现一个LocacteElem(L,e),会返回第一个值等于e的元素的位置。

代码如下:

/* 初始条件:顺序线性表L已存在 */
/* 操作结果:返回L中第1个与e满足关系的数据元素的位序。 */
/* 若这样的数据元素不存在,则返回值为0 */
int LocateElem(SqlList L,ElemType e){
    int i;
    if (L.length==0){
        return 0;
    }
    for (i=0;i<L.length;i++){
        if (L.data[i]==e){
            break;
        }
    }

    if (i>=L.length)
        return 0;
    
    return i+1;   /*返回该值所在位置*/
}

3.2.4 初始化和遍历线性表

代码如下:

/*初始化线性表*/
Status InitList(SqlList *L){
    L->length=0;
    return OK;
}

/*遍历线性表*/
Status visit(ElemType c){
    printf("%d ",c);
    return OK;
}

Status ListTraverse(SqlList L){
    int i;
    for(i=0;i<L.length;i++){
        visit(L.data[i]);
    }
    printf("\n");
    return OK;
}

3.2.5 将两张表连接

代码如下:

/*将所有的在线性表Lb中但不在La中的数据元素插入到La中*/
void unionL(SqlList *La,SqlList Lb){
    int La_len,Lb_len,i;
	ElemType e;                        /*声明与La和Lb相同的数据元素e*/
	La_len=ListLength(*La);            /*求线性表的长度 */
	Lb_len=ListLength(Lb);

    for(i=1;i<=Lb_len;i++){
        GetElem(Lb,i,&e);               /*将Lb中第i个元素存储到e中*/
        if (!LocateElem(*La,e))         /*如果La中不存在与e相同的数据元素*/
            ListInsert(La,++La_len,e);  
    }
}

3.2.5 测试代码

/*测试代码*/
int main(){
        
    SqlList L;
	SqlList Lb;
    
    ElemType e;
    Status i;
    int j,k;
    i=InitList(&L);
    printf("初始化L后:L.length=%d\n",L.length);
    for(j=1;j<=5;j++)
            i=ListInsert(&L,1,j);
    printf("在L的表头依次插入1~5后:L.data=");
    ListTraverse(L); 

    printf("L.length=%d \n",L.length);
    i=isEmpty(L);
    printf("L是否空:i=%d(1:是 0:否)\n",i);

    i=ClearList(&L);
    printf("清空L后:L.length=%d\n",L.length);
    i=isEmpty(L);
    printf("L是否空:i=%d(1:是 0:否)\n",i);

    for(j=1;j<=10;j++)
            ListInsert(&L,j,j);
    printf("在L的表尾依次插入1~10后:L.data=");
    ListTraverse(L); 

    printf("L.length=%d \n",L.length);

    ListInsert(&L,1,0);
    printf("在L的表头插入0后:L.data=");
    ListTraverse(L); 
    printf("L.length=%d \n",L.length);

    GetElem(L,5,&e);
    printf("第5个元素的值为:%d\n",e);
    for(j=3;j<=4;j++)
    {
            k=LocateElem(L,j);
            if(k)
                    printf("第%d个元素的值为%d\n",k,j);
            else
                    printf("没有值为%d的元素\n",j);
    }
    

    k=ListLength(L); /* k为表长 */
    for(j=k+1;j>=k;j--)
    {
            i=ListDelete(&L,j,&e); /* 删除第j个数据 */
            if(i==ERROR)
                    printf("删除第%d个数据失败\n",j);
            else
                    printf("删除第%d个的元素值为:%d\n",j,e);
    }
    printf("依次输出L的元素:");
    ListTraverse(L); 

    j=5;
    ListDelete(&L,j,&e); /* 删除第5个数据 */
    printf("删除第%d个的元素值为:%d\n",j,e);

    printf("依次输出L的元素:");
    ListTraverse(L); 

	//构造一个有10个数的Lb
	i=InitList(&Lb);
    for(j=6;j<=15;j++)
            i=ListInsert(&Lb,1,j);

	unionL(&L,Lb);

	printf("依次输出合并了Lb的L的元素:");
    ListTraverse(L); 

    system("pause");

    return 0;
}

运行结果:

初始化L后:L.length=0
在L的表头依次插入1~5后:L.data=5 4 3 2 1
L.length=5
L是否空:i=0(1:是 0:否)
清空L后:L.length=0
L是否空:i=1(1:是 0:否)
在L的表尾依次插入1~10后:L.data=1 2 3 4 5 6 7 8 9 10
L.length=10
在L的表头插入0后:L.data=0 1 2 3 4 5 6 7 8 9 10
L.length=11
第5个元素的值为:4
第4个元素的值为3
第5个元素的值为4
删除第12个数据失败
删除第11个的元素值为:10
依次输出L的元素:0 1 2 3 4 5 6 7 8 9
删除第5个的元素值为:4
依次输出L的元素:0 1 2 3 5 6 7 8 9
依次输出合并了Lb的L的元素:0 1 2 3 5 6 7 8 9 15 14 13 12 11 10
请按任意键继续. . .

3.2.6 完整代码

如下:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

#define MAXSIZE 20              /*定义顺序表的最大容量*/
typedef int ElemType;
typedef struct{
    ElemType data[MAXSIZE];     /*存储数据元素*/
    int length;                 /*线性表当前长度*/
}SqlList;

/*Status是函数的类型,其值是函数返回结果的状态码,如OK*/
typedef int Status;

/*初始条件:顺序线性表L已存在,1<=i<=ListLength(L)*/
/*操作结果:用e返回L中第i个数据元素的值,注意i是指位置,第1个位置的数组是从0开始的*/
Status GetElem(SqlList L,int i,ElemType *e){
    if(L.length==0 || i<1 || i>L.length)
        return ERROR;
    *e=L.data[i-1];

    return OK;
}

/*初始条件:顺序线性表L已存在,1<=i<=ListLength(L)*/
/*操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1*/
Status ListInsert(SqlList *L,int i,ElemType e){
    int k;
    if (L->length==MAXSIZE)                 /*线性表已满*/
        return ERROR;
    if (i<1 || i>L->length+1)                 /*i位置判断,比第一位置小,比最后位置大*/
        return ERROR;
    
    if (i<=L->length){                      /*如果插入位置不在表尾*/
        for(k=L->length-1;k>=i-1;k--)       /*将要插入位置后的元素向后移一位*/
            L->data[k+1]=L->data[k]; 
    }
    L->data[i-1]=e;                         /*将新元素插入*/
    L->length++;                            /*线性表长度加1*/

    return OK;
}


/*初始条件:顺序表L已存在,1<=i<=ListLength*/
/*操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1*/
Status ListDelete(SqlList *L,int i,ElemType *e){
    int k;
    if (L->length==MAXSIZE)                 /*线性表已满*/
        return ERROR;
    if (i<1 || i>L->length)                 /*删除位置不正确*/
        return ERROR;
    *e=L->data[i-1];
    if (i<L->length){                        /*如果删除不是最后位置*/
        for(k=i;k<L->length;k++)             /*将删除后继元素前移*/
            L->data[k-1]=L->data[k];       
    }
    L->length--;
    return OK;
}



/*初始化线性表*/
Status InitList(SqlList *L){
    L->length=0;
    return OK;
}

/*判断是否为空表*/
Status isEmpty(SqlList L){
    if (L.length==0){
        return TRUE;
    }else{
        return FALSE;
    } 
}

/*返回线性表元素个数*/
int ListLength(SqlList L){
    return L.length;
}



/* 初始条件:顺序线性表L已存在 */
/* 操作结果:返回L中第1个与e满足关系的数据元素的位序。 */
/* 若这样的数据元素不存在,则返回值为0 */
int LocateElem(SqlList L,ElemType e){
    int i;
    if (L.length==0){
        return 0;
    }
    for (i=0;i<L.length;i++){
        if (L.data[i]==e){
            break;
        }
    }

    if (i>=L.length)
        return 0;
    
    return i+1;   /*返回该值所在位置*/
}

/*遍历线性表*/
Status visit(ElemType c){
    printf("%d ",c);
    return OK;
}

Status ListTraverse(SqlList L){
    int i;
    for(i=0;i<L.length;i++){
        visit(L.data[i]);
    }
    printf("\n");
    return OK;
}

/*将所有的在线性表Lb中但不在La中的数据元素插入到La中*/
void unionL(SqlList *La,SqlList Lb){
    int La_len,Lb_len,i;
	ElemType e;                        /*声明与La和Lb相同的数据元素e*/
	La_len=ListLength(*La);            /*求线性表的长度 */
	Lb_len=ListLength(Lb);

    for(i=1;i<=Lb_len;i++){
        GetElem(Lb,i,&e);               /*将Lb中第i个元素存储到e中*/
        if (!LocateElem(*La,e))         /*如果La中不存在与e相同的数据元素*/
            ListInsert(La,++La_len,e);  
    }
}

/*清空线性表*/
Status ClearList(SqlList *L){
    L->length=0;
    return OK;
}

/*测试代码*/
int main(){
        
    SqlList L;
	SqlList Lb;
    
    ElemType e;
    Status i;
    int j,k;
    i=InitList(&L);
    printf("初始化L后:L.length=%d\n",L.length);
    for(j=1;j<=5;j++)
            i=ListInsert(&L,1,j);
    printf("在L的表头依次插入1~5后:L.data=");
    ListTraverse(L); 

    printf("L.length=%d \n",L.length);
    i=isEmpty(L);
    printf("L是否空:i=%d(1:是 0:否)\n",i);

    i=ClearList(&L);
    printf("清空L后:L.length=%d\n",L.length);
    i=isEmpty(L);
    printf("L是否空:i=%d(1:是 0:否)\n",i);

    for(j=1;j<=10;j++)
            ListInsert(&L,j,j);
    printf("在L的表尾依次插入1~10后:L.data=");
    ListTraverse(L); 

    printf("L.length=%d \n",L.length);

    ListInsert(&L,1,0);
    printf("在L的表头插入0后:L.data=");
    ListTraverse(L); 
    printf("L.length=%d \n",L.length);

    GetElem(L,5,&e);
    printf("第5个元素的值为:%d\n",e);
    for(j=3;j<=4;j++)
    {
            k=LocateElem(L,j);
            if(k)
                    printf("第%d个元素的值为%d\n",k,j);
            else
                    printf("没有值为%d的元素\n",j);
    }
    

    k=ListLength(L); /* k为表长 */
    for(j=k+1;j>=k;j--)
    {
            i=ListDelete(&L,j,&e); /* 删除第j个数据 */
            if(i==ERROR)
                    printf("删除第%d个数据失败\n",j);
            else
                    printf("删除第%d个的元素值为:%d\n",j,e);
    }
    printf("依次输出L的元素:");
    ListTraverse(L); 

    j=5;
    ListDelete(&L,j,&e); /* 删除第5个数据 */
    printf("删除第%d个的元素值为:%d\n",j,e);

    printf("依次输出L的元素:");
    ListTraverse(L); 

	//构造一个有10个数的Lb
	i=InitList(&Lb);
    for(j=6;j<=15;j++)
            i=ListInsert(&Lb,1,j);

	unionL(&L,Lb);

	printf("依次输出合并了Lb的L的元素:");
    ListTraverse(L); 

    system("pause");

    return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

压力小子呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值