顺序表的实现(头插、尾插、头删、尾删、查找、删除、插入)

目录

一. 数据结构相关概念​

二、线性表 

三、顺序表概念及结构 

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--;  
}  

今天就先到这了!!!

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024上半年软考别轻易尝试!先了解这些!

最近几年&#xff0c;软件考试变得非常受欢迎&#xff01;不论你的专业、学历或工作时间如何&#xff0c;你都可以报名参加&#xff0c;而且通过考试取得证书还能用来抵扣个人所得税、评职称、帮助落户和参与招投标等等。 身边的朋友们纷纷参加软考&#xff0c;这让我也产生了…

如何为你的网站启用HTTPS

步骤一&#xff1a;获取SSL/TLS证书 选择SSL证书提供商&#xff1a; 选择一家可信赖的SSL证书提供商。对于小型网站&#xff0c;JoySSL提供的免费证书是一个不错的选择。购买或申请证书&#xff1a; 根据你的网站需求&#xff0c;购买相应类型的SSL证书。证书的类型包括单域、…

Springboot+vue的交通管理在线服务系统(有报告)。Javaee项目,springboot vue前后端分离项目

演示视频&#xff1a; Springbootvue的交通管理在线服务系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot vue前后端分离项目 项目介绍&#xff1a; 本文设计了一个基于Springbootvue的前后端分离的交通管理在线服务系统&#xff0c;采用M&#xff08;m…

VS2005环境下编译C++报错

WinGenerateKey.obj : error LNK2011: 未链接预编译对象&#xff1b;映像可能不能运行 解决&#xff1a;连接器->输入&#xff0c;添加&#xff1a;..\WinGenerateKey\Debug\stdafx.obj 或者 ..\WinGenerateKey\Release\stdafx.obj 报错&#xff1a;fatal error C1083: Can…

多门店在线预约小程序源码系统+在线预约+在线支付+到店付款 +完整的代码包 带搭建教程

互联网的普及和消费者行为的转变&#xff0c;线上预约服务逐渐成为一种新的消费模式。特别是在医疗、美容、餐饮等服务行业&#xff0c;用户预约的便利性需求尤为突出。为了满足市场的这一需求&#xff0c;我们开发了多门店在线预约小程序源码系统。该系统为各类服务行业提供了…

Pytest用例执行顺序和跳过执行详解

1.py文件的执行顺序 pytest默认按字母顺序去执行的&#xff08;小写英文--->大写英文--->0-9数字&#xff09; setup_module->setup_claas->setup_function->testcase->teardown_function->teardown_claas->teardown_module 1&#xff09;文件之间按…

react 路由v6

这里是区别&#xff1a;V5 vs V6 这里是官网&#xff1a;可以查看更多高级属性 一、基本使用&#xff1a; 1、配置文件 src/routes/index import React from "react";const Home React.lazy(() > import("../Pages/Home")); const About React.laz…

软件设计不是CRUD(9):低耦合模块设计理论——设计落地所面临的挑战

应用程序的模块化设计是我们开始接触到应用程序设计时就立即会接触的概念。本系列文章试图将模块化设计从概念到落地进行体系化的讲解。本节开始我们首先介绍应用程序设计中的模块化概念,以及落地这个概念所需要面临的一些挑战。然后本系列文章将推导这些挑战、问题的解决办法…

【GoLang】Go语言几种标准库介绍(一)

你见过哪些令你膛目结舌的代码技巧&#xff1f; 文章目录 你见过哪些令你膛目结舌的代码技巧&#xff1f;前言几种库bufio&#xff08;带缓冲的 I/O 操作&#xff09;特性示例 bytes (实现字节操作)特性示例 总结专栏集锦写在最后 前言 随着计算机科学的迅猛发展&#xff0c;编…

第十四章 集合(List)

一、集合框架体系 集合&#xff1a; &#xff08;1&#xff09;可以动态保存任意多个对象。 &#xff08;2&#xff09;提供了一系列方便的操作对象的方法&#xff1a;add、remove、set、get等。 二、Collection 1. Collection 接口常用方法 &#xff08;1&#xff09;add&a…

Pytorch,16个超强转换函数全总结!!

哈喽&#xff0c;这些天无论是社群还是私信&#xff0c;很多人希望看到更多关于深度学习基础内容&#xff0c;这篇文章想要分享的是关于pytorch的转换函数。 建议大家一定要好好看看这部分&#xff0c;在平常的使用中&#xff0c;既多又重要&#xff01;&#xff01; 当然在 P…

ros2 基础学习11-参数的定义及示例

话题、服务、动作&#xff0c;不知道这三种通信机制大家是否已经了解清楚&#xff0c;本节我们再来介绍一种ROS系统中常用的数据传输方式——参数。 类似C编程中的全局变量&#xff0c;可以便于在多个程序中共享某些数据&#xff0c;参数是ROS机器人系统中的全局字典&#xff…