前言:
线性表是最基本、最简单也最常用的一种数据结构。例如成绩单中每个成绩记录就是一个数据元素,每个元素又包含学号、姓名等数据项。下面我将介绍线性表的顺序和链式两种存储结构。
1.线性表及其逻辑结构
1.1线性表的定义
线性表是具有相同特性的数据元素的一个有限序列。它的逻辑结构简单,便于实现和操作。因此,线性表这种数据结构在实际应用中是广泛采用的一种数据结构。逻辑结构可以用下图表示:
从定义可以得出线性表的三点特性:
1.有穷性:一个线性表中的元素个数有限。
2.一致性:一个线性表中元素的性质都一致。
3.序列性: 只存在唯一的开始元素和终端元素。每个元素只有唯一的前驱元素和后继元素。各元素在线性表中的位置只取决于它们的序号,所以在一个线性表中可以存在两个值相同的元素。
2.线性表的顺序存储结构
2.1顺序表
线性表的顺序存储结构是把线性表中的元素按照其逻辑顺序依次存储在从计算机存储器中指定的存储位置开始的一块连续的存储空间中。如图线性表到顺序表的映射示意图。
2.2顺序表的基本运算
顺序表的基本运算包括创建、插入、删除、查找等等,下面我们来具体实现。先是存储结构在声明时我们需要定义一个数组来存储线性表中的所有元素,再定义一个整型变量存储线性表的实际长度。
typedef struct
{
ElemType data[MaxSize]; //存放线性表中的元素
int length; //存放长度
}SqList; //顺序表类型
这一步不明白的话可以查看我这一篇 用户自己建立数据类型。
1.整体建立顺序表
void CreateList(SqList * & L,ElemType a[],int n)
{
int k=0,i=0; //k表示L中元素的个数
L=(SqList *)malloc(sizeof(SqList)); //分配存放线性表的空间
while (i<n) //扫描数组a的元素
{
L->data[k]=a[i]; //将元素a[i]存放在L中
k++;
i++;
}
L->length=k; //设置长度
}
2.初始化
构建一个空的线性表L,将length域设为0。
void InitList(SqList *& L)
{
L=(SqList *)malloc(sizeof(SqList)); //分配存放顺序表的空间
L->length=0; //长度设为0
}
3.插入数据元素
在顺序表L的第i(1≤i≤n+1)个位置上插入新元素e,若i值正确就将顺序表原来第i个元素及其以后的元素都后移一个位置。最后length加1。如图:想在箭头处插入一个元素,便要将箭头处及箭头以后的元素向后移一个位置,然后在空出位置插入新元素。
插入新元素后:
bool ListInsert(SqList * &L,int i,ElemType e)
{
int j;
if(i<1||i>L->length+1||L->length>MaxSize) //判断i值是否正确
return false;
i--; //将顺序表的逻辑序号转化为物理序号
for(j=L->length;j>i;j--)
L->data[j]=L->data[j-1]; //将data[i]及其后面的元素后移
L->data[i]=e; //插入e
L->length++; //长度加1
return true;
}
4.删除第i个元素
删除顺序表L的第i(1≤i≤n)个元素。若i值不正确返回false,否则将线性表第i个元素以后的元素均向前移动一个位置,并从a(i+1)开始移动,这样第i个元素就被覆盖了,最后长度减一即可。如图想要删除红色元素,便要将它后面的元素都向前移一位
5.查找元素
这里我们按照元素的查找,顺序表中有这个值就输出“存在”否则输出不存在。
int Research(SqList *L,ElemType e)
{
int i=0;
while(i<L->length&&L->data[i]!=e)
i++;
if(i>=L->length)
return 0;
else
return i+1;
}
全部代码
#include<stdio.h>
#include<malloc.h>
#define MaxSize 50
typedef int ElemType;
//存储结构
typedef struct
{
ElemType data[MaxSize];
int length;
}SqList;
//创建线性表
void CreateList(SqList * & L,ElemType a[],int n)
{
int k=0,i=0; //k表示L中元素的个数
L=(SqList *)malloc(sizeof(SqList)); //分配存放线性表的空间
while (i<n) //扫描数组a的元素
{
L->data[k]=a[i]; //将元素a[i]存放在L中
k++;
i++;
}
L->length=k; //设置长度
}
//初始化线性表
void InitList(SqList *& L)
{
L=(SqList *)malloc(sizeof(SqList)); //分配存放顺序表的空间
L->length=0; //长度设为0
}
//输出线性表
void DispList(SqList *L)
{
for(int i=0;i<L->length;i++)
{
printf("%d",L->data[i]);
printf("\n");
}
}
//销毁线性表
void DestroyList(SqList *& L)
{
free(L); //释放L所指的顺序空间
}
//插入元素
bool ListInsert(SqList * &L,int i,ElemType e)
{
int j;
if(i<1||i>L->length+1||L->length>MaxSize) //判断i值是否正确
return false;
i--; //将顺序表的逻辑序号转化为物理序号
for(j=L->length;j>i;j--)
L->data[j]=L->data[j-1]; //将data[i]及其后面的元素后移
L->data[i]=e; //插入e
L->length++; //长度加1
return true;
}
//求线性表长度
int ListLength(SqList *L)
{
return L->length;
}
//按元素值查找
int Research(SqList *L,ElemType e)
{
int i=0;
while(i<L->length&&L->data[i]!=e)
i++;
if(i>=L->length)
return 0;
else
return i+1;
}
//按序号得到线性表中的元素
int GetElem(SqList *L,int i,ElemType &e)
{
if(i<1||i>L->length)
return false;
else
e=L->data[i-1];
return true;
}
//删除第i元素
bool Delete(SqList *&L,int i,ElemType &e)
{
int j;
if(i<1||i>L->length)
return false;
i--;
e=L->data[i];
for(j=i;j<L->length;j++)
L->data[j]=L->data[j+1];
L->length--;
return true;
}
int main()
{
SqList *L;
ElemType m,e;
printf("初始化线性表\n");
InitList(L);
printf("按顺序插入元素1,2,3,4\n");
ListInsert(L,1,1);
ListInsert(L,2,2);
ListInsert(L,3,3);
ListInsert(L,4,4);
printf("打印线表元素\n");
DispList(L);
printf("输入要查找的值:\n");
scanf("%d",&e);
if(Research(L,e)==0){
printf("不存在\n");
}else
printf("存在\n");
printf("输入要删除第几个元素:\n");
scanf("%d",&m);
Delete(L,m,e);
printf("删除元素后打印表\n");
DispList(L);
DestroyList(L);
return 0;
}
结果
到这里顺序表的一些基本运算就大致介绍完了,因为采用数组储存元素在进行一些运算时,我们会发现很麻烦,例如插入操作如果需要在表头插入一个元素,那么后面的元素就要全部移动,时间复杂度会很高,后面会介绍采取链式存储结构,它相比顺序存储方式就大大便利了。最后说的不好的地方还请多多指正,谢谢。