废话不多说,直奔主题。
在c语言中,一般使用数组来表示线性表的顺序存储结构,这样就能使其表的物理存储结构也是连续的(顺序存储结构),线性表的顺序存储结构又叫顺序表。即顺序表逻辑上相邻,物理上也相邻。为了能使数组进行顺序表的基础操作,我们还需要引入一个变量来指向顺序表的表尾。这个时候,我们可以使用结构体来将数组和变量包括进去。
首先我们先创建一个头文件,相当于一个能创建并操作顺序表的“库”。博主把此头文件命名为SeqList.h。之后再在头文件里自己定义数据类型——顺序表。
#ifndef __SEQLIST_H__
#define __SEQLIST_H__
#define MAXSIZE 20 //用来表示顺序表的最大长度
typedef char Elemtype;
/*顺序表只能存储一种数据类型。
为方便以后替换存储类型我们把存储类型命名为Elemtype,当需要存储浮点数类型或字符类型的数据类型时只需要修改int即可*/
typedef struct{ // 定义顺序表
elemtype elem[MAXSIZE];
/*这里建立数组来表示顺序表,最大长度固定*/
int last; /* last作为指向顺序表最后一个元素的下标
若顺序表为空,则last=-1*/
}SeqList;
/*至此我们定义完了顺序表的数据类型。
我们以后可以用int i定义整数i一样用SeqList L定义顺序表L。*/
#endif
到此,顺序表就被定义完了。
现在我们来深度理解一下顺序表的下标表示。
{a1,a2,…,ai-1,ai,ai+1,…,an}
如上,相邻数据元素之间关系是线性的,ai-1是ai的直接前驱,ai+1是ai的直接后继。a1是顺序表的起点,它的下标是1。而c语言中数组的第一位是从0开始的!所以一定要注意数组与顺序表下标的对应。
顺序表被定义完了,但是我们还没有建立这样的顺序表。所以我们还要写一个函数用来建立一个存放数据的顺序表。
SeqList NewList(SeqList L)
/*该函数是从顺序表首个元素赋值
所以只用来建新顺序表
想往顺序表内修改元素请看下文*/
{
Elemtype e; //
for(L.last=-1;(L.last<MAXSIZE);){
printf("please elem:");
scanf("%c",&e);getchar(); //getchar()用来吃掉回车
if (e=='$') break; //输入$来结束顺序表的创建
L.last++;
L.elem[L.last]=e;
}
return L;
}
下面我们定义一个函数Locate来实现顺序表的查找操作:
int Locate(SeqList L,ElemType e) // 函数功能:在顺序表中寻找元素e,返回e第一次出现的下标。
{/*逻辑简述:从顺序表L中依次查找与e相等的元素,
若L(i)=e,找到并返回i+1,否则返回-1*/
int i=0; //从第一个元素开始查找
while((i<=L.last)&&(L.elem[i]!=e)) i++;
if(i<=L.last) rerurn i+1;
else return(-1); //没有找到就返回空序号-1
}
接下来我们开始进行顺序表的修改操作的函数的编写。
定义一个函数InsList实现顺序表的插入操作:
注意,函数定义的形式参数L是指针类型!
int InsList(SeqlList *L,int i,elemtype e)
// 在顺序表L的第i个元素前插入e,插入成功返回1,否则返回0
{
int k;
if(i<1||i>L.last+2){ //判断i值是否合理
printf("插入位置i不合法");
return 0;
}
if(L->last+1>=MAXSIZES){//判断存储空间是否满了
printf("顺序表已满,不可再插入");
return 0;
}
for(k=L->last;k>=i-1;k--){ //从最后一个元素开始逐一往后挪,为e的插入在i处留出位置
L.elem[k+1]=L.elem[k];
}
L->elem[i-1]=e; // 插入e
L->last++; // 表长+1
return 1;
}
定义一个函数ListDelete实现顺序表的插入操作:
注意,函数定义的形式参数L是指针类型!
//删除操作,删除L的第i个元素并将值赋给指针e
int ListDelete(SeqList *L,int i ,Elemtype *e)
{
int k;
if(i<1||i>L->last+2){
printf("删除位置%d不合法",i);
return 0;
}
*e=L->elem[i-1];
for(k=i;k<=L->elem[k];k++){
L->elem[k-1]=L->elem[k]; //被删除元素之后的元素左移
}
L->last--; // 表长-1
return 1;
}
至此,顺序表的一些基本操作函数就写完了。我们将这些函数的定义全部放到头文件SeqList.h里。然后我们再创建一个c文件来用一下上述函数试试效果吧!
演示代码如下:
#include <stdio.h>
#include "SeqList.h" //使用引号是因为我把此头文件和c文件放在了同一目录
int main
{
SeqList L;char e; int a;
SeqList *l;Elemtype *p;
L=NewList(L);l=&L; //建立顺序表L,指针l指向L
printf("L.last=%d\n",L.last); //输出一下L.last看看是否出错,其值应该是你输入的元素数量-1
printf("输入一个你想查找的元素:");
scanf("%c",&e);getchar();
printf("该元素在第 %d位.\n",Locate(L,e));
printf("插入k成功了吗(成功1不成功0)?:%d",InsList(l,2,'k'));
printf("k在第 %d位.\n",Locate(L,'k'));
a=ListDelete(l,3,p); //删除第三个元素
printf("删除操作成功了吗?:%d,把 %c删除了",a,*p);
return 0;
}
然后执行代码:(红字为博主输入)
效果如下:
please elem:a
please elem:b
please elem:c
please elem:d
please elem:$
L.last=3
输入一个你想查找的元素:b
该元素在第 2位.
插入k成功了吗(成功1不成功0)?:1
k在第 2位
删除操作成功了吗?:1,把 b删除了
所以,我们便可以在以后使用如上介绍的函数来实现顺序表的操作了。
顺序表的缺点
从函数中可以看到。当在长度为n的顺序表上删除第i位元素,需要把n-i个元素向左移动,效率是很慢的。插入操作同理。
而且为顺序表的存储分配空间是从一开始就宏定义好的(#define MAXSIZE 20 ),不能动态分配,十分不灵活,而且表长很长时难以确定分配多少存储空间。
在这个时候,链式存储就派上了用场。
完
人生如逆旅,我亦是行人