线性表之顺序存储与实现
- 线性表的顺序存储是指在内存中用一组地址连续的存储单元依次存储线性表的各元素,常用操作为插入、删除、查询。
- 其物理地址相邻则逻辑也相邻。
以数据元素为整型的线性表表举例来说,在C语言中,顺序表的描述如下
struct List{
int *p; //存储空间基址--->顺序表分配到的存储单元首地址
int length; //顺序表当前长度--->元素个数
int listsize; //当前分配存储容量--->可分配到的存储单元最大容量(以sizeof(int)为单位)
};
但是上述代码在定义变量时将使代码的不可读性大大增加,可复用性也很低。
在这里我们引入关键字typedef来为已存在的数据结构重命名,当定义变量时即见名知意。同时提高代码复用性,修改线性表中数据元素的数据类型时只需修改一行。同时引入define,使代码的可读性增强,
如:
#include <stdio.h>
#define ERROR -1 //表示失败
#define OK 1 //表示成功
typedef int Satus; //表示返回成功或失败,返回值为整型
typedef int Element; //将此行int修改为将要变换的类型
typedef struct List{
Element *p; //存储空间基址--->顺序表分配到的存储单元首地址
int length; //顺序表当前长度--->元素个数
int listsize; //当前分配存储容量--->可分配到的存储单元最大容量(以sizeof(int)为单位)
}SqList;
SqList L; //定义一个顺序表
如果你在代码里不用ERROR 这个宏而用-1,尤其在函数返回错误代码的时候(往往一个开发一个系统需要定义很多错误代码)。恐怕上帝都无法知道-1 表示的是什么意思吧。这个-1,我们一般称为“魔鬼数”,上帝遇到它也会发狂的。所以,我奉劝你代码里一定不要出现“魔鬼数”。(这里是从代码可读性的角度进行考虑!)
关于宏的定义与使用这里有个链接
http://mp.weixin.qq.com/s/r3alX1PsxRL-zCzNKyQAXg
- 顺序表常用操作有删除查找插入,而在操作线性表之前则需创建线性表并初始化,下面我们用一段小程序来逐一讲解
#include <stdio.h>
#include <stdlib.h> //malloc包含在此头文件中
#define FULL 0 //表示顺序表已满
#define ERROR -1 //表示失败
#define OK 1 //表示成功
typedef int Status; //表示返回成功或失败,返回值为整型
typedef int Element; //将此行int修改为将要变换的类型
typedef struct List
{
Element *p; //存储空间基址--->顺序表分配到的存储单元首地址
int length; //顺序表当前长度--->元素个数
int listsize; //当前分配存储容量--->可分配到的存储单元最大容量(以sizeof(int)为单位)
} SqList;
//初始化顺序表
Status InitList(SqList* L,int list_size)
{
L->p=(Element*)malloc(list_size*sizeof(Element));
if(!L->p)return ERROR; //分配失败,地址为空,直接返回
L->length = 0; //分配成功,继续下走,初始数据
L->listsize = list_size;
return OK; //返回成功
}
//顺序表插入元素
Status ListInsert(SqList *L,int i,Element e) //一样是返回插入成功或失败
{
int j;
if(i<0||i>L->length+1)return ERROR; //i值不合法
if(L->length==L->listsize)return FULL; //数组已满
for(j=(L->length); j>=i; j--)
{
L->p[j+1]= L->p[j];
}
L->p[i]=e; //在第i个位置插入元素e
++L->length; //表长增1
return OK;
}
//逆置顺序表
Status InverseList(SqList *L) //一样是返回逆置成功或失败
{
Element e;
int i,n;
if(L->length==0)return ERROR; //数组为空
n = L->length-1;
for(i=0; i<n; i++,n--) //数组逆置
{
e = L->p[i];
L->p[i] = L->p[n];
L->p[n] = e;
}
}
//输出顺序表
void InputList(SqList *L)
{
int i;
for(i=0; i<L->length; i++)
{
printf("%d ",L->p[i]);
}
}
int main()
{
int i,n,e;
SqList L;
scanf("%d",&n);
if(InitList(&L,n)==-1)
{
printf("顺序表创建失败");
exit(0);
}
for(i=0; i<n; i++)
{
scanf("%d",&e);
if(ListInsert(&L,i,e)==-1)
printf("顺序表数据插入失败");
}
if(InverseList(&L)==-1)
printf("顺序表逆置失败");
InputList(&L);
}
当然了,上述代码是为了详尽描述数据结构的操作,正常做题是不应该输出一些无关数据的。
除此之外,顺序表还有删除,查找等功能,代码如下:
//查找给定元素e的位序
int LocateElem(SqList *L,Element e)
{
int i;
if(L->length==0)return ERROR; //顺序表为空
for(i=0; i<L->length; i++)
{
if(e==L->p[i])
return i;
}
return ERROR; //顺序表中未找到与e相等的元素
}
//删除给定元素e
int ListDelete1(SqList *L,Element e)
{
int i = LocateElem(L,e);
if(i==-1)return ERROR; //删除失败
ListDelete2(L,i);
}
//删除指定位置元素e
int ListDelete2(SqList *L,int i)
{
int j;
if(L->length==0)return ERROR; //数组为空,删除失败
if(i<0||i>L->length)return ERROR; //i值不合法
for(j=i; j<L->length-1; j++)
{
L->p[j]=L->p[j+1];
}
--L->length;
}
有了上边的基础操作,剩下的一些顺序表的并交操作就交给各位自己练习了。博主今天的讲解到此结束。