顺序表的定义与操作实现

来源:互联网 发布:wifi连网神器mac版 编辑:程序博客网 时间:2024/06/01 09:50
#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+1int 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;}
0 0