线性表的顺序存储--
线性表是最基本、最简单、也是最常用的一种数据结构。线性表(linear list)是数据结构的一种,一个线性表是n个具有相同特性的数据元素的有限序列。
线性表示什么?借助网上大佬的一个例子
小学生放学都是要按顺序排队的,一个接一个,每个小学生的前后位置是固定的,这样便于迅速清点。
其实这就是一个线性表,从这件事里我们就可以找到很多关于线性表的特性,如
1、线性表是一个序列,它是有顺序的(排队)
2、第一个元素无前驱,最后一个无后继,其他每个元素都有一个前驱和后继(一个接一个)
3、元素是有限的(小学生的个数是有限的)
4、数据类型都相同(都是小学生在排队)
那么我们如何定义一个节点呢?
/*定义线性表类型*/
typedef struct{
ElemType data[MAXSIZE];
int length;
}sqList;
结构较简单,一个数组用于存放元素信息 和一个长度用于下面操作
代码实现的功能包括线性表的初始化,判断是否为空、清空、增加元素、删除元素、合并线性表等操作。
#include <stdio.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 20 /*初始化存储空间*/
/*取别名,便以操作*/
typedef int Status;
typedef int ElemType;
/*定义线性表类型*/
typedef struct{
ElemType data[MAXSIZE];
int length;
}sqList;
/*初始化顺序线性表*/
Status InitList(sqList *L){
L->length=0;
return OK;
}
/*初始条件:顺序表已存在,操作结果:若L为空,则返回TRUE,否则返回FALSE*/
Status ListEmpty(sqList* L){
if(L->length==0)
return TRUE;
else
return FALSE;
}
/* 初始条件:顺序线性表L已存在。操作结果:将L重置为空表 */
Status ClearList(sqList* L){
L->length=0;
return OK;
}
/*初始条件:顺序线性表L已存在。操作结果:获取线性表的长度*/
Status ListLength(sqList* L){
return L->length;
}
/* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L) */
/* 操作结果:用e返回L中第i个数据元素的值,注意i是指位置,第1个位置的数组是从0开始 */
Status GetElem(sqList* L,int i, ElemType* e){
if(i<1 || i>L->length)
return ERROR;
else
*e = L->data[i-1];
return OK;
}
/* 初始条件:顺序线性表L已存在 */
/* 操作结果:返回L中第1个与e满足关系的数据元素的位序。 */
/* 若这样的数据元素不存在,则返回值为0 */
Status LocalElem(sqList* L,ElemType e){
int i;
if(L->length==0)
return ERROR;
for(i=0;i<L->length;i++)
if(e==L->data[i])
break;
if(i>=L->length) //没有找到相匹配的元素
return 0;
return i+1;
}
/* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L), */
/* 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1 */
Status ListInsert(sqList* L,int i,ElemType e){
int k;
if(L->length == MAXSIZE) return ERROR;
if(i<1 || i>L->length+1) return ERROR;
for(k=L->length-1;k>=i-1;k--)
L->data[k+1]=L->data[k];
L->length++;
L->data[i-1]=e ;
return OK;
}
/* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L) */
/* 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1 */
Status ListDelete(sqList* L,int i,ElemType* e){
int k;
if(i<1 || i>L->length) return ERROR;
else
*e = L->data[i-1];
for(k=L->length-1;k>i;k--)
L->data[k]=L->data[k+1];
L->length--;
return OK;
}
/* 初始条件:顺序线性表L已存在 */
/* 操作结果:依次对L的每个数据元素输出 */
Status ListTraverse(sqList* L){
int i;
for(i=0;i<L->length;i++)
printf("%d ",L->data[i]);
return OK;
}
/*求并集*/
void unioList(sqList* La,sqList* Lb){
int La_len,Lb_len,i;
ElemType e;
La_len = La->length;
Lb_len = Lb->length;
for(i=1;i<=Lb_len;i++){
/*用e来获取Lb线性表中的值*/
GetElem(Lb,i,&e);
if(!LocalElem(La,e))
ListInsert(La,++La_len,e);
}
}
int main(){
//构造一个有10个数的Lb
sqList Lb;
sqList L;
ElemType e;
int i,j,k;
InitList(&L); //初始化
printf("初始化L后:L.length=%d
",L.length);
/*插入数据*/
for(j=1;j<=5;j++)
ListInsert(&L,1,j);
printf("在L的表头依次插入1~5后:L.data=");
ListTraverse(&L); //遍历输出
printf("
");
printf("L.length=%d
",L.length);
i = ListEmpty(&L); //判断是否为空
printf("L 是否为空:i=%d(1:是 0:否)
",i);
i =ClearList(&L); //清空线性表
printf("清空L后:L.length=%d
",L.length);
i = ListEmpty(&L);//判断是否为空
printf("L 是否为空:i=%d(1:是 0:否)
",i);
for(j=1;j<=10;j++) /*插入数据*/
ListInsert(&L,j,j);
printf("在L的表尾依次插入1~10后:L.data=");
ListTraverse(&L);
printf("
");
printf("L.length=%d
",L.length);
GetElem(&L,5,&e); //取得5号元素
printf("L中第五个元素=%d
",e);
for(j=7;j<9;j++){
k=LocalElem(&L,j); //判断是否存在元素
if(k)
printf("存在%d号元素=%d
",j,k);
else
printf("No存在%d号元素
");
}
k=ListLength(&L);
for(j=k+1;j>=k;j--){
i=ListDelete(&L,j,&e); //删除第j个元素
if(i == ERROR)
printf("删除第%d个数据失败
",j);
else
printf("删除第%d个的元素值为:%d
",j,e);
}
printf("依次输出L的元素:");
ListTraverse(&L);
j=8;
ListDelete(&L,j,&e); //删除8号元素
printf("删除第%d个的元素值为:%d
",j,e);
printf("依次输出L的元素:");
ListTraverse(&L);
printf("
");
/*合并La ,Lb*/
InitList(&Lb);
/*插入数据*/
for(j=10;j<=100;j+=10){
ListInsert(&Lb,1,j);
}
unioList(&L,&Lb); //合并
printf("依次输出合并了Lb的L的元素:");
ListTraverse(&L);
return 0;
}
注意点:
1、线性表其实可以理解是数组的一种特殊表示,但线性表的数据是从1开始的,数组的元素是从0开始的。
2、线性表的顺序存储结构,在存、读哪个数据的时候,不管在哪个位置,时间复杂度都是O(1),而在插入和删除时,时间复杂度时O(n)。
3、线性表的优点:无需为表示表中元素之间的逻辑关系而增加额外的存储空间;可以快速的存取表中的任意一个位置的元素。
4、线性表的缺点:插入和删除数据时需要移动大量的数据;当线性表长度变化较大时,难以确定存储空间的容量;容易造成存储空间的 ”碎片“
Java代码实现见下一篇。