<数据结构>动态数组实现顺序表

/*本文用于汇总顺序表的基本操作*/
/*顺序表是在计算机内存中以数组的形式保存的线性表,是指用一组地址连续的存储单元依次存储数据元素的线性结构。逻辑上相邻的两个元素在物理位置上也是相邻的*/
/*实现的是分离式结构的动态顺序表*/
#include<stdio.h>
#include<stdlib.h>  //包含malloc的头文件

#define LIST_INIT_SIZE 100   //线性表存储空间的初始分配量,100是个数,没有单位,即不存在100个字节或100位这样
#define LISTINCREMENT 10     //线性表存储空间的分配增量
#define ElemType int         //将ElemType定义为整型,是为了程序的可操作性,如果要对程序进行修改,如换成double型,只需修改该行即可
                             //有的编辑器里可能会写成#define int ElemType的形式,编译报错的时候可尝试将二者颠倒
#define Status int           //编写函数时给一个返回值 而不是用void类型
#define ok 1
#define error 0
#define overflow -1 //这四行应该同时出现

/*定义一个结构体类型,SqList是该类型的变量*/
typedef struct {
    ElemType *elem;          //存储空间基址,第一个元素结点的地址,联系:数组名即数组第一个元素的地址,a = &a[0]
    int length;              //当前长度,当前元素个数
    int listsize;            //当前分配的存储容量(以sizeof(ElemType)为单位,当前的最大长度
}SqList;

/*顺序表初始化*/
Status InitList(SqList *L) { //C语言中没有引用&,要想直接对数据元素进行操作,需要传递指针
    L->elem = (ElemType *)malloc(LIST_INIT_SIZE*sizeof(ElemType));
    //(void *)malloc(sizeof(viod))函数返回申请成功的空间的地址(指针),第一个*表示地址,第二个*表示相乘
    if(L->elem == NULL ) return error;   // 存储分配失败,有时也用exit
    
    L->length = 0;           //顺序表长度为0
    L->listsize = LIST_INIT_SIZE;  //初始存储空间
    return ok;       //此处是为了对应Status,返回一个数值,为0为1为-1为其他都行,如果后续需要用这个返回值做判断之类的,要注意取值有无冲突
}                   //因为有exit(1),所以不能用void

/*exit是一个函数,进程退出时会有一个值,exit函数的参数就是指明进程退出的返回值,操作系统根据这个值来判断是否是正常退出。
无论参数是什么,调用exit()函数后都会退出,对程序无影响(例如控制台程序),只是将这个参数返回给操作系统。
通常exit(0)表示正常退出,其他参数表示异常退出*/

/*销毁顺序表*/
void  DestroyList(SqList *L) {
    free(L->elem);   //释放存储空间
    L->elem = NULL;  //保险起见,free过的指针均置为空,免得出现野指针
    
    L->length = 0;   //表长归零
    L->listsize = 0; //存储容量归零
}

/*关于野指针的问题:
free和delete只是把指针所指的内存给释放掉,但并没有把指针本身释放掉。
用调试器跟踪示例程序,发现指针p被free 以后其地址仍然不变(非NULL),只是该地址对应的内存是垃圾,p成了“野指针”。
如果此时不把p设置为NULL,会让人误以为p是个合法的指针。
如果程序比较长,有时记不住p所指的内存是否已经被释放,在继续使用p之前,通常会用语句if(p!= NULL)进行防错处理。
然而!!!此时if 语句起不到防错作用,因为即便p不是NULL指针,它也不指向合法的内存块。
函数体内的局部变量在函数结束时自动消亡。很多人误以为,p是局部的指针变量,它消亡的时候会让它所指的动态内存一起完蛋。这是错觉!(会造成内存被占用但是没有指针指向?
即:(1)指针消亡了,并不表示它所指的内存会被自动释放;
   (2)内存被释放了,并不表示指针会消亡或者成了NULL指针;
野指针的成因主要有两种:
    (1)指针变量没有被初始化。任何指针变量刚被创建时不会自动成为NULL 指针,它的缺省值是随机的,它会乱指一气。
    所以,指针变量在创建的同时应当被初始化,要么将指针设置为NULL,要么让它指向合法的内存。例如
    char *p = NULL;
    char *str = (char *) malloc(100);
   (2)指针p被free或者delete之后,没有置为NULL,让人误以为p是个合法的指针。
   (3)指针操作超越了变量的作用范围。如在把a的地址赋给p前a已经被释放,此时不知道p指向哪儿
Q:用新值赋给p不就可以了吗?
*/

/*将L重置为空表,表结构仍然处于内存中*/
void Clear(SqList *L) {
    L->length = 0;
}

/*判断L是否为空表*/
Status ListEmpty(SqList *L) {
    if(L->length == 0) return ok;
    else return error;
}
/*因为插入、删除、查找等操作都会对参数有一个类似限制条件:if(i>L.length || i<1),这样就保证了在把length设为0后,其他操作就不能访问到原来的那些元素
(实质上原来的元素还是在内存空间里的,如果直接用索引去访问,仍然可以把元素读取出来的),
但是可以认为length=0的表是空表,此条件也就是判断表是否为空的唯一依据。*/

/*获得表中元素个数/获得表长*/
Status ListLength(SqList *L) {
    return L->length;
}

/*获得表中第i个数据元素赋给e*/
Status GetElem(SqList *L, int i, ElemType *e) { //不用指针无法得到e值,值传递vs地址传递 && 全局变量vs局部变量
    if(i < 1 ||i > L->length)  return error; 
    *e = L->elem[i-1];//第一个元素从0开始编号,若从1开始编号则为L.elem[i];
    return ok;
}

/*返回顺序表中与元素e满足compare()关系的位序,下面是满足equal的函数*/
int LocateElem(SqList *L, ElemType *e) {
    int i,num = L->length;
    for(i = 0; i < num; i++) {
        if(L->elem[i] == *e) return i+1;//第一个元素从0开始编号
    }
    return 0;
    /*
    ElemType *p=NULL; 
    int i=1; // i的初值为第1个元素的位序 
    p=L.elem; // p的初值为第1个元素的存储位置 
 
    while(i<=L.length&&!equal(*p++,e)){ 
      ++i; 
    } 
    if(i<=L.length) 
      return i; 
    else 
     return 0; 
    */   
}

/*在第i个位置之前插入元素*/
Status Insert (SqList *L, int i, ElemType e) {
    ElemType *p = NULL, *q = NULL;//创建即初始化
    if (i < 1 || i > L->length + 1) return error;//i值不合法,因为要在i位置之前插入元素e
    if (L->length >= L->listsize) {//当前空间已满,因为插入元素要移动后续元素,需要追加分配
        ElemType *newbase;
        newbase = (ElemType*)realloc(L->elem, (LISTINCREMENT + L->listsize)* sizeof(ElemType));
        if (newbase = NULL) 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;
}   
/*删除第i个元素*/
Status Delete (SqList *L, int i, ElemType *e) {
    if (i < 1 || i > L->length + 1) return error;//i值不合法
    ElemType *p, *q;
    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;
}
/*打印表*/
/*数组实现*/
void Display (SqList *L) {
    int i;
    for (i = 0; i < L->length; i++) {
        printf ("%d ", L->elem[i]);
    }
    printf ("\n");
}
/*指针实现*/
//才疏学浅 还没实现

int main (void) {
    SqList L;
    InitList (&L);//&是取地址
    printf ("case 1:test_Initlist\n");
    printf ("the right number is 0,and the real number is: %d\n",L.length);

    printf ("case 2:test_ListEmpty\n");
    printf ("if the list is empty,the number is 1,now the number is %d\n", ListEmpty(&L));

    printf ("case 3:test_Insert\n");
    int i;
    for (i = 0; i < 9; i++) {
        Insert (&L, i, i + 1);//因为在0之前没有位置可以插入,所以最终插入了8个字符
    }

    printf ("case 4:test_Display\n");
    Display (&L);

    printf ("case 5:test_ListLength\n");
    printf ("now the number is %d\n", ListLength(&L));
    
    printf ("case 6:test_Delete\n");
    ElemType e;
    Delete (&L, 2, &e);
    printf ("the number is %d\n", e);

    printf ("case 7:test_GetElem\n");
    ElemType x;
    Delete (&L, 2, &x);
    printf ("the number is %d\n", x);

    DestroyList(&L);
    return 0;
}

测试结果

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值