使用C++进行线性表之顺序表代码实现

情况说明:

  • 这是对于本科数据结构重新学习,代码参考本科所学的严蔚敏的数据结构和github(https://github.com/kangjianwei/Data-Structure)上一位牛人的代码进行学习。
  • 需要说明:那位牛人的宏定义方面和课本风格一致,宏定义方面特别严谨,而本系列的代码均是在理解人家代码基础上,配合课本完成简化版,可以运行的代码。

顺序表初始化:

//主要代码
//使用结构体对顺序表进行表示
typedef struct {
   int * elem;//这是指向这个结构体的指针变量
   int length;//这是顺序表的长度
   int listsize;//这是顺序表当前分配的大小,比如书里面给的100大小的空间
}SqList;

//顺序表初始化
void InitList_Sq(SqList *L){
   //首先需要动态分配一个地址
   //注意这个函数参数的位置,这里可以写成SqList *L,下面必须写成L->elem或者(*L).elem,
   //如果是Sqlist &L 下面写的形式是L.elem(*L 表示的是指针,而&L是引用,说人话就是二者都可以
   // 指向这个顺序表,&L可以理解为一个别名而已。先这样理解吧)
   L->elem = (int *) malloc(LIST_INIT_SIZE*sizeof(int));
   if(!(L->elem)){
       return;
   }
   L->length=0;
   L->listsize=LIST_INIT_SIZE;
}
int main() {
   SqList L;
   printf("开始初始化这个顺序表...\n");
   {
       InitList_Sq(&L);//&L,这里是作为实参,而*L往往作为一种形参
       printf("初始化完毕...\n");
   }
   return 0;
}

return 0加断点内存测试结果如下:
可以发现结构体的初始内存地址、长度、初始分配空间大小均已经分配好。
在这里插入图片描述
顺序表销毁

//销毁顺序表
void DestroyList(SqList *L){
    //首先释放地址空间
    free(L->elem);
    L->elem=NULL;//指针指向空
    L->length=0;//长度均变成0
    L->listsize=0;
}
 printf("开始销毁这个顺序表...\n");
    {
        DestroyList(&L);
        printf("初始化完毕...\n");//这里是销毁之后断点,变成NULL 0 0
    }

内存如图所示:
在这里插入图片描述添加元素

//某个位置插入一个数
void ListInsert_Sq(SqList *L,int i,int e){
    //在顺序表1-n的i位置之前插入一个数e
    int *newbase,*p,*q;
    if(i<1||i>(L->length)+1) return;
    if((L->length)>=(L->listsize)){
        //如果插入的数据过大,超过顺序表当前大小
        //需要重新开辟空间
        //这里用realloc 是表明在谁基础上再改变内存
        //newbase是一个新的地址
        newbase=(int *)realloc((L->elem),(L->listsize+LISTINCREMENT)*sizeof(int));
        if(!newbase) return;//如果不是这个,返回
        L->elem=newbase;//把这个新的地址分给elem
        L->listsize+=LISTINCREMENT;//容量增加
    }
    //q表示数据e insert的位置
    q=&(L->elem[i-1]);
    for(p=&((*L).elem[(*L).length-1]);p>=q;--p)
        *(p+1)=*p;//实现右移
    *q =e;//这里说明一下 ( * &q)就是表示本身的数据
    (*L).length++;
}
//测试
   printf("开始插入元素到这个顺序表...\n");
    {
        for(int i=1;i<=8;i++){
            printf("在L第%d个位置插入 \"%d\"...\n",i,i);
            ListInsert_Sq(&L,i,i);

        }
        printf("\n");
    }

结果以及debug如下:
在这里插入图片描述
在这里插入图片描述


清空顺序表

//清空顺序表
void ClearList_Sq(SqList *L){
    L->length=0;
}
//测试
   printf("开始清空这个顺序表...\n");
    {
        ClearList_Sq(&L);
        printf("清空完毕...\n");
    }

内存效果图:
在这里插入图片描述

剩余方法(看代码):

//判断顺序表是否为空
int ListIsEmpty(SqList L){
    return L.length==0?1:0;
}
//获取顺序表某个元素
void GetElem_Sq(SqList L,int i,int *e){
    if(i<1||i>L.length) return;
    else *e=L.elem[i-1];
}
//获取顺序表长度
int ListLength_Sq(SqList L)
{
    return L.length;
}
//获取顺序表前驱
int PriorElem(SqList L,int cur_e,int &pre_e){
    int i=1;
    if(L.elem[0]!=cur_e){
        while(L.elem[i]!=cur_e&&i<L.length) i++;
        if(i<L.length){
            pre_e=L.elem[i-1];
            return 1;
        }
    }
    return 0;
}
//获取顺序表后继
int NextElem(SqList L,int cur_e,int &next_e){
    int i=0;

    while(L.elem[i]!=cur_e&&i<L.length) i++;
    if(i<L.length-1){ //判断最后一个位置没有后继
        next_e=L.elem[i+1];
            return 1;
    }
    return 0;
}
//删除元素
void ListDelete(SqList &L,int i,int &e){
    int *p,*q;
    if(i<1||i>L.length) return;
    p=&(L.elem[i-1]);//定义p为e删除的位置
    e=*p;//将p位置的数值赋给e
    q=&(L.elem[L.length-1]);//元素末尾的位置
    for(;p<=q;p++){
        *(p-1)=*p;//左移
    }
    L.length--;
}
//定位函数
int LocateElem_Sq(SqList L, int e, int(Compare)(int, int))
{
    int i = 1;							//i的初值为第一个元素的位序

    while(i<=L.length && !Compare(e, L.elem[i-1]))
        ++i;

    if(i<=L.length)
        return i;
    else
        return 0;
}
void raverse_Sq(SqList L, void(Visit)(int))
{
    int i;

    for(i=0; i<L.length; i++)
        Visit(L.elem[i]);

}

整片文章总的代码如下:

/*
 * 数据结构简单代码实现
 * 参考:https://github.com/kangjianwei/Data-Structure
 * 这个代码是GitHub的简化版的再一次的实现,宏定义方面没有人家那么严谨。
 * 顺序表的实现
 * */
#include <stdio.h>
#include <stdlib.h>

//宏定义初始化的一些变量
#define LIST_INIT_SIZE 100 //这个是顺序表的初始化大小
#define LISTINCREMENT  10 //这个是顺序表需要增加的单位长度
int CmpGreater(int e, int data){return data>e? true: false;};
void PrintElem(int e){printf("%d\t",e);};

//使用结构体对顺序表进行表示
typedef struct {
    int * elem;//这是指向这个结构体的指针变量
    int length;//这是顺序表的长度
    int listsize;//这是顺序表当前分配的大小,比如书里面给的100大小的空间
}SqList;

//顺序表初始化
void InitList_Sq(SqList *L){
    //首先需要动态分配一个地址
    //注意这个函数参数的位置,这里可以写成SqList *L,下面必须写成L->elem或者(*L).elem,
    //如果是Sqlist &L 下面写的形式是L.elem(*L 表示的是指针,而&L是引用,说人话就是二者都可以
    // 指向这个顺序表,&L可以理解为一个别名而已。先这样理解吧)
    L->elem = (int *) malloc(LIST_INIT_SIZE*sizeof(int));
    if(!(L->elem)){
        return;
    }
    L->length=0;
    L->listsize=LIST_INIT_SIZE;
}
//销毁顺序表
void DestroyList(SqList *L){
    //首先释放地址空间
    free(L->elem);
    L->elem=NULL;//指针指向空
    L->length=0;//长度均变成0
    L->listsize=0;
}
//某个位置插入一个数
void ListInsert_Sq(SqList *L,int i,int e){
    //在顺序表1-n的i位置之前插入一个数e
    int *newbase,*p,*q;
    if(i<1||i>(L->length)+1) return;
    if((L->length)>=(L->listsize)){
        //如果插入的数据过大,超过顺序表当前大小
        //需要重新开辟空间
        //这里用realloc 是表明在谁基础上再改变内存
        //newbase是一个新的地址
        newbase=(int *)realloc((L->elem),(L->listsize+LISTINCREMENT)*sizeof(int));
        if(!newbase) return;//如果不是这个,返回
        L->elem=newbase;//把这个新的地址分给elem
        L->listsize+=LISTINCREMENT;//容量增加
    }
    //q表示数据e insert的位置
    q=&(L->elem[i-1]);
    for(p=&((*L).elem[(*L).length-1]);p>=q;--p)
        *(p+1)=*p;//实现右移
    *q =e;//这里说明一下 ( * &q)就是表示本身的数据
    (*L).length++;
}
//清空顺序表
void ClearList_Sq(SqList *L){
    L->length=0;
}
//判断顺序表是否为空
int ListIsEmpty(SqList L){
    return L.length==0?1:0;
}
//获取顺序表某个元素
void GetElem_Sq(SqList L,int i,int *e){
    if(i<1||i>L.length) return;
    else *e=L.elem[i-1];
}
//获取顺序表长度
int ListLength_Sq(SqList L)
{
    return L.length;
}
//获取顺序表前驱
int PriorElem(SqList L,int cur_e,int &pre_e){
    int i=1;
    if(L.elem[0]!=cur_e){
        while(L.elem[i]!=cur_e&&i<L.length) i++;
        if(i<L.length){
            pre_e=L.elem[i-1];
            return 1;
        }
    }
    return 0;
}
//获取顺序表后继
int NextElem(SqList L,int cur_e,int &next_e){
    int i=0;

    while(L.elem[i]!=cur_e&&i<L.length) i++;
    if(i<L.length-1){ //判断最后一个位置没有后继
        next_e=L.elem[i+1];
            return 1;
    }
    return 0;
}
//删除元素
void ListDelete(SqList &L,int i,int &e){
    int *p,*q;
    if(i<1||i>L.length) return;
    p=&(L.elem[i-1]);//定义p为e删除的位置
    e=*p;//将p位置的数值赋给e
    q=&(L.elem[L.length-1]);//元素末尾的位置
    for(;p<=q;p++){
        *(p-1)=*p;//左移
    }
    L.length--;
}
//定位函数
int LocateElem_Sq(SqList L, int e, int(Compare)(int, int))
{
    int i = 1;							//i的初值为第一个元素的位序

    while(i<=L.length && !Compare(e, L.elem[i-1]))
        ++i;

    if(i<=L.length)
        return i;
    else
        return 0;
}
//打印顺序表
void raverse_Sq(SqList L, void(Visit)(int))
{
    int i;

    for(i=0; i<L.length; i++)
        Visit(L.elem[i]);

}
int main() {
    SqList L;
    int i;
    printf("开始初始化这个顺序表...\n");
    {
        InitList_Sq(&L);//&L,这里是作为实参,而*L往往作为一种形参
        printf("初始化完毕...\n");
    }//这个断点初始化完毕结构体

    printf("开始插入元素到这个顺序表...\n");
    {
        for( i=1;i<=8;i++){
            printf("在L第%d个位置插入 \"%d\"...\n",i,i);
            ListInsert_Sq(&L,i,i);
            GetElem_Sq(L,i,&i);
            printf("在L第%d个位置元素是 \"%d\"...\n",i,i);





            //测试前驱元素,循环控制需要对端点增加元素9
            PriorElem(L,i+1,i);
            printf("元素\"%d\"的前驱元素是\"%d\"...\n",i+1,i);
            //测试后继元素,循环控制需要对端点增加元素0
            NextElem(L,i-1,i);
            printf("元素\"%d\"的后继元素是\"%d\"...\n",i-1,i);
        }

        printf("\n");
    }
    //删除元素测试
    {
       for( i=1;i<=8;i++){
           printf("顺序表长度:%d\n",ListLength_Sq(L));
           GetElem_Sq(L,i,&i-1);
           printf("在L第%d个位置元素是 \"%d\"...\n",i-1,i);
           printf("%d\n",L.elem[i-1]);
           int j=i-1;
           ListDelete(L,i,j);
           printf("在L第%d个位置删除元素是 \"%d\"...\n",i-1,i);
       }



    }

    raverse_Sq(L,PrintElem);
    printf("顺序表长度:%d\n",ListLength_Sq(L));
    int m;

    m=LocateElem_Sq(L,6,CmpGreater);
    printf("比6大的位置是第%d个数.\n",m);

    printf("这个顺序表的状态是:%d\n",ListIsEmpty(L));
    printf("开始清空这个顺序表...\n");
    {
        ClearList_Sq(&L);
        printf("清空完毕...\n");
    }
    printf("顺序表长度:%d\n",ListLength_Sq(L));
    printf("这个顺序表的状态是:%d\n",ListIsEmpty(L));
    printf("开始销毁这个顺序表...\n");
    {
        DestroyList(&L);
        printf("销毁完毕...\n");//这里是销毁之后断点,变成NULL 0 0
    }
    return 0;
}

展开阅读全文

Windows版YOLOv4目标检测实战:训练自己的数据集

04-26
©️2020 CSDN 皮肤主题: 技术工厂 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值