001顺序表

一、顺序表

1、基本概念

  • 顺序表:顺序存储的线性表。
  • 链式表:链式存储的线性表,简称链表。
  • 图解:

顺序存储就是将数据存储到一片连续的内存中,在C语言环境下,可以是具名的栈数组,或者是匿名的堆数组。

存储方式不仅仅只是提供数据的存储空间,而是必须要能体现数据之间的逻辑关系。当采用顺序存储的方式来存放数据时,唯一能用来表达数据间本身的逻辑关系的就是存储位置。

2、顺序表的设计

a、顺序表结构体设计

  • 顺序表总容量
  • 顺序表当前最末元素下标位置
  • 顺序表指针(指向的内存)
  • 图解:

  • 示例代码:
  • typedef struct sequence_list
    {
        int capacity;   // 顺序表的容量
        int last;       // 顺序表的元素下标(最末尾元素的下标)
        int *data_p;    // 顺序表内存(指针指向的内存区域)  --- 以整型数据为例
    }sq_list_t, *sq_list_p;

    b、初始化顺序表

    所谓初始化就是建立一个不包含任何元素的顺序表,设置好管理结构体中的表的总容量、末元素下标,申请好顺序表内存空间等系列准备工作。

  • 图解:
  • 示例代码:
  • /**
      * @brief  初始化顺序表
      * @note   None    
      * @param  cap_size:顺序表的容量
      * @retval 成功:返回指向这个顺序表内存的指针
      *         失败:返回NULL
      */ 
    sq_list_p SQUENCE_LIST_Init(int cap_size) 
    {
        // 1、给顺序表管理结构体申请一个堆内存空间
        sq_list_p p = malloc(sizeof(struct sequence_list));
        bzero(p, sizeof(struct sequence_list));
    
        // 2、给申请的空间进行赋值操作
        if ( p != NULL)
        {
            p->capacity = cap_size;                     // 顺序表的内存空间的容量
            p->last     = -1;                           // 顺序表的元素个数(初始化时,顺序表里面没有数据,所以是-1)
            p->data_p   = malloc(sizeof(int)*cap_size); // 申请顺序表的内存空间(内存空间的大小由cap_size来决定)
                                                        // (再乘sizeof(数据类型)是为了保证空间不浪费,访问不出错)
            bzero(p->data_p , sizeof(int)*cap_size);  
            
            if ( p->data_p == NULL)                     // 判断是否申请空间失败
            {
                free(p);
                return NULL;
            }   
        }
        else                                            // 判断是否申请空间失败
        {  
            return NULL;
        }
        
        // 3、将申请的空间(顺序表管理结构体堆空间)的地址返回
        return p;
    }

    c、销毁顺序表

    一个顺序表最后不再需要,应当要释放其所占用的内存空间,这被称为顺序表的销毁。

  • 图解:
  • /**
      * @brief  销毁顺序表
      * @note   None    
      * @param  p:顺序表管理结构体指针
      * @retval None
      */ 
    void SQUENCE_LIST_UnInit(sq_list_p p)
    {
        // 1、如果顺序表本身就为NULL,就不必继续下面的内容了
        if ( p == NULL)
            return;
        
        // 2、释放内存空间(堆区)(由内到外)
        free(p->data_p);
        free(p);
    }
    

    d、判断顺序表是否满了或空了

  • 图解:
  • 示例代码:

    /**
      * @brief  判断顺序表是否数据为满
      * @note   None    
      * @param  p: 顺序表管理结构体指针
      * @retval 顺序表数据满了:返回true
      *         顺序表数据未满:返回false
      */ 
    bool SQUENCE_LIST_IfFull(sq_list_p p)
    {
        return p->last == p->capacity-1;
    }
    
    /**
      * @brief  判断顺序表是否数据为空
      * @note   None    
      * @param  p: 顺序表管理结构体指针
      * @retval 顺序表数据为空:返回true
      *         顺序表数据未空:返回false
      */ 
    bool SQUENCE_LIST_IfEmpty(sq_list_p p)
    {
        return p->last == -1;
    }

    e、向顺序表中的表头插入一个数据

  • 图解:
  • 示例代码:
  • /**
      * @brief  在顺序表中的表头插入一个数据
      * @note   None    
      * @param  p:       顺序表管理结构体指针
      *         new_data: 要插入的数据
      * @retval 成功:返回0
      *         失败:返回-1
      */ 
    int SQUENCE_LIST_InsertData(sq_list_p p, int new_data)
    {
        // 1、判断顺序表数据是否满了,满了返回-1
        if ( SQUENCE_LIST_IfFull(p))
            return -1;
        
        // 2、将原有的数据全部往后挪一位,再将数据插入
        for (int i = p->last; i >=0; i--)
        {
            p->data_p[i+1] = p->data_p[i];
        }
    
        // 3、将数据插入到表头
        p->data_p[0] = new_data;
    
        // 4、顺序表的元素下标(last)+1
        p->last++;
    
        // 5、成功返回0
        return 0;
    }
    

    f、遍历顺序表

  • 图解:
  • 示例代码:

    /**
      * @brief  遍历顺序表
      * @note   None    
      * @param  p: 顺序表管理结构体指针
      * @retval None
      */ 
    void SQUENCE_LIST_ShowList(sq_list_p p)
    {
        printf("==============顺序表里面的数据==============\n\n");
    
        for (int i = 0; i <= p->last; i++)
        {
            printf("顺序表里面的内存的数据data[%d] == %d\n", i, p->data_p[i]);
        }
    
        printf("==========================================\n\n");
    
    }

    g、将顺序表指定的数据删除

  • 图解:
  • 示例代码:
  • /**
      * @brief  将顺序表指定的数据删除
      * @note   根据下标(位置)来删除 
      * @param  p:       顺序表管理结构体指针
      *         data_pos:要删除的顺序表数据的位置
      * @retval 成功:返回0
      *         失败:返回-1
      */ 
    int SQUENCE_LIST_DelPosData(sq_list_p p, int data_pos)
    {
        // 1、如果顺序表里面没有数据,就返回-1
        if(SQUENCE_LIST_IfEmpty(p))
            return -1;
    
        // 2、根据要删除的数据的位置,将其后面的数据全部往前挪动一位即可
        for (int i = data_pos; i <= p->last; i++)
        {
            p->data_p[i] = p->data_p[i+1];
        }
        
        // 3、将下标减1
        p->last--;
    
        // 4、成功删除数据,返回0
        return 0;
    }
    

    h、修改顺序表中的数据

  • 图解:
  • 示例代码:
  • /**
      * @brief  修改顺序表中的数据
      * @note   根据数据的位置来修改数据
      * @param  p:       顺序表管理结构体指针
      *         data_pos:要修改的顺序表数据的位置
      * @retval 成功:返回0
      *         失败:返回-1
      */ 
    int SQUENCE_LIST_ChangeData(sq_list_p p, int data_pos, int new_data)
    {
        // 1、判断顺序表是否为空,且输入的数据位置不得超过下标位置
        if ( SQUENCE_LIST_IfEmpty(p) || (data_pos > p->last)) 
            return -1;
    
        // 2、根据位置,修改数据
        p->data_p[data_pos] = new_data;
    
        // 3、成功返回0
        return 0;
        
    }

    3、顺序表优缺点总结

    顺序存储中,由于逻辑关系是用物理位置来表达的,因此从上述示例代码可以很清楚看到,增删数据都非常困难,需要成片地移动数据。顺序表对数据节点的增删操作是很不友好的。

  • 优点
  • 不需要多余的信息来记录数据间的关系,存储密度高
  • 所有数据顺序存储在一片连续的内存中,支持立即访问任意一个随机数据,比如上述顺序表中中第i个节点是 p->data[i]
  • 缺点
  • 插入、删除时需要保持数据的物理位置反映其逻辑关系,一般需要成片移动数据
  • 当数据节点数量较多时,需要一整片较大的连续内存空间
  • 当数据节点数量变化剧烈时,内存的释放和分配不灵活
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Bardb

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值