线性表:线性表的顺序储存结构是一种随机存取的储存结构
以下代码及注释则是其基本操作的简单实现:
- 线性表的动态分配顺序储存结构:
储存结构中最基本的应该是存放数据元素的起始地址,然后还有相应的线性中数据个数和总的最大存放数据个数
struct list
{
ElemType *elem; //存放数据元素的基址
int length; //当前线性表的长度
int listsize; //当前分配的储存容量
}SqList;
- 相关宏定义:
为方便后面的程序修改,因此可以使用宏定义
# define LIST_INIT_ZIZE //线性表储存空间的初始值
# define LISTINCREMENT //线性表储存空间的分配增量
#define OVERFLOW 1
#define ERROR 0
#define OK 1
typedef int Status;
//Status :函数返回值(一般替换int型)
函数声明:
Status InitList(SqList &L); /*构造一个空的线性表L*/
Status ListEmpty(SqList L); /*判断是否为空表*/
Status ListFull(SqList L); /*判断是否为满表*/
Status ClearList(SqList &L); /*将L重置为空表*/
Status DestroyList(SqList &L); /*销毁线性表*/
Status ListLength(SqList L); /*线性表的长度*/
Status GetElem(SqList L,int i,ElemType &e); /*查找L中第i个元素,并用e表示其值*/
Status LocateElem(SqList L,ElemType e) /*查找L中第一个与e满足关系相等的元素的位置,查找失败则返回0*/
Status PriorElem(SqList L,ElemType cur_e,ElemType &pre_e) /* 若cur_e是L中的数据元素,且不是第一个,则pre_e返回它的前驱,否则失败,pre_e无定义*/
Status NextElem(L,cur_e,&next_e) /*若cur_e是L中的数据元素,且不是第一个,则next_e返回它的后继,否则失败,next_e无定义*/
Status ListInsert(SqList &L,int i,ElemType e); /*在L中第i个位置之前插入一个新的数据e,L的长度加一*/
Status ListDelete(SqList &L,int i,ElemType &e); /*删除L的第i个数据元素,并用e返回其值,L的长度减一*/
- 空线性表的创建:
先创建一个起始节点,因为是空表,所以将表中的数据长度设为零
Status InitList(SqList &L); /*构造一个空的线性表L*/
{
L.elem = (ElemType *)malloc(sizeof(ElemType)*LIST_INIT_ZIZE); //动态内存分配
if(!L.elem)
exit(OVERFLOW); //内存分配失败
L.length = 0; //初始化线性表长度为0
L.listsize = LIST_INIT_ZIZE; //初始化线性表储存容量
}
- 判断是否为空的线性表:
只需判断表中数据长度是否为零就行
Status ListEmpty(SqList L); /*判断是否为空表*/
{
if(L.length == 0) //线性表长度是否为0
return TURE;
else
return FLASE;
}
- 判断是否为满表:
只需判断表中数据个数是否已达到最大容纳量即可
Status ListFull(SqList L); /*判断是否为满表*/
{
if(L.length == L.listsize) //线性表长度是否已达到储存容量
return TURE;
else
return FLASE;
}
- 将线性表L重置为空表:
个人认为只需将表中数据个数都归零即可
Status ClearList(SqList &L); /*将L重置为空表*/
{
L.length = 0; //线性表长度归零
return OK;
- 销毁线性表:
将头节点置零,并将表中数据个数都置零,且表的数据容纳量也相应置零
,最后释放无用头节点
Status DestroyList(SqList &L); /*销毁线性表*/
{
L.elem = NULL; //线性表的基址归0
L.length = 0; //长度归零
L.listsize = 0; //储存容量归零
free(L.elem); //释放头结点
}
- 返回线性表长度:
只需返回表中数据个数即可
Status ListLength(SqList L); /*线性表的长度*/
{
return L.length; //返回线性表当前长度
}
- 查找L中第i个元素,并用e表示其值
首先要判断i是否为表中元素,即判断i是否大于等于一且小于表的数据长度
Status GetElem(SqList L,int i,ElemType &e); /*查找L中第i个元素,并用e表示其值*/
{
if(i < 1||i > L.length) //i小于一或i大于当前线性表长度
return ERROR;
e = *(L.elem + i - 1) //第i个元素的地址等于基址加i-1
return OK;
}
- 查找线性表L中满足函数的元素的位置:
从起始节点开始计数并判断节点是否满足相等关系,不满足则不断后移一位继续判断,直至满足相等关系,最后位置也必须满足是表中元素
Status LocateElem(SqList L,ElemType e) /*查找L中第一个与e满足关系相等的元素的位置,查找失败则返回0*/
{
int i = 1; //i的初值为第一个元素的位置
ElemType *p = L.elem; //p的初值为第一个元素的储存基址
while(i <= L.length&&!(*compare)(*p++,e)) //不超过表的长度且未找到满足关系的元素
++i;
if(i <= L.length) //i不超过表长
return i;
else
return 0;
}
返回查找到元素位置的前驱:
取表的初始地址,然后从上一个函数取得该元素位置,因为要返回前驱,所以该元素不能为首元素,即该序列不为一,然后返回该元素前驱为初始地址加i减二
Status PriorElem(SqList L,ElemType cur_e,ElemType &pre_e) /* 若cur_e是L中的数据元素,且不是第一个,则pre_e返回它的前驱,否则失败,pre_e无定义*/
{
ElemType *p = L.elem; //p的初值为第一个元素的储存基址
int a;
a = LocateElem(L,cure);
if(!a||a == 1)
return ERROR;
else
per_e = *(L.elem + a -2); //用per_e来返回该元素的前驱
return OK;
}
返回查找元素位置的后继:
取表的初始地址,然后从上一个函数取得该元素位置,因为要返回后继,所以该元素不能为尾元素,即该序列不为表中最后一个数据的序列,然后返回该元素后继为初始地址加i
Status NextElem(L,cur_e,&next_e) /*若cur_e是L中的数据元素,且不是第一个,则next_e返回它的后继,否则失败,next_e无定义*/
{
ElemType *p = L.elem; //p的初值为第一个元素的储存基址
int a;
a = LocateElem(L,cure);
if(!a||a != L.length)
return ERROR;
else
next_e = *(L.elem + a) //用next_e来返回该元素的后继
}
- 在L的第i个位置插入新元素,表长加一:
首先判断此时表的数据个数是否已达最大容量,是则增加容量,并分配新的起始地址,然后找到表的第i个位置起始地址加i减一,然后表中第i个位置之后的元素地址都后移一位,表中数据个数加一,并插入新元素
Status ListInsert(SqList &L,int i,ElemType e); /*在L中第i个位置之前插入一个新的数据e,L的长度加一*/
{
ElemType *newbase,*p,*q;
if(i < 1||i > L.length+1) //i小于一或i大于当前线性表长度+1
return ERROR;
if(L.length == L.listsize) //L当前长度等于储存容量,增加内存分配
{
newbase = (ElemType *)relloc(L.elem,(L.listsize+LISTINCREMENT)*sizeof(ElemType));//realloc对malloc申请的内存进行大小的调整
if(!newbase) //给一个已经分配了地址的指针重新分配空间,参数L.elem为原有的空间地址,之后的sizeof是重新申请的地址长度
exit(OVERFLOW); //储存分配失败
L.elem = newbase; //新基址
L.listsize += LISTINCREMENT; //增加储存容量
}
p = L.elem + i - 1; //插入元素的位置
for(q = L.elem + L.length - 1;q >= p;--q)
{
*(q+1) = *q; //插入位置及其之后的元素右移
}
*p = e; //插入e
++L.length; //表长加一
return OK;
}
- 删除线性表L第i个位置的元素,表长减一:
先判断i是否为表中元素,是则将i之后元素全部左移一位,表长相应减一(注:只是元素左移。其容量依旧不变)
Status ListDelete(SqList &L,int i,ElemType &e); /*删除L的第i个数据元素,并用e返回其值,L的长度减一*/
{
ElemType *p,*q;
if(i < 1||i > L.length+1) //i小于一或i大于当前线性表长度+1
return ERROR;
p = L.elem + i - 1; //删除元素位置
e = *p; //被删元素值赋给e
q = L.elem + L.length - 1; //表尾元素位置
for(++p;p <= q;++p)
{
*(p-1) = *p; //删除元素之后元素左移
}
--L.length; //表长减一
}
- 主函数:
主要具体实现以上操作
#include<stdio.h>
#include<stdlib.h>
struct list
{
ElemType *elem; //存放数据元素的基址
int length; //当前线性表的长度
int listsize; //当前分配的储存容量
}SqList;
int main()
{
SqList L;
InitList(SqList &L); /*构造一个空的线性表L*/
ElemType e;
ElemType &pre_e,&next_e;
int i;
int choice;
while(1)
{
printf("*************************************************\n");
printf("*[1] 判断是否为空表 [2]判断是否为满表 *\n");
printf("*[3] 将表L清空 [4] 销毁表L *\n");
printf("*[5] 查找L中第i个元素 [6]查找表中与e相等元素位置*\n");
printf("*[7]与e相等位置的前驱 [8]与e相等位置的后继 *\n");
printf("*[9]表L第i之前插入新数[10]删除L第i个元素 *\n");
printf("*************** [0] 退出系统 ******************\n");
printf("*************************************************\n");
printf("请选择: ");
scanf("%d",&choice);
switch(choice)
{
case 0: break;
case 1: ListEmpty(L); //判断是否为空表
break;
case 2: ListFull(L); //判断是否为满表
break;
case 3: ClearList(L); //将L重置为空表
break;
case 4: DestroyList(L); //销毁线性表
break;
case 5: printf("请输入i值\n");
scanf("%d",&i);
GetElem(L,i,e); //查找L中第i个元素,并用e表示其值
printf("%d\n",e);break;
case 6: printf("请输入e\n");
scanf("%d",&e);
LocateElem(L,e) //查找L中第一个与e满足关系相等的元素的位置,查找失败则返回0
break;
case 7: printf("请输入e\n");
scanf("%d",&e);
PriorElem(L,cur_e,pre_e) //若cur_e是L中的数据元素,且不是第一个,则pre_e返回它的前驱,否则失败,pre_e无定义
break;
case 8: printf("请输入e\n");
scanf("%d",&e);
NextElem(L,cur_e,next_e) //若cur_e是L中的数据元素,且不是第一个,则next_e返回它的后继,否则失败,next_e无定义
break;
case 9: printf("请输入位置和数据 \n");
scanf("%d %d",&i,&e)
ListInsert(L,i,e); //在L中第i个位置之前插入一个新的数据e,L的长度加一
break;
case 10: printf("请输入位置\n");
scanf("%d",&i);
ListDelete(L,i,e); //删除L的第i个数据元素,并用e返回其值,L的长度减一
break;
}
}
}