线性表的顺序表示指的是用一组地址连续的存储单元依次存储线性表的数据元素。
线性表的第一个数据元素a1的存储位置,通常称作线性表的起始位置或基地址。
只要确定了存储线性表的起始位置,线性表中任一数据元素都可随机存取,所以线性表的顺序存储结构是一种随机存取的存储结构。
数组类型有随机存取的特性,因此通常都用数组来描述数据接哦故中的顺序存储结构。由于线性表的长度可变,且所需最大存储空间随问题不同而不同,在C语言中可用动态分配的一维数组,如下描述。
/* 线性表的动态分配顺序存储结构 */ #define LIST_INIT_SIZE 100 /* 线性存储空间的初始分配量 */ #define LISTINCREMENT 10 /* 线性存储空间的分配增量 */ typedef struct { ElemType *elem; /* 存储空间基址 */ int length; /* 当前长度 */ int listsize; /* 当前分配的存储容量(以sizeof(ElemType)为单位) */ } SqList;
在上述定义中,数组指针elem指示线性表的基地址,length指示线性表的当前长度。顺序表的初始化操作就是为顺序表分配一个预定定义大小的数组空间,并将线性表的当前长度设为“0”。listsize指示顺序表当前分配的存储空间大小,一旦因插入元素而空间不足时,可进行再分配,即为顺序表增加一个大小为存储LISTINCREMENT个数据元素的空间。
要特别注意的是,C语言中数组的下标是从“0”开始,因此,若L是SqList类型的顺序表,则表中第i个数据元素是L.elem[i-1]。
//构造一个空的线性表 Status InitList_Sq(SqList &L) { L.elem = (ElemType *)malloc(LIST_INIT_SIZE * sizeof(ElemType)); if (!L.elem) exit(OVERFLOW); L.length = 0; //空表长度为0 L.listsize = LIST_INIT_SIZE; //初始存储容量 return OK; }
一般情况下,在第i(1<= i <= n)个元素之前插入一个元素时,需将第n至第i(共n-i+1)个元素向后移动一个位置。如下算法:
//在线性表中插入元素 //在顺序线性表L中第i个位置之前插入新的元素e, i的合法值为 1<= i <= ListLength_Sq(L) + 1 Status ListInsert_Sq(SqList &L, int i, ElemType e) { ElemType *newbase = NULL; ElemType *p = NULL; ElemType *q = NULL; if (i <1 || i >L.length + 1) return ERROR; if (L.length >= L.listsize) { newbase = (ElemType *)realloc(L.elem, (L.listsize + LISTINCREMENT) * sizeof(ElemType)); if (!newbase) exit(OVERFLOW); L.elem = newbase; L.listsize += LISTINCREMENT; } q = &(L.elem[i - 1]); //q为插入位置 for (p = &(L.elem[L.length - 1]); p >= q; --p) *(p + 1) = *p; //插入位置及之后的元素右移 *q = e; ++L.length; return OK; }
删除第i(1<= i <= n)个元素时需将从第i+1至第n(共n-i)个元素依次向前移动一个位置。如下算法:
//删除线性表中的元素 //在顺序线性表L中删除第i个元素, 并用e返回其值, i的合法值为 1<= i <= ListLength_Sq(L) Status ListDelete_Sq(SqList &L, int i, ElemType &e) { ElemType *p = NULL; ElemType *q = NULL; if ((i < 1) || (i > L.length)) return ERROR; p = &(L.elem[i - 1]); //p为被删除元素的位置 e = *p; q = L.elem + L.length - 1; //表尾元素位置 for (++p; p <= q; ++p) *(p - 1) = *p; //被删除元素之后的元素左移 --L.length; //表长减1 return OK; }
在顺序表L中查访是否存在和e相同的数据元素的最简便的方法是,令e和L中的数据元素逐个比较。如下算法:
int LocateElem_Sq(SqList L , ElemType e , Status (*compare)(ElemType , ElemType)) { //在顺序线性表L中查找第1个值与e满足compare()的元素的位序 //若找到,则返回其在L中的位序,否则返回0 i = 1; //i的初值为第1个元素的位序 p = L.elem; //p的初值为第1个元素的存储位置 while(i <= L.length && !(*compare)(*p++ , e)) ++i; if(i <= L.length) return i; else return 0; }
顺序线性表的实现代码如下:
//线性表的顺序表示与实现 #include <stdio.h> #include <stdlib.h> /****************************************************************************** /* 数据类型和常量定义 /******************************************************************************/ #define TURE 1 #define FALSE 0 #define OK 1 #define ERROR 0 #define OVERFLOW -2 typedef int Status; typedef int ElemType; /****************************************************************************** /* 数据结构声明 /******************************************************************************/ /* 线性表的动态分配顺序存储结构 */ #define LIST_INIT_SIZE 2 /* 线性存储空间的初始分配量 */ #define LISTINCREMENT 1 /* 线性存储空间的分配增量 */ typedef struct { ElemType *elem; /* 存储空间基址 */ int length; /* 当前长度 */ int listsize; /* 当前分配的存储容量(以sizeof(ElemType)为单位) */ } SqList; //构造一个空的线性表 Status InitList_Sq(SqList &L) { L.elem = (ElemType *)malloc(LIST_INIT_SIZE * sizeof(ElemType)); if (!L.elem) exit(OVERFLOW); L.length = 0; //空表长度为0 L.listsize = LIST_INIT_SIZE; //初始存储容量 return OK; } //在线性表中插入元素 //在顺序线性表L中第i个位置之前插入新的元素e, i的合法值为 1<= i <= ListLength_Sq(L) + 1 Status ListInsert_Sq(SqList &L, int i, ElemType e) { ElemType *newbase = NULL; ElemType *p = NULL; ElemType *q = NULL; if (i <1 || i >L.length + 1) return ERROR; if (L.length >= L.listsize) { newbase = (ElemType *)realloc(L.elem, (L.listsize + LISTINCREMENT) * sizeof(ElemType)); if (!newbase) exit(OVERFLOW); L.elem = newbase; L.listsize += LISTINCREMENT; } q = &(L.elem[i - 1]); for (p = &(L.elem[L.length - 1]); p >= q; --p) *(p + 1) = *p; *q = e; ++L.length; return OK; } //删除线性表中的元素 //在顺序线性表L中删除第i个元素, 并用e返回其值, i的合法值为 1<= i <= ListLength_Sq(L) Status ListDelete_Sq(SqList &L, int i, ElemType &e) { ElemType *p = NULL; ElemType *q = NULL; if ((i < 1) || (i > L.length)) return ERROR; p = &(L.elem[i - 1]); e = *p; q = L.elem + L.length - 1; //表尾元素位置 for (++p; p <= q; ++p) *(p - 1) = *p; //被删除元素之后的元素左移 --L.length; return OK; } //遍历线性表 Status ListTraverse_Sq(SqList &L, Status (*Visit)(ElemType)) { ElemType *p = NULL; ElemType *q = NULL; if (L.length == 0) return ERROR; p = &(L.elem[0]); q = L.elem + L.length - 1; //表尾元素位置 for (; p <= q; ++p) Visit(*p); return OK; } //访问线性表中的元素 Status Visit(ElemType e) { printf("%d ", e); return OK; } // 测试函数 void main() { SqList L; InitList_Sq(L); ElemType e; //遍历空表 if (OK == ListTraverse_Sq(L, Visit)) printf("visit succeed!\n"); //插入元素 if (OK == ListInsert_Sq(L, 1, 10)) printf("insert succeed!\n"); if (OK == ListInsert_Sq(L, 2, 20)) printf("insert succeed!\n"); if (OK == ListInsert_Sq(L, 1, 30)) printf("insert succeed!\n"); if (OK == ListInsert_Sq(L, 2, 40)) printf("insert succeed!\n"); if (OK == ListInsert_Sq(L, 1, 50)) printf("insert succeed!\n"); //遍历非空表 if (OK == ListTraverse_Sq(L, Visit)) printf("visit succeed!\n"); //删除元素 if (OK == ListDelete_Sq(L, 1, e)) printf("delete %d succeed!\n", e); if (OK == ListDelete_Sq(L, 3, e)) printf("delete %d succeed!\n", e); if (OK == ListDelete_Sq(L, 2, e)) printf("delete %d succeed!\n", e); //遍历非空表 if (OK == ListTraverse_Sq(L, Visit)) printf("visit succeed!\n"); }