【数据结构】手撕顺序表

目录

🐏一、线性表介绍

🐏二、顺序表

2.1.概念

2.2.结构可视化

(1)顺序表的静态存储

(2)顺序表的动态存储

2.3 接口实现——增删查改

(1)顺序表初始化

(2)顺序表的销毁

(3)检查和开辟空间

(4)头部插入

(5)尾部插入

(6)头部删除

(7)尾部删除

(8)查找数据

(9)非特殊情况,直接插入

(10)非特殊情况,直接删除

(11)修改数据

🐏三、总结

1.顺序表优点:

2.顺序表缺点:


🐏一、线性表介绍

         线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串...

         虽然它在逻辑上是线性结构,也就是连续的一条直线;在物理结构上不一定是连续的,通常以数组和链式结构形式存储。


🐏二、顺序表

2.1.概念

        顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。

2.2.结构可视化

(1)顺序表的静态存储

考虑静态顺序表的缺点:

       仅适用于确定存储多少数据的场景,开辟空间不够灵活。

       空间开多了浪费,开少了需频繁扩容,操作麻烦。

(2)顺序表的动态存储

2.3 接口实现——增删查改

(1)顺序表初始化

void SLInit(SL* psl)
{
       assert(psl);
       psl->a = NULL;
       psl->capacity = psl->size = 0;
}

(2)顺序表的销毁

void SLDestory(SL* psl)
{
       assert(psl);
       /*if (psl->a)
       {*/
       free(psl->a);
       psl->a = NULL;
       psl->capacity = psl->size = 0;
       //}
}

(3)检查和开辟空间

void SLCheckCapacity(SL* psl)
{
       // 检查容量
       if (psl->size == psl->capacity)
       {
              int newCapcity = psl->capacity == 0 ? 4 : psl->capacity * 2;
              SLDataType* tmp = (SLDataType*)realloc(psl->a, newCapcity *  sizeof(SLDataType));
              if (tmp == NULL)
              {
                      perror("realloc fail");
                      return;
                      //exit(-1);
              }
              psl->a = tmp;
              psl->capacity = newCapcity;
       }
}

注:以下代码块均用两种方法实现。

一种是普普通通的挪动数据,进行插入、删除(被注释//掉了)

一种是另写了SLInsert函数和SLErase函数进行插入、删除(见9、10)

(4)头部插入

void SLPushFront(SL* psl, SLDataType x)
{
       //assert(psl);
       //SLCheckCapacity(psl);
        挪动数据
       //int end = psl->size - 1;
       //while (end >= 0)
       //{
       //     psl->a[end + 1] = psl->a[end];
       //     --end;
       //}
       //psl->a[0] = x;
       //psl->size++;
       SLInsert(psl, 0, x);
}

(5)尾部插入

void SLPushBack(SL* psl, SLDataType x)
{
       /*assert(psl);
       SLCheckCapacity(psl);
       psl->a[psl->size] = x;
       psl->size++;*/
       SLInsert(psl, psl->size, x);
}

(6)头部删除

void SLPopFront(SL* psl)
{
       assert(psl);
       assert(psl->size > 0);
       /*int begin = 0;
       while (begin < psl->size - 1)
       {
              psl->a[begin] = psl->a[begin + 1];
              ++begin;
       }*/
       int begin = 1;
       while (begin < psl->size)
       {
              psl->a[begin-1] = psl->a[begin];
              ++begin;
       }
       --psl->size;//前置后置都可以
}

(7)尾部删除

void SLPopBack(SL* psl)
{
       assert(psl);
       // 温柔的检查
       /*if (psl->size == 0)
       {
           return;
       }*/
       // 暴力的检查
       assert(psl->size > 0);
       psl->size--;
}

(8)查找数据

int SLFind(SL* psl, SLDataType x)
{
       assert(psl);
       for (int i = 0; i < psl->size; i++)
       {
              if (psl->a[i] == x)
              {
                      return i;//返回的是下标
              }
       }
       return -1;
}

(9)非特殊情况,直接插入

void SLInsert(SL* psl, size_t pos, SLDataType x)
{
       assert(psl);
       assert(pos <= psl->size);//等于的时候就相当于尾插
       SLCheckCapacity(psl);
       //挪动数据
       size_t end = psl->size;//先确定一个end,如果用size_t到时候,pos为0时,end负数就会变成一个很大的数,导致进入死循环
       while (end > pos)
       {
              psl->a[end] = psl->a[end-1];
              --end;
       }
       psl->a[pos] = x;
       ++psl->size;
}

(10)非特殊情况,直接删除

void SLErase(SL* psl, size_t pos)
{
       assert(psl);
       assert(pos <= psl->size);//可以等于的原因是相当于尾插
       size_t begin = pos;
       while (begin < psl->size - 1)
       {
              psl->a[begin] = psl->a[begin + 1];
              ++begin;
       }
       psl->size--;
}

(11)修改数据

void SLModify(SL* psl, size_t pos, SLDataType x)
{
       assert(psl);
       assert(pos < psl->size);
       psl->a[pos] = x;
}

🐏三、总结

1.顺序表优点:

(1)尾插尾删效率很高

(2)随机访问(用下标访问)

(3)相比链表结构,CPU高速缓存命中率更高

2.顺序表缺点:

(1)头部和中部插入删除效率低——O(N)

(2)扩容时单次性能消耗大。一次扩多了,存在空间浪费;扩少了,频繁扩容,效率损失


🐏:如果对您有帮助的话,不要忘记一键三连👍👍👍哦,撒花

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值