线性表的定义
线性表是由(n>=0)个数据元素(结点)a[0],a[1],a[2]……a[n-1]
组成的有限序列。其中,一个数据元素可以由若干个数据项组成。数据元素称为记录,含有大量记录的线性表称为文件。
线性表存在以下特点
- 存在一个唯一没有前驱(头)的数据元素
- 存在一个唯一没有后继(尾)的数据元素
- 此外,所有数据元素都有一个前驱和后继
线性表的存储结构
1 顺序表
2 链表
- 单链表(动态单链表,静态单链表)
- 双链表
- 循环链表(单循环链表,双循环链表)
下面来学习线性表的顺序表。
什么是顺序表
顺序表是在计算机内存中以数组的形式保存的线性表,是指使用一组地址连续的存储单元来存储数据元素的线性结构。
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
/* 线性表的动态分配顺序存储结构 */
#define LIST_INIT_SIZE 10 /* 线性表存储空间的初始分配量 */
#define LIST_INCREMENT 2 /* 线性表存储空间的分配增量 */
typedef struct
{
ElemType *elem;/*存储空间基址*/
int length;/*当前长度*/
int listsize;/*当前分配的存储容量(以sizeof(ElemType)为单位) */
}Sqlist;
/**
*线性表的基本操作
* 增删改查
*/
/**
* 构造一个空的顺序线性表L
* @brief InitSqlist
* @param L
*/
void InitSqlist(Sqlist *L){
L->elem=malloc(LIST_INIT_SIZE*sizeof(ElemType)); /* 存储单元的地址是连续的 */
if(!L->elem)
exit(OVERFLOW);/* 分配空间失败 */
L->length=0; /* 空表长度为0 */
L->listsize=LIST_INIT_SIZE; /* 初始存储容量 */
}
/** 初始条件:顺序线性表L已存在。销毁顺序线性表L
* @brief DestroySqlist
* @param L
*/
void DestroySqlist(Sqlist * L){
free(L->elem);
L->elem=NULL;
L->length=0;
L->listsize=0;
}
/** 清除表中所有元素
* @brief ClearSqlist
* @param L
*/
void ClearSqlist(Sqlist *L){
L->length=0;
}
/** 判断表是否为空
* @return
*/
Status ListEmpty(Sqlist *L){
if(L->length=0)
return TRUE;
return FALSE;
}
/** 返回L中数据元素个数
* @brief ListLength
* @param L
* @return
*/
int ListLength(SqList L)
{
return L.length;
}
/** 获取指定位置的数据元素
* @brief GetElem
* @param L
* @param position 数据元素在顺序表的位置(第一个是1,第二个是2……)
* @param e
* @return
*/
Status GetElem(Sqlist L,int position,ElemType *e){
if(position<1||position>L.length)
return ERROR;
*e=*(L.elem+position-1);
return OK;
}
/** 返回指定元素的位置
* @brief LocateElem
* @param L
* @param e 指定元素
* @return
*/
int LocateElem(Sqlist *L, ElemType e,Status(*compare)(ElemType,ElemType)){
/* compare()是数据元素判定函数(满足为1,否则为0) */
ElemType *p;
int 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;
}
/**
* @brief PriorElem
* @param L
* @param cur_e 当前元素
* @param pre_e 前驱
* @return
*/
Status PriorElem(Sqlist L,ElemType cur_e,ElemType *pre_e)
{
int i=2;
ElemType *p=L.elem+1;
while(i<=L.length&&*p!=cur_e)
{/*?为什么前面使用函数指针,但是此却却直接使用值比较呢?*/
p++;
i++;
}
if(i>L.length)
return INFEASIBLE; /* 操作失败 */
else
{
*pre_e=*--p;
return OK;
}
}
/**
* @brief NextElem
* @param L
* @param cur_e 当前元素
* @param next_e 后继
* @return
*/
Status NextElem(Sqlist L,ElemType cur_e,ElemType *next_e)
{
int i=1;
ElemType *p=L.elem;
while(i<L.length&&*p!=cur_e)
{
i++;
p++;
}
if(i==L.length)
return INFEASIBLE; /* 操作失败 */
else
{
*next_e=*++p;
return OK;
}
}
/**
* 插入操作需要判断插入位置是否合法,表的存储空间是否满
* 插入位置不合法就返回错误信息,满表则需要增加表的存储空间
* @brief ListInsert
* @param L
* @param i
* @param e
* @return
*/
Status ListInsert(Sqlist *L,int i,ElemType e)
{
ElemType *newbase,*q,*p;
if(i<1||i>L->length+1) /* i值不合法 */
return ERROR;
if(L->length>=L->listsize) /* 当前存储空间已满,增加分配 */
{
newbase=realloc(L->elem,(L->listsize+LIST_INCREMENT)*sizeof(ElemType));
if(!newbase)
exit(OVERFLOW); /* 存储分配失败 */
L->elem=newbase; /* 新基址 */
L->listsize+=LIST_INCREMENT; /* 增加存储容量 */
}
q=L->elem+i-1; /* q为插入位置 */
for(p=L->elem+L->length-1;p>=q;--p) /* 插入位置及之后的元素右移 */
*(p+1)=*p;
*q=e; /* 插入e */
++L->length; /* 表长增1 */
return OK;
}
/** 删除表指定元素
* @brief ListDelete
* @param L
* @param i
* @param e
* @return
*/
Status ListDelete(Sqlist *L,int i,ElemType *e)
{
ElemType *p,*q;
if(i<1||i>L->length) /* i值不合法 */
return ERROR;
p=L->elem+i-1; /* p为被删除元素的位置 */
*e=*p; /* 被删除元素的值赋给e */
q=L->elem+L->length-1; /* 表尾元素的位置 */
for(++p;p<=q;++p) /* 被删除元素之后的元素左移 */
*(p-1)=*p;
L->length--; /* 表长减1 */
return OK;
}