#include <stdio.h>
#include <stdlib.h>//malloc()
#define OK 1
#define ERROR 0
#define TURE 1
#define FALSE 0
#define INFEASIBLE -1 //不可行的
#define OVERFLOW -2 //溢出
#define LIST_INIT_SIZE 100//初始分配的元素个数(这些数据都是自己定义的,可以根据实际情况来分配)
#define LIST_ADD_SiZE 10//分配增量
typedef char ElemType;//表明ElemType是 char 类型
//========================线性表的动态分配存储结构====================
typedef struct
{
ElemType *elem;//指针型变量,存储空间的起始地址
int length;//当前的长度(存储的数据个数)
int listsize;//当前分配的存储容量
}SqList;
//基本操作定义
//==========================InitList()初始化函数======================
int InitList(SqList &L)
{
L.elem=(ElemType *)malloc(LIST_INIT_SIZE*sizeof(LIST_INIT_SIZE));//用指针elem存储分配的线性表的起始地址
if(!L.elem)
exit(OVERFLOW);//由于某种原因,内存分配失败
L.length=0;//初始化时候最初存储的元素个数为0
L.listsize=LIST_INIT_SIZE;
return OK;
}
//==========================ClearList()重新设置为空表==================
int ClearList(SqList &L)
{
L.length=0;
return OK;
}
//==========================ListEmpty()判断是否为空================================
int ListEmpty(SqList L)
{
if(L.length==0)
return TURE;//为空,返回TURE
else
return FALSE;//不为空,返回FALSE
}
//==========================ListLength()返回线性表的长度=====================================
int ListLength(SqList L)
{
if(!L.elem)
return ERROR;
return L.length;
}
//==========================GetElem()用e返回第i个数据元素的值================================
ElemType GetElem(SqList L,int i,ElemType &e)
{
if(i<1 || i>L.length || !L.elem) //查找的位置越界或L表不存在,返回错误
return ERROR;
e=*(L.elem+i-1);//蛋蛋,这里要明白的是:L.elem表示的是
return e;
}
//==========================LocateElem()返回所找元素在表中的位置================================
int LocateElem(SqList L,ElemType e,int(*compare)(ElemType,ElemType))
{
int i=1;//这里的i=1,和下面的while语句相呼应,表明的是检测【1......L.length】共length个元素
ElemType *p;
p=L.elem;//指针p存储表L的首元地址,如果用指针p做相应操作(比较),相当于直接用L.elem指针一样
while(i<=L.length && !(*compare)(*p++,e))//表中的元素和e想等时,用i记下那个位置
++i;
if(i<=L.length) //注意:上面一句,是++i;因此,当最后一个元素和e比较不等时,i仍然+1,此时i>L.length【不应该输出这个i】,所以要限制为i<=L.length
return i;
else
return FALSE;
}
//==========================GetElem()用e返回第i个数据元素的值================================
int compare(ElemType e1,ElemType e2)
{
if(e1==e2)
return TURE;
else
return FALSE;
}
//==========================PriorElem()返回cur_e的前驱元素================================
//若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱,否则操作失败
int PriorElem(SqList L,ElemType cur_e,ElemType &pre_e)
{
//关键是找到值为cur_e的元素位置
int i=2;
ElemType *p=L.elem+1;//p存储第二个元素的地址
while(i<=L.length && *p!=cur_e)//没找到,执行......
{
p++; //p指向下一个元素
i++;
}
if(i>L.length) //如果i>length时还没找到,则返回“不可行”
return INFEASIBLE;
else
{
//*--p表示先让指针减1,再取其值,所以下面用()把--p扩住,括号的运算优先级大于*运算符
//在这里强烈建议一定要看C prime Pluse 第十章{数组和指针}
pre_e=*(--p); //当找到(while循环结束),赋给pre_e
return OK;
}
}
//==========================NextElem()用next_e返回cur_e的后继元素================================
int NextElem(SqList L,ElemType cur_e,ElemType &next_e)
{
int i=1;
ElemType *p=L.elem;
while(i<L.length && *p!=cur_e)//比较【1......length-1】共length-1个元素
{
i++;
p++;
}
if(i==L.length)
return INFEASIBLE;//注意:已经找到了最后一个元素(最后一个元素没有后继),还没找到,返回“不可行”
else
{
next_e=*(++p);
return OK;
}
}
//==========================ListInsert()在第i个位置之前插入元素e================================
/*顺序表是从0开始的一种存储单位连续的数据结构,它如果有i个元素最后一个元素下标就为i
用数组来存储顺序表的元素数据,数组从【0】开始【i-1】结束,顺序表的第i个元素的数组下标是【i-1】*/
//操作结果:成功插入,length+1
int ListInsert(SqList &L,int i,ElemType e)
{
ElemType *newbase,*q,*p;
if(i<1 || i>L.length+1)//从表的第一个元素开始可以插入,在表的最后一个元素的后面也可插入元素,符合则执行
return ERROR;
//在已经有数据的基础上,表已经满了,则考虑再分配存储空间
if(L.length>=L.listsize)
{
newbase=(ElemType *)realloc(L.elem,(L.listsize+LIST_ADD_SiZE));//插入元素要考虑内存空间空间是否足够
if(!newbase)//和分配L.elem时类似(某种原因导致分配错误)
exit(ERROR);
L.elem=newbase;//用elem存储新基址
L.listsize+=LIST_ADD_SiZE;//当前分配空间增加
}
q=&(L.elem[i-1]);//用q记[i]位置的前一个位置[i-1]的元素
for(p=&(L.elem[L.length-1]);p>=q;--p)//逆序开始,把表的最后一个元素[length-1]到第[i-1]个元素处(注意范围,想一想为什么?)
*(p+1)=*p;//元素统一往后移一个位置,可以画图表示出要移动的元素起始到结束的位置!
*q=e;//表示e值放到指针所指的位置上
L.length++;//记得要让长度加1
return OK;
}
//==========================ListDelete()删除L中第i个数据,用e返回其值================================
ElemType ListDelete(SqList &L,int i,ElemType &e)
{
ElemType *p,*q;
if(i<1 || i>L.length)
return ERROR;
p=L.elem+i-1;//p为被删除元素的位置 L.elem+0相当于是L.elem[0] L.elem+i就相当于是L.elem[i]
e=*p;
q=&(L.elem[L.length-1]);//沿用插入操作的赋值方式,记录下表尾元素的位置
//++p 分析:p是指针,所以++p就是指针p指向下一个元素的位置 //遇到++i 和i++ 不要怕,弄清原则就很好理解!举个例子:C到C++ 先有C再有C++,++i表示先+1再使用。//如果这块有问题,还是看书彻底搞明白。
for(++p;p<=q;++p)//注:第一个++p表示for循环的起始位置(表示从第i个元素的后一个元素[i-1]开始向后移动一个位置),第二个++p表示进行的动作操作(自增)
*(p-1)=*p;//这里的赋值其实是后面的值覆盖了前面的元素值。
L.length--;
return OK;
}
//==========================ListTraverse()对每个数据元素调用vi()函数================================
void ListTraverse(SqList L,void(*vi)(ElemType ))
{
ElemType *p;
int i;
p=L.elem;//指针p指向L的首元地址
for(i=1;i<=L.length;i++)
vi(*p++);//依次对表中的每个元素执行Vi()函数
printf("\n");
}
//==========================vi()函数只是一个任意的你想对数据处理的函数功能,比如对int 型数据每个元素乘以2,对char型数据每个元素执行输出操作,可以参考那个资料================================
//这里的vi仅实现对元素输出的操作
void vi(ElemType e)
{
printf("%c ",e);
}
//==========================main()===========================================================
int main()
{
SqList L;
ElemType e,e1;
int i;
int k;
//执行初始化函数
InitList(L);
//=====================这步是帮助理解的==============
//执行完初始化函数后可以输出给L分配的空间基址和当前分配的空间大小
//其实这步可以帮助理解指针和存储相关的存储空间的知识
printf("%u %d 当前的元素个数:%d\n",L.elem,L.listsize,L.length);//无符号十进制输出
printf("%u \n",L.elem+1);//elem是指针,elem+1 就是指针指向下一个元素,这里测试的是char类型,char类型 占一个字节。通过输出可以一看出。地址+1
//同样的道理,如果这里存储的是int类型,int 类型占4个字节,下一个int元素的地址是上一个int元素地址+4。
//每个变量都占有一定数目的字节(通过sizeof运算符获得)其中取第一个字节的地址做该变量的地址。
//=========================又啰嗦了,进入正题!============================================
//判断是否为空
if(ListEmpty(L)==TURE)
printf("由于线性表的长度存储的元素个数是0,所以为空。\n");
else if(ListEmpty(L)==FALSE)//判断不为空,同时输出元素个数。
printf("不空。存储的元素个数是=>:%d\n",L.length);
//接下来向表内手动插入元素
printf("请输入你要插入的元素个数=>:");
scanf("%d",&k);
printf("请输入数据=>:");
for(i=1;i<=k;i++)
{
scanf(" %c",&e);//输入一个数据,把它插入到依次第i个元素之前
ListInsert(L,i,e);
}
//测试输出L里面的数据
ListTraverse(L,vi);
printf("当前表的长度是:%d\n",ListLength(L));
printf("查找元素的位置(接下来请输入你要查找的元素)=>:");
scanf(" %c",&e);
i=LocateElem(L,e,compare);
if( i==FALSE)
printf("表中没有该元素!\n");
else
printf("你所找的元素%c在表中的位置是=>%d\n",e,i);
//========================================================
//插入元素
printf("请输入你要插入的元素的位置和值=>:");
scanf(" %d %c",&i,&e);
if(ListInsert(L,i,e)==ERROR)
printf("错误!");
else
{
printf("成功插入%c后的表L=>:",e);
//测试输出L里面的数据
ListTraverse(L,vi);
}
//============================================================
//删除元素
printf("请输入你要删除的元素在表中的位置=>:");
scanf(" %d",&i);
ListDelete(L,i,e);
printf("删除第%d个元素%c后表L=>:",i,e);
ListTraverse(L,vi);
//查找前驱元素的值
printf("请输入元素(查找该元素的前驱)=>:");
scanf(" %c",&e);
PriorElem(L,e,e1);
printf("元素%c的前驱是=>: %c\n",e,e1);
//查找后继
printf("请输入元素(查找该元素的后继)=>:");
scanf(" %c",&e);
NextElem(L,e,e1);
printf("元素%c的后继是=>: %c\n",e,e1);
ClearList(L);
printf("执行清空表操作后,表长为=>:%d\n",ListLength(L));
return 0;
}
顺序表的定义与操作实现
猜你喜欢
转载自blog.csdn.net/sinat_28995767/article/details/51494827
今日推荐
周排行