数据结构之动态顺序表(含游戏菜单)

简介: 我们可以知道,静态顺序表的缺点是: 因为使用的是定长数组,所以空间给少了不够用,给多了,就会造成空间的浪费. 由此,我们引入一个新的顺序表----动态顺序表.

    一.什么是动态顺序表?

动态顺序表:使用动态开辟的数组存储,使用指针指向动态开辟的数组,可以进行扩容。可以队数组内容进行增删查改等操作。


20210709111035449 (1).png


       这里顺便提一下什么是逻辑结构和物理结构

逻辑结构: 人为想象出来的,实际并不存在.

物理结构: 实际存在,可以被观察到

二.动态顺序表的优缺点

优点:空间连续,支持随机访问。


缺点:1.中间或前面部分的插入时间复杂度是O(N),


           2.增容的代价比较大    

三.创建项目


工程文件 存放的内容
SeqList.h 函数声明,宏定义
SeqList.c 实现顺序表函数接口的定义
test.c 测试函数接口是否能实现功能

 四.接口实现

       1.定义顺序表

       为了后续我们想更改数据类型时方便,我们一般对类型进行typedef操作。


typedef int SeqlistType;
//创建结构体
typedef struct Seqlist
{
  SeqlistType* arr; //指向动态开辟的数组
  SeqlistType size; //有效个数
  SeqlistType capacity;//容量
}SL;

20210709111035449.png

    2.结构体初始化

传值:因为形参是实参的一份临时拷贝,对形参的改变并不会改变实参。所以我们应该把结构体变量的地址传过去,用结构体指针接收!为了防止传过来的是空指针,我们可以用assert进行断言!


//

void SeqlistInit(SL* ps)
{
  assert(ps);
  ps->arr = NULL;
  ps->size = 0;
  ps->capacity = 0;
}

3.打印数据

我们只需要遍历顺序表就能完成打印

void SeqlistPrint(SL* ps)
{
  assert(ps);
  int i = 0;
  for (i = 0; i < ps->size; i++)
  {
    printf("%d ", ps->arr[i]);
  }
  printf("\n");
}


/

4.顺序表增容

       我们插入数据时,应该要先检查顺序表的容量是否满了(ps->size == ps->capacity)


因为一开始我们时没有给容量的(capacity = 0),所以我们可以先给4个空间,后续不够空间了再两倍的扩容!

//检查容量
void SeqlistCheckCapacity(SL* ps)
{
  assert(ps);
  //当size == capacity时要扩容了
  int newcapacity = 0;
  if (ps->size == ps->capacity)
  {
    newcapacity = (ps->capacity == 0 ? 4 : ps->capacity * 2);
    //如果一开始容量为0,就给4个空间
    //不为0就扩为原来的2倍
    //扩容还要重新开辟空间->realloc
    SeqlistType* tmp = 
      (SeqlistType*)realloc(ps->arr, sizeof(SeqlistType) * newcapacity);
    //注意:要判断是否开辟成功
    if (tmp == NULL)
    {
      printf("扩容失败\n");
      //exit(-1);
      return;
    }
    else
    {
      ps->arr = tmp;
      ps->capacity = newcapacity;
    }
  }
}


/

5.头插数据

       头插数据:1.要先检查顺序表容量,不够则扩容


                          2.头插即为把数据放到第一个位置,那我们把数组原来的数据向后移动即可!要注意从最右边的开始移动(i = ps->size-1),否则前面的数据会把后面的数据覆盖!


                          3.插入数据后,标记有效数字的size+1;

//头插
void SeqlistPushFront(SL* ps, SeqlistType x)
{
  assert(ps);
  //注意先检查容量!!!!
  SeqlistCheckCapacity(ps);
  int i = 0;
  for (i = ps->size-1; i >=0; i--)
  {
    ps->arr[i+1] = ps->arr[i];
  }
  ps->arr[0] = x;
  ps->size++;
}

   


/

    6.尾插数据

       尾插数据:1.尾插数据也要先检查容量


                         2.在数组的位置上插入数据即:ps->size位置


                          3.插入数据,szie++;


//尾插
void SeqlistPushBack(SL* ps, SeqlistType x)
{
  assert(ps);
  //注意先检查容量!!!!
  SeqlistCheckCapacity(ps);
  ps->arr[ps->size] = x;
  ps->size++;
}


      7.头删数据

 头删数据:1.把后面的数据往前面覆盖,要注意从左边开始(i=0),否则会造成数据丢失!


                    2.删除了数据,size--


void SeqlistPopFront(SL* ps)
{
  assert(ps);
  int i = 0;
  for (i = 0; i < ps->size-1; i++)
  {
    ps->arr[i] = ps->arr[i+1];
  }
  ps->size--;
}


      8.尾删数据

      只需让有效数字-1即可,数据虽然还在数组里,但是我们以及访问不到了!

void SeqlistPopBack(SL* ps)
{
  assert(ps);
  ps->size--;
}


9.查找数据、

1查找元素是否在顺序表内,如果元素在数组中的下标.


2.如果不在,返回-1  (-1为无效坐标)


3.返回类型为int  若返回类型写成我们之前typedef的类型要注意typedef的类型是什么!

int SeqlistFind(SL* ps, SeqlistType x)
{
  assert(ps);
  //遍历查找
  for (int i = 0; i < ps->size; i++)
  {
    if (ps->arr[i] == x)
      return i;
  }
  return -1;  //-1为无效坐标
}


10.某一位置插入数据

    函数接口实现内容:给一个下标,在该下标前位置插入数据.

1.要保证位置在数组有效范围内(ps->size-1范围内)

      2.把要插入位置的数据及后面的数据向后移动,注意要从最后的数据开始移动(i=ps->size-1),否则会造成前面的数据覆盖后面的数据。

       3.最后把数据插入该位置,size++

//插入
void SeqlistInsert (SL* ps, SeqlistType pos, SeqlistType x)
{
  assert(ps);
  //要保证在有效区域内插入
  assert(pos < ps->size);
  //把pos位置及其后面的数据后移  
  // 要从最后面开始移动
  //要保证容量
  SeqlistCheckCapacity(ps);
  for (int i = ps->size-1; i >=pos;i--)
  {
    ps->arr[i+1] = ps->arr[i];
  }
  ps->arr[pos] = x;
  ps->size++;
}


11.删除某一位置

    函数接口实现内容:给一个下标,删除该位置。

    1.要保证要删除的位置的数组在数据范围内((ps->size-1范围内))

     2.把该位置后面的数据向前移动,把要删除位置的数据覆盖即可。

     3.删除掉元素->size--

//删除
void SeqlistErase(SL* ps, SeqlistType pos)
{
  assert(ps);
    assert(pos<ps->size);
  //把pos后面的东西前移动
  for (int i = pos + 1; i < ps->size; i++)
  {
    ps->arr[i-1] = ps->arr[i];
  }
  ps->size--;
}


      12.修改某一位置数据

      函数接口实现内容:给一个下标,修改该下标对应的值

              要保证该下标在数组的数据范围内(ps->size-1范围)

//更改数据
void SeqlistModify(SL* ps, SeqlistType pos, SeqlistType x)
{
  //要保证在有效数据范围内更改
  assert(pos < ps->size);
  ps->arr[pos] = x;
}


13.顺序表的元素个数

              size标识的就是顺序表的有效数字个数

 
         


/

14.销毁顺序表

释放掉动态开辟的数组即可,free和指针置空要同时使用!不然就可能造成野指针!

 
         


  精华总结:

              1. 有些童鞋理解不了size和数组下标的关系!下面请看图


20210813170637613.png


size是有效数字的个数,即数组有多少个元素。数组的下标是从0开始的,所以ps->arr[ps->size]是数组最后一个元素后面的位置。数组最后一个元素下标为ps->arr[ps->size-1]


       其他注意事项:


              !搞清楚传值还是传址问题!


传值:形参是实参的一份临时拷贝,对形参的改变并不会改变实参

       1.插入数据时要检查容量!

       2.在某个下标,修改/删/插入数据,要保证该下标在数组下标的范围内(ps->size-1)

      3.插入/删除数据后,size也要记得++ /-- !

       4.头插头删以及在某个下标位置前插入,要搞清楚从哪边元素开始移动!

当我们将全部接口实现时,我们就可以设计成一个游戏菜单了!


效果展示:

20210813171945237.png


具体游戏代码以及本文章中的所有代码都在附录!


    如果感觉本篇文章对你有所帮助,请给笔者一个小小的点赞,评论和关注吧!你们的支持就是我的动力!


相关文章
|
2月前
|
存储 C语言
【数据结构】顺序表
数据结构中的动态顺序表
35 3
【数据结构】顺序表
|
3月前
|
存储
数据结构—顺序表(如果想知道顺序表的全部基础知识点,那么只看这一篇就足够了!)
数据结构—顺序表(如果想知道顺序表的全部基础知识点,那么只看这一篇就足够了!)
|
4天前
|
存储 Java 程序员
【数据结构】初识集合&深入剖析顺序表(Arraylist)
Java集合框架主要由接口、实现类及迭代器组成,包括Collection和Map两大类。Collection涵盖List(有序、可重复)、Set(无序、不可重复),Map则由键值对构成。集合通过接口定义基本操作,具体实现由各类如ArrayList、HashSet等提供。迭代器允许遍历集合而不暴露其实现细节。List系列集合元素有序且可重复,Set系列元素无序且不可重复。集合遍历可通过迭代器、增强for循环、普通for循环及Lambda表达式实现,各有适用场景。其中ArrayList实现了动态数组功能,可根据需求自动调整大小。
26 11
|
3月前
|
存储 缓存 算法
数据结构和算法学习记录——总结顺序表和链表(双向带头循环链表)的优缺点、CPU高速缓存命中率
数据结构和算法学习记录——总结顺序表和链表(双向带头循环链表)的优缺点、CPU高速缓存命中率
39 0
|
11天前
|
存储 C语言 C++
数据结构基础详解(C语言) 顺序表:顺序表静态分配和动态分配增删改查基本操作的基本介绍及c语言代码实现
本文介绍了顺序表的定义及其在C/C++中的实现方法。顺序表通过连续存储空间实现线性表,使逻辑上相邻的元素在物理位置上也相邻。文章详细描述了静态分配与动态分配两种方式下的顺序表定义、初始化、插入、删除、查找等基本操作,并提供了具体代码示例。静态分配方式下顺序表的长度固定,而动态分配则可根据需求调整大小。此外,还总结了顺序表的优点,如随机访问效率高、存储密度大,以及缺点,如扩展不便和插入删除操作成本高等特点。
|
11天前
|
存储 算法 C语言
C语言手撕数据结构代码_顺序表_静态存储_动态存储
本文介绍了基于静态和动态存储的顺序表操作实现,涵盖创建、删除、插入、合并、求交集与差集、逆置及循环移动等常见操作。通过详细的C语言代码示例,展示了如何高效地处理顺序表数据结构的各种问题。
|
1月前
|
存储 算法
【数据结构与算法】顺序表
【数据结构与算法】顺序表
13 0
【数据结构与算法】顺序表
|
1月前
|
存储 算法
【初阶数据结构篇】顺序表和链表算法题
此题可以先找到中间节点,然后把后半部分逆置,最近前后两部分一一比对,如果节点的值全部相同,则即为回文。
|
1月前
|
存储 测试技术
【初阶数据结构篇】顺序表的实现(赋源码)
线性表(linearlist)是n个具有相同特性的数据元素的有限序列。
|
1月前
|
存储 编译器
【数据结构】顺序表(长期维护)
【数据结构】顺序表(长期维护)