去幼儿园或者低年级小学的时候时常有这样的现象:
幼儿园的小朋友在放学的时候,总会排成一排或者一个小队,依次从学校的门口出来,井然有序,能让接孩子的家长们一眼就能看到自己的孩子在哪一队,哪一排,而孩子们也能知道自己前面的小朋友是谁,后面的小朋友是谁.
这种n个有限序列的结构叫做数据的顺序储存结构.
该结构向我展示了一个我从没有见过的编程新思想ADT(Abstract Data Type).
程序员可以通过这种类型的数据结构对数据进行很方便的储存操作,在这个结构里的每一个数只有唯一一个前驱元素和唯一的一个后驱元素(当n = 1时,a1没有前驱元素,当n = n时,an没有后驱元素,n=0时为空表).
ADT 线性表(List)
Data
这里必须要符合线性表里的顺序储存结构的定义.
Operation
InitList(*L);\\初始化操作,创建一个空列表L.
ListEmpty(L);\\若线性表为空,返回0,否则1.
ClearList(*L);\\清空线性表L.
GetItem(L,i,*e);\\将线性表L的第i个元素值返回给e.
LocateElem(L,e);\\在线性表里查找元素e,有就返回1,没有就返回0.
GetInsert(*L,i,e);\\在线性表L的第i个位置插入元素e.
Del(*L,i,*e);\\在线性表L的第i个位置删除元素e.
ListLength(L);\\返回线性表的元素个数.
这种储存结构有几个好处:
1.无须考虑每个元素之间的逻辑关系,并因为该逻辑关系而增加新的储存空间.
2.可以快速地存取表中任一位置的元素.
缺点也是有的:
1.因为该储存方式为直线型储存方式,所以如果想要增加或者删除该表中的某个元素的位置,最理想的时间复杂度为O(1),可以看作待操作的元素刚好是第一个或者是最后一个,而最坏的情况,如果要删除某个元素,这个元素刚好在第一个,那么需要从最后一个元素开始进行遍历,并一一进行排列,时间复杂度为O(n),因此如果这个表的元素很多,那么显然这种方法就不再适用。
2.容易造成存储空间的“碎片”.(这个我还不是很懂,垃圾这个机制要学习).
具体实现方式如下:
#include <stdio.h>
#define OK 1
#define ERROR 0
#define MAXSIZE 20
typedef int Status; \\typedef的语法(这里是为了更直观的体现代码的作用).
typedef int Elemtype;
typedef struct
{
Elemtype back[MAXSIZE];
int len = 10;
}SqList;
Status GetItem(SqList L,int i,Elemtype *e) \\该操作为获取一个数,将这个数放入变量e中.
{
if (L.len == 0 || i < 1 || i > L.len)
{
return ERROR;
}
*e = L.back[i - 1];
return OK;
}
Status GetInsert(SqList *L,int i,Elemtype e) \\这个操作用来进行插入.
{
int k;
\\开始时需要考虑异常的情况,插入的这个元素的合理性.
if(i < 1 || i > L -> len+1) \\插入的位置要合理.
{
return ERROR;
}
if(L -> len == MAXSIZE)
{
return ERROR;
}
if(i <= L -> len)
{
for(k = L -> len;k >= i-1;k--) \\从最后一位开始向前进行遍历.
{
L -> back[k+1] = L -> back[k];
}
e = L -> back[i-1];
L -> len++;\\插入了一个元素该表的长度要增加.
}
return OK;
}
Status Del(SqList *L,int i,Elemtype *e)\\删除某个元素.
{
int k;
if(L -> len == 0)
{
return ERROR;
}
if(i < 1 || i > L -> len+1)
{
return ERROR;
}
*e = L -> back[i-1];
if(i <= L -> len)
{
for(k = i;k <= L -> len;k++)
{
L -> back[k -1] = L -> back[k];
}
L -> len--;\\删除之后表的长度要减一.
}
return OK;
}