文章目录
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。
插入算法的思路:
- 如果插入位置不合理,抛出异常。
- 如果线性表长度大于等于数组长度,则抛出异常或动态增加容量。
- 从最后一个元素开始向前遍历到第i个位置,分别将他们都向后移动一个位置。
- 将要插入的元素填入位置i处。
- 表长加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。
实现代码:
/*初始条件:顺序表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;
}