顺序表的实现

目录

一. 数据结构相关概念​

二、线性表 

三、顺序表概念及结构 

3.1顺序表一般可以分为:

3.2 接口实现: 

四、基本操作实现

4.1顺序表初始化

4.2检查空间,如果满了,进行增容​编辑

4.3顺序表打印

4.4顺序表销毁

4.5顺序表尾插

4.6顺序表头插

4.7顺序表头删

4.8顺序表尾删

4.9顺序表在pos位置插入x

4.10顺序表删除pos位置的值


链表相关知识:

链表基础知识(二、双向链表头插、尾插、头删、尾删、查找、删除、插入)-CSDN博客

链表基础知识(一、单链表、头插、尾插、头删、尾删、查找、删除、插入)-CSDN博客 

一. 数据结构相关概念​

什么是数据结构​?

数据结构是由“数据”和“结构”两词组合而来。
什么是数据?常见的数值1、2、3、4.....、教务系统里保存的用户信息(姓名、性别、年龄、学历等等)、网页里肉眼可以看到的信息(文字、图片、视频等等),这些都是数据什么是结构?
当我们想要使用大量使用同一类型的数据时,通过手动定义大量的独立的变量对于程序来说,可读性非常差,我们可以借助数组这样的数据结构将大量的数据组织在一起,结构也可以理解为组织数据的方式。

概念:数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系
的数据元素的集合
。数据结构反映数据的内部构成,即数据由那部分构成,以什么方式构成,以及数据元素之间呈现的结构。
总结:
1)能够存储数据(如顺序表、链表等结构)​
2)存储的数据能够方便查找​
2、为什么需要数据结构?​

通过数据结构,能够有效将数据组织和管理在一起。按照我们的方式任意对数据进行增删改查等操
作。
最基础的数据结构:数组。

【思考】有了数组,为什么还要学习其他的数据结构?
假定数组有10个空间,已经使用了5个,向数组中插入数据步骤:​
求数组的长度,求数组的有效数据个数,向下标为数据有效个数的位置插入数据(注意:这里是
否要判断数组是否满了,满了还能继续插入吗).....​
假设数据量非常庞大,频繁的获取数组有效数据个数会影响程序执行效率。
结论:最基础的数据结构能够提供的操作已经不能完全满足复杂算法实现。
 

二、线性表 

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

线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,
线性表在物理上存储时,通常以数组和链式结构的形式存储。

三、顺序表概念及结构 

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

  • 顺序表和数组的区别

  • 顺序表的底层结构是数组,对数组的封装,实现了常用的增删改查等接口

3.1顺序表一般可以分为:

  • 静态顺序表:使用定长数组存储。

// 顺序表的静态存储
#define N 100
typedef int SLDataType;
typedef struct SeqList
{
     SLDataType array[N]; // 定长数组
     size_t size;     // 有效数据的个数 
}SeqList;

  • 动态顺序表:使用动态开辟的数组存储。

// 顺序表的动态存储
typedef struct SeqList
2.2 接口实现: 
静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大
了,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态
的分配空间大小,所以下面我们实现动态顺序表。
{
     SLDataType* array;  // 指向动态开辟的数组
     size_t size ;       // 有效数据个数
     size_t capicity ;   // 容量空间的大小
}SeqList;

3.2 接口实现: 

静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大
了,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态
的分配空间大小,所以下面我们实现动态顺序表。
 

先解释一下预处理指令

  • #pragma once:这是一个非标准的预处理指令,它告诉预处理器这个头文件只应该被包含一次。如果尝试多次包含,预处理器会忽略后续的包含。尽管它是非标准的,但许多现代编译器(如GCC和Clang)都支持它。

  • #ifndef SEQLIST_H:这是一个条件编译指令。它检查是否定义了一个名为SEQLIST_H的宏。如果没有定义(即这个头文件还没有被包含过),那么接下来的代码会被编译。

  • #define SEQLIST_H:这定义了一个名为SEQLIST_H的宏。当这个头文件首次被包含时,这个宏会被定义,从而标记这个头文件已经被包含过了。

  • #endif:这结束了之前的#ifndef条件编译块。

SeqList.h

//#pragma once
#ifndef _SEQLIST_H_
#define _SEQLIST_H_

#include<stdio.h>
#include<string.h>
#include<stdlib.h>

#include<assert.h>

//增强程序的可维护性
#define MAX_SIZE 10
typedef int SQDataType;
//静态顺序表
//问题:给少了不够用,给多了用不完浪费,不能灵活控制

//typedef struct SeqList
//{
//	SQDataType a[MAX_SIZE];
//	int size;
//}SL;


typedef struct SeqList
{
	SQDataType *a;// 指向动态开辟的数组
	int size;	 //有效的数据的个数
	int capacity;//容量
}SL;

//typedef struct SeqList SL;//定义为简写

// 基本增删查改接口
// 顺序表初始化


//增删查改等接口函数
//void SeqListInit(struct SeqList s);

//顺序表初始化
void SeqListInint(SL* ps);
// 检查空间,如果满了,进行增容
void CheckCapacity(SeqList * psl);
//顺序表打印
void SeqListPrint(SL* ps);
// 顺序表销毁
void SeqListDestory(SL* ps);
//顺序表尾插
void SeqListPushBack(SL* ps, SQDataType x);
//顺序表头插
void SeqListPushFront(SL* ps, SQDataType x);
//顺序表头删
void SeqListPopBack(SL* ps);
//顺序表尾删
void SeqListPopFront(SL* ps);

// 顺序表在pos位置插入x
void SeqListInsert(SL* ps, int pos, SQDataType x);

// 顺序表删除pos位置的值
void SeqListErase(SL* ps, int pos);

#endif

四、基本操作实现

4.1顺序表初始化

void SeqListInit(SL* ps)
{
	ps->a = NULL;
	ps->size = 0;
	ps->capacity = 0;
}

4.2检查空间,如果满了,进行增容

 这个函数的主要目的是在顺序列表满时自动扩容,以便能够继续添加元素。它首先检查列表是否已满,然后计算新的容量,并使用realloc函数尝试调整数组的大小。如果realloc失败(返回NULL),则打印错误信息并退出程序。如果成功,就更新列表的数组指针和容量。

// 函数定义,传入一个指向顺序列表(SeqList)的指针  
void SeqListCheckCapacity(SL* ps)  
{  
    // 检查顺序列表是否已满,即当前大小(size)是否等于容量(capacity)  
    if (ps->size == ps->capacity)  
    {  
        // 如果满了,计算新的容量。如果当前容量为0,则新容量为4;否则,新容量为当前容量的2倍  
        int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;  
          
        // 使用realloc函数尝试调整顺序列表的数组大小  
        // realloc可能会改变原有内存块的位置,因此需要使用一个临时指针来接收结果  
        SQDataType* tmp = (SQDataType*)realloc(ps->a, newcapacity * sizeof(SQDataType));  
          
        // 检查realloc是否成功  
        if (tmp == NULL)  
        {  
            // 如果失败,打印错误信息并退出程序  
            printf("realloc fail\n");  
            exit(-1);  
        }  
        else  
        {  
            // 如果成功,更新顺序列表的数组指针和容量  
            ps->a = tmp;  
            ps->capacity = newcapacity;  
        }  
    }  
}

4.3顺序表打印

这个函数的主要目的是遍历顺序列表,并打印出其中的每一个元素。通过循环,它会依次访问列表中的每个元素,并将其打印。

// 打印顺序列表中的所有元素  
void SeqListPrint(SL* ps)  
{  
    // 通过循环遍历顺序列表中的每一个元素  
    for (int i = 0; i < ps->size; i++)  
    {  
         
        printf("%d ", ps->a[i]);  
    }  
    // 打印一个换行符,使得每次打印列表后都会换行,输出更清晰  
    printf("\n");  
}

4.4顺序表销毁

 SeqListDestroy函数主要目的是释放顺序列表所占用的内存空间

// 销毁顺序列表的函数  
void SeqListDestroy(SL* ps)  
{  
    // 断言:确保传入的顺序列表指针ps不为空  
    assert(ps);  
  
    // 判断顺序列表的数组指针a是否不为空  
    if (ps->a != NULL)  
    {  
        // 释放数组指针a所指向的内存空间  
        free(ps->a);  
          
        // 将数组指针a设置为NULL,避免野指针  
        ps->a = NULL;  
          
        // 将顺序列表的大小设置为0,表示列表已空  
        ps->size = 0;  
          
        // 将顺序列表的容量设置为0,表示已没有分配内存空间  
        ps->capacity = 0;  
    }  
}

4.5顺序表尾插

在插入新元素之前,它们都首先检查当前的容量是否足够,如果不够则调用 SeqListCheckCapacity 函数进行扩容。尾插函数SeqListPushBack直接在末尾添加新元素

// 尾插法:在顺序列表的末尾插入一个新元素  
void SeqListPushBack(SL* ps, SQDataType x)  
{  
    // 检查当前顺序列表的容量是否足够,如果不够则进行扩容  
    SeqListCheckCapacity(ps);  
      
    // 在顺序列表的当前末尾位置插入新元素  
    ps->a[ps->size] = x;  
      
    // 更新顺序列表的大小(元素数量)  
    ps->size++;  
}  
  

4.6顺序表头插

在插入新元素之前,它们都首先检查当前的容量是否足够,如果不够则调用 SeqListCheckCapacity 函数进行扩容。头插函数SeqListPushFront将现有元素向后移动以腾出空间。

// 头插法:在顺序列表的开头插入一个新元素  
void SeqListPushFront(SL* ps, SQDataType x)  
{  
    // 检查当前顺序列表的容量是否足够,如果不够则进行扩容  
    SeqListCheckCapacity(ps);  
      
    // 初始化:设定一个变量来追踪当前需要移动的元素的位置  
    // 结束条件:当所有元素都已移动到它们的新位置时停止  
    // 迭代过程:从列表的末尾开始,将每个元素向后移动一个位置以腾出空间  
    int end = ps->size - 1; // 从列表的最后一个元素开始  
    while (end >= 0) // 当还有元素需要移动时继续循环  
    {  
        // 将当前位置的元素向后移动一个位置  
        ps->a[end + 1] = ps->a[end];  
        --end; // 移动到前一个元素  
    }  
  
    // 在顺序列表的开头(现在为空)插入新元素  
    ps->a[0] = x;  
      
    // 更新顺序列表的大小(元素数量)  
    ps->size++;  
}

4.7顺序表头删

 SeqListPopFront`函数用于删除顺序列表的第一个元素。它首先通过断言确保列表不为空,然后通过一个循环将第一个位置之后的所有元素都向前移动一个位置,从而覆盖掉第一个位置的元素,并更新列表的大小。

// 头删:删除顺序列表的第一个元素  
void SeqListPopFront(SL* ps)  
{  
    // 断言,确保顺序列表不为空,即其大小大于0  
    // 如果ps->size <= 0,则触发断言错误,终止程序  
    assert(ps->size > 0);  
      
    // 初始化一个变量start,用于从第二个元素开始遍历  
    int start = 1;  
      
    // 当start小于列表大小时,执行循环  
    // 这个循环用于将第一个位置之后的元素都向前移动一个位置,从而覆盖掉第一个位置的元素  
    while (start < ps->size)  
    {  
        // 将下一个位置的元素移动到当前位置  
        ps->a[start - 1] = ps->a[start];  
        // start向后移动一个位置,继续处理下一个元素  
        start++;  
    }  
      
    // 因为第一个元素已经被覆盖,所以不需要额外处理  
    // 更新顺序列表的大小(元素数量),因为删除了一个元素,所以大小减1  
    ps->size--;  
}

4.8顺序表尾删

 SeqListPopBack函数用于删除顺序列表的最后一个元素。它首先通过断言确保列表不为空,然后直接更新列表的大小。

// 尾删:删除顺序列表的最后一个元素  
void SeqListPopBack(SL* ps)  
{  
    // 断言,确保顺序列表不为空,即其大小大于0  
    // 如果ps->size <= 0,则触发断言错误,终止程序  
    assert(ps->size > 0);  
      
    // 可以选择将最后一个元素的值设置为0或其他默认值,以确保不留下未定义的值  
    // 但这取决于具体的应用需求,有时可能不需要这样做  
    //ps->a[ps->size - 1] = 0;  
      
    // 更新顺序列表的大小(元素数量),因为删除了一个元素,所以大小减1  
    ps->size--;  
}

4.9顺序表在pos位置插入x

 SeqListInsert函数的主要作用是在顺序列表的指定位置pos插入一个新元素x。为了达到这个目的,它首先确保插入的位置是有效的(不会超出当前列表的大小),然后检查是否需要扩容。接着,它通过一个循环将pos位置及其之后的元素都向后移动一个位置,以便为新元素腾出空间。最后,它在pos位置插入新元素,并更新列表的大小。

// 在顺序列表的指定位置插入一个元素  
void SeqListInsert(SL* ps, int pos, SQDataType x)  
{  
    // 断言,确保插入的位置不会超出当前列表的大小  
    // 如果pos >= ps->size,则触发断言错误,终止程序  
    assert(pos < ps->size);  
      
    // 检查当前顺序列表的容量是否足够,如果不够则进行扩容  
    SeqListCheckCapacity(ps);  
  
    // 初始化一个变量end,用于从列表的末尾开始遍历  
    int end = ps->size - 1;  
      
    // 当end位置大于或等于要插入的位置pos时,执行循环  
    // 这个循环用于将pos位置及其之后的元素都向后移动一个位置,为插入新元素腾出空间  
    while (end >= pos)  
    {  
        // 将当前位置的元素向后移动一个位置  
        ps->a[end + 1] = ps->a[end];  
        // end向前移动一个位置,继续处理前一个元素  
        end--;  
    }  
  
    // 在腾出的位置pos处插入新元素x  
    ps->a[pos] = x;  
      
    // 更新顺序列表的大小(元素数量)  
    ps->size++;  
}

4.10顺序表删除pos位置的值

SeqListErase函数用于删除顺序列表中指定位置的元素。它首先通过断言确保要删除的位置是有效的,然后通过一个循环将指定位置之后的所有元素都向前移动一个位置,从而覆盖掉指定位置的元素。最后,它更新列表的大小。

// 删除顺序列表中指定位置的元素  
void SeqListErase(SL* ps, int pos)  
{  
    // 断言,确保要删除的位置不会超出当前列表的大小  
    // 如果pos >= ps->size,则触发断言错误,终止程序  
    assert(pos < ps->size);  
      
    // 初始化一个变量start,用于从要删除的位置的下一个元素开始遍历  
    int start = pos + 1;  
      
    // 当start小于列表大小时,执行循环  
    // 这个循环用于将pos位置之后的元素都向前移动一个位置,覆盖掉pos位置的元素  
    while (start < ps->size)  
    {  
        // 将下一个位置的元素移动到当前位置  
        ps->a[start - 1] = ps->a[start];  
        // start向后移动一个位置,继续处理下一个元素  
        start++;  
    }  
      
    // 更新顺序列表的大小(元素数量),因为删除了一个元素,所以大小减1  
    ps->size--;  
}  

今天就先到这了!!!

看到这里了还不给博主扣个:
⛳️ 点赞☀️收藏 ⭐️ 关注!

你们的点赞就是博主更新最大的动力!
有问题可以评论或者私信呢秒回哦。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/269100.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

酷开系统千屏千面,深度探索消费者喜好

为什么大家这么喜欢用酷开系统呢&#xff1f;当然是因为它好用啊&#xff01;酷开系统基于人工智能技术&#xff0c;为消费者提供个性化的服务。它具有“千人千面”的推荐特性&#xff0c;即根据消费者的需求和喜好&#xff0c;自动生成个性化的内容推荐和界面布局。 01.更智能…

pngPackerGUI是一款免费的图集打包工具,png图片打包plist工具

pngPackerGUI是一款免费的图集打包工具&#xff0c;png图片打包plist工具 手把手教你使用pngPackerGUI_V2.0此软件是在pngpacker_V1.1软件基础之后&#xff0c;开发的界面化操作软件&#xff0c;方便不太懂命令行的小白快捷上手使用。1.下载并解压缩软件&#xff0c;得到如下目…

Python桌面开发技术 PyQt6教程专栏 一周快速上手,开发桌面应用

大家好&#xff0c;我是python222小锋老师。 近日锋哥又卷了一波课程&#xff0c;Python桌面开发技术 PyQt6教程&#xff0c;文字版视频版。一周掌握。 2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 PyQt6 Python桌面开发 视频教程(…

LeetCode刷题--- 字母大小写全排列

个人主页&#xff1a;元清加油_【C】,【C语言】,【数据结构与算法】-CSDN博客 个人专栏 力扣递归算法题 http://t.csdnimg.cn/yUl2I 【C】 http://t.csdnimg.cn/6AbpV 数据结构与算法 http://t.csdnimg.cn/hKh2l 前言&#xff1a;这个专栏主要讲述递归递归、搜索与回…

cesium实现二三维联动

记录项目中实现二三维地图联动 效果如下&#xff1a; 第一步&#xff1a;现在页面中加载二三维地图&#xff08;地图的初始化已省略&#xff09; <template><div><div><button click"show">二三维联动</button></div><div&…

css学习笔记7(浮动)

css学习笔记7&#xff08;浮动&#xff09; 六、浮动1.浮动的简介2.元素浮动后的特点3.浮动影响3.1浮动后会有哪些影响3.2浮动后会有哪些影响 4.浮动布局练习 六、浮动 1.浮动的简介 ​ 在最初&#xff0c;浮动是用来实现文字环绕图片效果的&#xff0c;现在浮动是主流的页面…

VR全景对普通人的生活有哪些好处?

许多普通人对VR全景还全然没有概念&#xff0c;这是因为VR全景虽然一直在快速发展&#xff0c;但目前为止也不过几年而已&#xff0c;但这发展的几年同样为我们普通人的生活带来了切实的改变和便利。VR全景技术为人们带来了沉浸感和真实感的体验&#xff0c;让我们感受到迥异于…

C# SqlSugar 数据库 T4模板

生成效果 模板代码 <# template debug"false" hostspecific"true" language"C#" #> <# output extension".cs" #> <# assembly name"System.Core" #> <# assembly name"System.Data" #>…

图片素材管理软件Eagle for mac提高素材整理维度

Eagle for mac是一款图片素材管理软件&#xff0c;支持藏网页图片&#xff0c;网页截屏&#xff0c;屏幕截图和标注&#xff0c;自动标签和筛选等功能&#xff0c;让你设计师方便存储需要的素材和查找&#xff0c;提供工作效率。 Eagle mac软件介绍 Eagle mac帮助你成为更好、…

小天使的小难题:新生儿疝气的关注与温馨呵护

引言&#xff1a; 新生儿疝气是一种在出生后可能出现的常见情况&#xff0c;虽然通常不会造成长期影响&#xff0c;但对于家长而言&#xff0c;了解如何正确应对新生儿疝气是至关重要的。本文将深入探讨新生儿疝气的原因、症状&#xff0c;以及家长在面对这一问题时应该采取的…

Isaac Sim urdf文件导入

本教程展示如何在 Omniverse Isaac Sim 中导入 urdf 一. 使用内置插件导入urdf 安装urdf 插件 方法是转到“window”->“Extensions” 搜索框中输入urdf, 并启用 通过转至Isaac Utils -> Workflows -> URDF Importer菜单来访问 urdf 扩展。 表格中的 1,2,3 对应着…

系列七(实战)、发送 接收单向消息(Java操作RocketMQ)

一、发送 & 接收单向消息 1.1、概述 发送单向消息&#xff0c;适用于发送方不关心或者不在意消息的发送结果&#xff0c;这种方式的吞吐量很大&#xff0c;但是存在消息丢失的风险&#xff0c;对于重要消息要慎用&#xff01;该种方式通常适用于对消息没有那么严格的场景中…

0基础学习VR全景平台篇第131篇:曝光三要素—光圈

上课&#xff01;全体起立~ 大家好&#xff0c;欢迎观看蛙色官方系列全景摄影课程&#xff01; 我们经常从电视或书刊上看到这样的照片&#xff0c;照片的主体清晰&#xff0c;前后镜朦胧虚化&#xff0c;整体看起来非常的漂亮。那这样的照片是如何拍出来的呢&#xff1f;他和…

A+CLUB管理人支持计划第十期 | 坤望基金

免责声明 本文内容仅对合格投资者开放&#xff01; 私募基金的合格投资者是指具备相应风险识别能力和风险承担能力&#xff0c;投资于单只私募基金的金额不低于100 万元且符合下列相关标准的单位和个人&#xff1a; &#xff08;一&#xff09;净资产不低于1000 万元的单位&…

第十八节TypeScript 泛型

1、简介 泛型是一种编程语言特性&#xff0c;允许在定义函数、类、接口等使用占位符来表示类型&#xff0c;而不是具体的类型。 泛型是一种在编写可重用、灵活且类型安全的代码时非常有用的功能。 使用泛型的主要目的是为了处理不特定类型的数据&#xff0c;使得代码可以适用…

公众号推荐流量玩法的3个秘密

从微信生态的流量触点来看&#xff0c;公众号链接着私聊、朋友圈、微信群、小程序、视频号、搜一搜、看一看等一切与目标用户能接触到的中转站 流量的尽头是私域。而对于大部分普通人来说&#xff0c;公众号可以作为私域的第一站。且相比个人微信号&#xff0c;其有着深度价值…

【数字电路】期末速通!

1. 数制及转换 常用的数制&#xff1a;十进制&#xff08;D&#xff09;&#xff0c;二进制&#xff08;B&#xff09;&#xff0c;八进制&#xff08;O&#xff09;&#xff0c;十六进制&#xff08;H&#xff09;。 常见的码制包括以下几种&#xff1a; 二进制码&#xff…

xposed 02 - 模块编写与构造函数Hook

本文讨论一下xposed模块编写的步骤&#xff0c;与如何hook构造函数&#xff0c;以及一些需要注意的地方。 Xposed模块编写 跟把大象放冰箱分3步一样&#xff0c;编写xposed模块只需要4步。 第一步 拷贝 XposedBridgeApi.jar 到模块工程的 libs 目录下&#xff0c;放一个 ja…

Unity 根据 数字 让 显示游戏总时长的txt直接显示该个 时间时分秒显示方法

Unity 根据 数字 让 显示游戏总时长的txt直接显示该个 时间时分秒显示方法 效果如下&#xff1a; 上代码 void Update(){int timeER int.Parse((txt_gameTimesER - Time.deltaTime).ToString("00"));Set_All_PlayTime_txtLookTime(timeER,bg.txt_LastTime); }/// &…

c 语言学习:输出阶乘的算式

c 语言学习&#xff1a;输出阶乘的算式 代码 #include "stdio.h"int fact(int num){if (num < 1){printf("1 ");return 1;} else {printf("%d x ",num);return num * fact(num-1);} }int main(){int num 10; // printf("plz inpu…