C语言数据结构之线性表-顺序表篇

星光不负赶路人

江河眷顾奋楫者



🎥烟雨长虹,孤鹜齐飞的个人主页

🔥个人专栏

期待小伙伴们的支持与关注!!!


线性表的简介#

线性表(linearlist):是n个具有相同特性的数据元素的有限序列。线性表是⼀种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串。 线性表在逻辑上是线性结构,也就说是连续的⼀条直线。但是在物理结构上并不⼀定是连续的, 线性表在物理上存储时,通常以数组和链式结构的形式存储。


目录

线性表的简介#

顺序表的概念与结构

概念#

结构#

 顺序表的接口实现

定义顺序表的结构体#

初始化和动态内存的开辟#

顺序表的头插尾插 

顺序表的尾插#

顺序表的头插#

顺序表的头删尾删 

 顺序表的尾删#

顺序表的头删#

顺序表的指定插入删除 

顺序表的指定插入#

顺序表的指定删除#

顺序表在解题中的运用 

移除元素

顺序表的概念与结构

概念#

顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构

一般情况下采用数组存储,在数组上完成数据的增删查改

日常生活中我们的手机通讯录、聊天软件界面就是通过顺序表实现的


结构#

<1>静态顺序表:使用定长数组存储元素

静态顺序表一旦空间不够用了还需要手动调节,很不方便

<2>动态顺序表:使用动态开辟的数组存储元素

动态顺序表可以通过realloc来调节空间的大小,无需手动

静态顺序表和动态顺序表的优劣:

静态顺序表#

给定数组的长度

优点:

<1>创建空间时为静态开辟,不用malloc函数,代码相对简单

缺点:

<1>若空间了,会导致后续的数据存储失败

<2>若空间了,会导致空间的大量浪费


动态顺序表#

动态开辟的数组存储元素

优点:

<1>动态开辟空间,使用相对灵活,相比于静态开辟空间也可以减少空间浪费

缺点:

<1>因为要用到malloc开辟内存,代码相对复杂


由于静态顺序表实用价值极低,实现思路上不如动态顺序表

且会实现动态顺序表的话实现静态顺序表也没有太大的问题

因此在这里只给大家详细讲解一下动态顺序表的实现

 顺序表的接口实现

今天我将带领大家去学习顺序表的动态实现:

<1>从头部插入数据

<2>从尾部插入数据

<3>从头部删除数据

<4>从尾部删除数据

<5>从指定位置插入数据

<6>从指定位置删除数据


现在到了我们写代码的环节啦

我们依然是像这种代码量多的项目最好分模块写代码

定义顺序表的结构体#

#include<stdio.h> //标准的输入输出
#include<stdlib.h>//开辟动态空间的
#include<assert.h>//断言typedef int SLDataType; //对变量类型的重命名typedef struct SeqList
{SLDataType* str;   //指向开辟的动态空间int capacity;      //记录当前顺序表的空间大小int size;          //记录当前顺序表的元素个数
}SL;                   //对结构体的重命名

我们使用 typedef 的好处就是减少类型需求的变化带来修改上的麻烦

初始化和动态内存的开辟#

void SLInit(SL* h);         //初始化
void SLCheckCapacity(SL* h);//动态内存开辟
void SLInit(SL* h)
{h->str = NULL;h->capacity = h->size = 0;
}void SLCheckCapacity(SL* h)
{if (h->size == h->capacity){//三目运算符判断顺序表的扩容//如果空间大小为0就开4个SLDataType类型的空间//若不够则扩大原来的二倍int newCapacity = h->capacity = 0 ? 4 : 2 * h->capacity;SLDataType* tmp = (SLDataType*)malloc(h->str, newCapacity * sizeof(SLDataType));//断言防止开辟失败assert(tmp);h->str = tmp;h->capacity = newCapacity;}
}

可能有小伙伴不理解为啥 void SLInit(SL* h) 传的是指针

我们来看

因为现在是传值调用:形参是实参的拷贝,出了函数就会被销毁

而我们为了修改实参的数据应该选用传址调用-指针

顺序表的头插尾插 

顺序表的尾插#

对于表尾插入元素,需要先判断表是否已满,如果未满,则将元素插入表尾

void SLPushBack(SL* h, SLDataType x)
{//判断是否扩容SLCheckCapacity(h);//空间足够,直接插入h->str[h->size++] = x;
}

在用我们的SLPrint()函数将尾插结果测试一下

void SLPrint(SL* h)
{//遍历顺序表for (int i = 0; i < h->size; i++){printf("%d ", h->str[i]);}printf("\n");
}

这样我们的尾插就完成啦


顺序表的头插#

对于头插入元素,需要先将首位置及其之后的元素后移,然后再将要插入的元素放入头部

void SLPushFront(SL* h,SLDataType x)
{//判断是否扩容SLCheckCapacity(h);//原顺序表中的元素全部往后挪动for (int i = h->size; i > 0; i--){h->str[i] = h->str[i - 1];}//将待插入元素放在首位h->str[0] = x;//元素个数加一h->size++;
}

这样我们的头插也就完成啦

顺序表的头删尾删 

 顺序表的尾删#

对于删除表尾元素,直接将表中的元素个数减一即可

void PopBack(SL* h)
{//判断顺序表是否为空assert(h);assert(h->size);//顺序表不为空//减掉元素个数h->size--;
}

我们发现末尾的三个元素被删除了,这样我们的尾删接口也就完成啦


顺序表的头删#

对于删除表中首元素,需要将首位置之后的元素前移,最后将表中的元素个数减一

void PopFront(SL* h)
{assert(h);assert(h->size);//用后面的元素覆盖前一个元素for (int i = 0; i < h->size - 1; i++){h->str[i] = h->str[i + 1];}h->size--;
}

这样我们的头删也就完成啦!!!是不是难不倒你呢?

顺序表的指定插入删除 

顺序表的指定插入#

以下是将元素6插入指定位置3的图片模拟

对于在表中任意位置插入元素,需要先将插入位置及其之后的元素后移,然后再将要插入的元素放入合适的位置

void SLInsert(SL* h, int pos, SLDataType x)
{//判断动态内存是否开辟成功assert(h);//规定pos的范围区间assert(pos>=0&&pos<=h->size);SLCheckCapacity(h);//pos之后的数据全部往后挪动一位,pos空出来for (int i = h->size; i > pos; i--){h->str[i] = h->str[i - 1];}h->str[pos] = x;h->size++;
}

我们发现7和0以及10已经插入了我们指定的位置啦

顺序表的指定删除#

以下是删除指定位置3的图片模拟

对于删除表中任意元素,需要先找到要删除的元素的位置,然后将该位置之后的元素前移,最后将表中的元素个数减一

void PopErase(SL* h, int pos)
{//判断动态内存是否开辟成功assert(h);assert(pos >= 0 && pos <= h->size);//pos后面的数从后往前移动for (int i = pos; i < h->size-1; i++){h->str[i] = h->str[i + 1];}h->size--;
}

我们发现0和1以及2已经在我们指定的位置删除啦

顺序表的动态内存销毁 

void SeqListFree(SL* h)
{free(h->str); //释放动态申请的内存空间h->str = NULL;//置空指针h->size = 0;h->capacity = 0;
}

为了避免发生程序的内存泄露问题,在不使用空间的时候记得释放哦

 以下是全部代码的实现:

#pragma once
#include<stdio.h> 
#include<stdlib.h>
#include<assert.h>typedef int SLDataType;typedef struct SeqList
{SLDataType* str;   int capacity;      int size;          
}SL;                  void SLInit(SL* h);         
void SLCheckCapacity(SL* h);
void SLPrint(SL* h);
void SLPushBack(SL* h, SLDataType x);
void SLPushFront(SL* h, SLDataType x);
void PopBack(SL* h);
void PopFront(SL* h);
void SLInsert(SL* h, int pos, SLDataType x);
void PopErase(SL* h, int pos);
void SeqListFree(SL* h);void SLInit(SL* h)
{h->str = NULL;h->capacity = h->size = 0;
}void SLCheckCapacity(SL* h)
{if (h->size == h->capacity){int newCapacity = h->capacity = 0 ? 4 : 2 * h->capacity;SLDataType* tmp = (SLDataType*)malloc(h->str, newCapacity * sizeof(SLDataType));assert(tmp);h->str = tmp;h->capacity = newCapacity;}
}void SLPrint(SL* h)
{for (int i = 0; i < h->size; i++){printf("%d ", h->str[i]);}printf("\n");
}void SLPushBack(SL* h, SLDataType x)
{SLCheckCapacity(h);h->str[h->size++] = x;
}void SLPushFront(SL* h,SLDataType x)
{SLCheckCapacity(h);for (int i = h->size; i > 0; i--){h->str[i] = h->str[i - 1];}h->str[0] = x;h->size++;
}void PopBack(SL* h)
{assert(h);assert(h->size);h->size--;
}void PopFront(SL* h)
{assert(h);assert(h->size);for (int i = 0; i < h->size - 1; i++){h->str[i] = h->str[i + 1];}h->size--;
}void SLInsert(SL* h, int pos, SLDataType x)
{assert(h);assert(pos>=0&&pos<=h->size);SLCheckCapacity(h);for (int i = h->size; i > pos; i--){h->str[i] = h->str[i - 1];}h->str[pos] = x;h->size++;
}void PopErase(SL* h, int pos)
{assert(h);assert(pos >= 0 && pos <= h->size);for (int i = pos; i < h->size-1; i++){h->str[i] = h->str[i + 1];}h->size--;
}void SeqListFree(SL* h)
{free(h->str); h->str = NULL;h->size = 0;h->capacity = 0;
}void CeShi()
{SL s1;SLInit(&s1);
}int main(void)
{CeShi();system("pause");
}

顺序表在解题中的运用 

移除元素

题目链接:移除元素


题目描述#

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

说明#

为什么返回数值是整数,但输出的答案是数组呢?

请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。

你可以想象内部操作如下:

// nums 是以“引用”方式传递的。也就是说,不对实参作任何拷贝
int len = removeElement(nums, val);// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。
for (int i = 0; i < len; i++) {print(nums[i]);
}

示例 1:

输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2]
解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。

示例 2:

输入:nums = [0,1,2,2,3,0,4,2], val = 2
输出:5, nums = [0,1,3,0,4]
解释:函数应该返回新的长度 5并且 nums 中的前五个元素为 0 1 3 0 4注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。

提示:

  • 0 <= nums.length <= 100
  • 0 <= nums[i] <= 50
  • 0 <= val <= 100

思路:

<1>定义两个快慢指针,都指向开头

<2>如果没有遇到val两个指针就一起走,并且left将当前的值给right指针

<3>遇到val时,left先去寻找共同的目标(不是val的数)并把它给right

<4>这样返回right就是移除后的新长度


class Solution 
{
public:int removeElement(vector<int>& nums, int val) {int left = 0;int right = 0;int n = nums.size();//计算数组大小while(left<n){if(nums[left] !=  val){nums[right++] = nums[left++];}else{left++;}}return right;}
};

总结: 

<1>编写代码量大的项目,要学会模块写

<2>动态内存在不适使用的情况下,记得销毁,避免内存泄露

<3>顺序表的本质就是数组,只不过增加了增删查改的功能

<4>在静态分配时,由于数组的大小和空间是固定的,一旦空间占满,就无法再新增数据,否则会导致数据溢出

<5>在动态分配时,存储数组的空间在程序执行过程中会动态调整大小,当空间占满时,可以另行开辟更大的存储空间来储存数据

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

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

相关文章

css实现动态水波纹效果

效果如下&#xff1a; 外层容器 (shop_wrap)&#xff1a; 设置外边距 (padding) 提供一些间距和边距 圆形容器 (TheCircle)&#xff1a; 使用相对定位 (position: relative)&#xff0c;宽度和高度均为 180px&#xff0c;形成一个圆形按钮圆角半径 (border-radius) 设置为 50%&…

面试题 05.06. 整数转换(力扣)(OJ题)

题目链接&#xff1a;面试题 05.06. 整数转换 - 力扣&#xff08;LeetCode&#xff09; 所属专栏&#xff1a;刷题 整数转换。编写一个函数&#xff0c;确定需要改变几个位才能将整数A转成整数B。 示例1: 输入&#xff1a;A 29 &#xff08;或者0b11101&#xff09;, B 15…

5-微信小程序语法参考

1. 数据绑定 官网传送门 WXML 中的动态数据均来自对应 Page 的 data。 数据绑定使用 Mustache 语法&#xff08;双大括号&#xff09;将变量包起来 ts Page({data: {info: hello wechart!,msgList: [{ msg: hello }, { msg: wechart }]}, })WXML <view class"vie…

搜索与图论第四期 树与图的广度优先遍历(例题)

例题&#xff1a;快速排序模板&#xff1a; AC代码&#xff1a; 源码&#xff1a; #include <iostream> using namespace std; const int N 1e6 10; int n; int q[N];void quick_sort(int q[], int l, int r) {if (l > r)return ;int x q[l], i l - 1, j r 1…

经典目标检测YOLO系列(二)YOLOV2的复现(1)总体网络架构及前向推理过程

经典目标检测YOLO系列(二)YOLOV2的复现(1)总体网络架构及前向推理过程 和之前实现的YOLOv1一样&#xff0c;根据《YOLO目标检测》(ISBN:9787115627094)一书&#xff0c;在不脱离YOLOv2的大部分核心理念的前提下&#xff0c;重构一款较新的YOLOv2检测器&#xff0c;来对YOLOV2有…

压力测试+接口测试(工具jmeter)

jmeter是apache公司基于java开发的一款开源压力测试工具&#xff0c;体积小&#xff0c;功能全&#xff0c;使用方便&#xff0c;是一个比较轻量级的测试工具&#xff0c;使用起来非常简单。因 为jmeter是java开发的&#xff0c;所以运行的时候必须先要安装jdk才可以。jmeter是…

【论文阅读】Deep Graph Contrastive Representation Learning

目录 0、基本信息1、研究动机2、创新点3、方法论3.1、整体框架及算法流程3.2、Corruption函数的具体实现3.2.1、删除边&#xff08;RE&#xff09;3.2.2、特征掩盖&#xff08;MF&#xff09; 3.3、[编码器](https://blog.csdn.net/qq_44426403/article/details/135443921)的设…

借用GitHub将typora图片文件快速上传CSDN

前情概要 众所周知&#xff0c;程序员大佬们喜欢用typora软件写代码笔记&#xff0c;写了很多笔记想要放到CSDN上给其他大佬分享&#xff0c;但是在往csdn上搬运的时候&#xff0c;图片总是上传出错&#xff0c;一张一张搞有很麻烦&#xff0c;咋如何搞&#xff1f; 废话不多…

muduo网络库剖析——监听者EpollPoller类

muduo网络库剖析——监听者EpollPoller类 前情从muduo到my_muduo 概要epoll原理解析epoll提供的接口epoll的触发模式epoll实现多路复用 框架与细节成员函数使用方法 源码结尾 前情 从muduo到my_muduo 作为一个宏大的、功能健全的muduo库&#xff0c;考虑的肯定是众多情况是否…

SpringBoot 更新业务场景下,如何区分null是清空属性值 还是null为vo属性默认值?

先看歧义现象 值为null 未传递此属性 所以此时如何区分null 时传递进来的的null&#xff0c;还是属性的默认值null? 引入方案 引入过滤器&#xff0c;中间截获requestBodyData并保存到HttpServletRequest&#xff0c;业务层从HttpServletRequest 获取到requestBodyData辅…

LaTeX 多栏文档 Multiple columns如何插入图片并修改样式

在今天写报告的时候用到了 latex 的多栏列表&#xff0c;插入图片的时候感觉很无助 如果不喜欢让Latex自动安排图片位置&#xff0c;可以使用float包&#xff0c;然后可以使用\begin{figure}[H]。 记得提前导入这个包 \usepackage{float} 为了让我的图片的caption居中&#xf…

市面上常见硬盘分析及对比

固态硬盘 vs. 机械硬盘对比&#xff1a; 工作原理&#xff1a; 固态硬盘(SSD)&#xff1a; 使用非易失性存储器&#xff08;NAND闪存&#xff09;来存储数据&#xff0c;通过电子方式读写。机械硬盘(HDD)&#xff1a; 使用旋转的磁盘片和移动的磁头进行数据读写&#xff0c;依赖…

django电影推荐系统

电影推荐 启动 ./bin/pycharm.shdjango-admin startproject movie_recommendation_projectcd movie_recommendation_project/python manage.py movie_recommendation_apppython manage.py startapp movle_recommendation_applspython manage.py runserver Using the URLconf d…

Python多线程爬虫——数据分析项目实现详解

前言 「作者主页」&#xff1a;雪碧有白泡泡 「个人网站」&#xff1a;雪碧的个人网站 ChatGPT体验地址 文章目录 前言爬虫获取cookie网站爬取与启动CSDN爬虫爬虫启动将爬取内容存到文件中 多线程爬虫选择要爬取的用户 线程池 爬虫 爬虫是指一种自动化程序&#xff0c;能够模…

Kylin 安装novnc 远程访问

noVNC可以使用浏览器直接访问服务器&#xff0c;而不需要使用VNC客户端。 1.初始环境 关闭防火墙或允许IP访问本机 2.安装依赖 dnf install -y tigervnc-server git 3.git下载novnc git clone https://github.com/novnc/noVNC.git 4.配置信任证书 openssl req -new -x509 …

RabbitMQ使用篇

☆* o(≧▽≦)o *☆嗨~我是小奥&#x1f379; &#x1f4c4;&#x1f4c4;&#x1f4c4;个人博客&#xff1a;小奥的博客 &#x1f4c4;&#x1f4c4;&#x1f4c4;CSDN&#xff1a;个人CSDN &#x1f4d9;&#x1f4d9;&#x1f4d9;Github&#xff1a;传送门 &#x1f4c5;&a…

USB转SPI USB转IIC 串口转SPI串口转IIC SPI I2C模块

一款支持USB转SPI、USB转I2C、USB转GPIO、USB转PWM、USB转ADC的模块。提供上位机工具&#xff0c;开发协议。 资料下载&#xff0c;链接&#xff1a;https://pan.baidu.com/s/1sw3RCMwjhrMO4qzUBq9bjA 提取码&#xff1a;qzjp 概述 串口转多协议模组为了客户调试一些功能…

PICO Developer Center 创建和调试 ADB 命令

PICO 开发者中心概览 ADB 是一个轻量级的 Android 调试桥(Android Debug Bridge&#xff0c;简称 ADB)&#xff0c;用于与 Android 设备进行通信和调试。ADB提供了许多有用的功能&#xff0c;使开发人员能够轻松地管理和调试设备上的应用程序。 你可以使用 PDC 工具来调试系统…

阿里云服务器4核8G配置收费标准及新老用户优惠价格整理

阿里云服务器4核8g配置云服务器u1价格是955.58元一年&#xff0c;4核8G配置还可以选择ECS计算型c7实例、计算型c8i实例、计算平衡增强型c6e、ECS经济型e实例、AMD计算型c8a等机型等ECS实例规格&#xff0c;规格不同性能不同&#xff0c;价格也不同&#xff0c;阿里云服务器网al…

使用 vsCode创建GO项目

最近回顾了一下go的使用&#xff1a;具体操作看下面的参考连接&#xff0c;下面只描述一些踩过的坑&#xff1a; 1. go安装配置 安装go->配置go环境变量 推荐官网下载&#xff0c;速度很快&#xff1b; 这里需要配置五个参数&#xff1a;GOPATH/GOROOT/Path、GO111MODULE/…