数据结构顺序表

在这里插入图片描述
今天主要讲解顺序表,实现顺序表的尾插,头插,头删,还有尾删等操作,和我们之前写的通讯录的增删查改有类似的功能。接下来让我们开始我们的学习吧。
1.线性表
线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结
构,常见的线性表:顺序表、链表、栈、队列、字符串…
线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物
理上存储时,通常以数组和链式结构的形式存储

在这里插入图片描述
顺序表其实本质上和数组差不多。
2.顺序表
2.1概念及结构
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组
上完成数据的增删查改。
顺序表一般可以分为:

  1. 静态顺序表:使用定长数组存储元素。
    静态的顺序表通俗点讲就是死的,我们不能改变里面的元素,一开始是多少就是多少,不能实现我们的增删查改一些操作,所以我们写顺序表的时候基本上都是动态。
    静态顺序表的代码。
    在这里插入图片描述
typedef struct SeqList
{int arry[100];int size;
}SL

我们可以写成这样,但是如果我存储数据的个数不是100的话又要改,我们可以写成这样,在前面define一下。
在这里插入图片描述
同时我们的顺序表可能不只是int 类型的 这个时候我们就可以typedef一下,下次改的时候就方便很多。
在这里插入图片描述
但是我们说静态的顺序表存在缺陷,这个时候我们就得动态开辟空间,我们可以写一个动态顺序表。

typedef int SLDataType;
typedef struct SeqList
{SLDataType* arry;//指向顺序表开始位置int size;//个数int capacity;//空间
}SL;

这样的话我们就可以用动态开辟的方式实现了。

首先我们要初始化顺序表。

在这里插入图片描述
在这里插入图片描述
我们一开始这样写的时候,经过调试可以发现我们的s并没有初始化,在VS2022下直接会提醒你使用未初始化的变量s,这是为什么,是因为我们形参是实参的一份临时拷贝,并不能改变实参,所以我们传值不行,要传地址过去次啊可以解决。
在这里插入图片描述

#include"SeqList.h"
void SLInit(SL* ps)
{ps->arry = NULL;ps->capacity = ps->size = 0;
}
void SLtest1()
{SL s;SLInit(&s);
}int main()
{SLtest1();return 0;
}

那我们接下来初始化之后实现一个简单的尾插功能吧


void SLPushBack(SL* ps, SLDataType x)
{ps->arry[ps->size] = x;ps->size++;
}

我们一开始肯定会这样想,在末尾插入数字,那我们就在末尾找到这个位置,然后插入就行,但是这会有问题,一个原因就是如果这个数组满了,我们就不能插入,插入的化就要扩容,而我们一开始为什么要写动态顺序表的原因就是这个,除了这个原因以外,还有一个原因就是如果我们一开始放的是空指针的时候,这个是时候插入就相当于非法访问,所以我们在插入的时候要进行一下判断。那因为后面头插的时候也会遇到这样的问题,我们干脆给它写成一个函数,这样就方便我们使用。
尾插函数

void SLCheckCapacity(SL* ps)
{if (ps->capacity == ps->size){int NewCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;SLDataType* tmp = (SLDataType*)realloc(ps->arry, sizeof(SLDataType) * NewCapacity);if (tmp == NULL){printf("realloc fail\n");exit(-1);}ps->arry = tmp;ps->capacity = NewCapacity;}} 

所以我们的尾插也可以写成

void SLPushBack(SL* ps, SLDataType x)
{SLCheckCapacity(ps);ps->arry[ps->size] = x;ps->size++;
}

我们为什么取得是结构体的地址,原因还是形参只是实参的一个临时拷贝,形参改变并不会改变实参

打印顺序表的函数。

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

打印函数可以传地址也可以传值,因为打印不会改变我们的内容,我们这里写的就是传址。
实现打印函数,我们其实可以在这些前面都加上assert,做好防御,因为如果传进来的是一个空指针的话,这就会,我们是没有办法进行修改的,所以在函数进来的时候都写好断言,从根本上解决问题。

接下来我们就写一个尾删,尾删就更简单了,直接–就行了,但是我们还要考虑一个问题就是里面一开始的时候有没有数字,如果这个顺序表为空就没有必要删除了。

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

从上面顺序表的尾删和尾插来看,其实顺序表相对来说效率还是比较快的,但是头删和头插的效率并不是特别高,我们继续接着写

头插

void SLPushFront(SL* ps, SLDataType x)
{assert(ps);SLCheckCapacity(ps);int end = ps->size - 1;while (end >= 0){ps->arry[end + 1] = ps->arry[end];end--;}ps->arry[0] = x;ps->size++;}

头插的时候也要进行检查 否则空间满的话,就会越界。

头删

void SLPopFront(SL* ps)
{assert(ps);assert(ps->size > 0);int begin = 0;while (begin < ps->size-1){ps->arry[begin] = ps->arry[begin + 1];begin++;}ps->size--;
}

为什么要assert(ps->size > 0)是因为如果数都没有的话就不需要删了,所以就需要断言一下。

void SLInsert(SL* ps, int pos, SLDataType x)
{assert(ps);assert(pos >= 0 && pos <= ps->size);SLCheckCapacity(ps);int end = ps->size - 1;while (end >= pos){ps->arry[end + 1] = ps->arry[end];end--;}ps->arry[pos] = x;ps->size++;
}

写完这个其实头插就可以改成SLInsert(SL* ps, 0, SLDataType x)尾插就可以改成SLInsert(SL* ps, ps->size-1, SLDataType x)
那我们在实现一个在pos位置进行删除的代码。

void SLErase(SL* ps, int pos)
{assert(ps);assert(pos >= 0 && pos < ps->size);int begin = pos;while (begin < ps->size-1){ps->arry[begin] = ps->arry[begin + 1];begin++;}ps->size--;
}

那这样我们的每个功能基本都实现了,因为我们一开始realloc空间,所以我们现在要销毁原来的空间。

void SLDestory(SL* ps)
{if (ps->arry != NULL){free(ps->arry);ps->arry = NULL;}}

这样我们其实还可以用一个菜单来实现这写功能,和通讯录那个差不多,就设置一个菜单,这里小编就不搞了
给大家分享一下完整代码。

SeqList.h

#pragma once#include<stdio.h>
#include<stdlib.h>
#include<assert.h>//#define N 100
//typedef int SLDataType;
//typedef struct SeqList
//{
//	int arry[N];
//	int size;
//}SL;typedef int SLDataType;
typedef struct SeqList
{SLDataType* arry;//指向顺序表开始位置int size;//个数int capacity;//空间
}SL;//初始化
void SLInit(SL* ps);//尾插
void SLPushBack(SL* ps, SLDataType x);//检查空间是否够
void SLCheckCapacity(SL* ps);void SLPrint(SL* ps);void SLPopBack(SL* ps);//头插
void SLPushFront(SL* ps, SLDataType x);//头删
void SLPopFront(SL* ps);void SLInsert(SL* ps, int pos, SLDataType x);void SLErase(SL* ps, int pos);void SLDestory(SL* ps);

SeqList.c

#define _CRT_SECURE_NO_WARNINGS 1#include"SeqList.h"
void SLInit(SL* ps)
{ps->arry = NULL;ps->capacity = ps->size = 0;
}void SLCheckCapacity(SL* ps)
{assert(ps != NULL);if (ps->capacity == ps->size){int NewCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;SLDataType* tmp = (SLDataType*)realloc(ps->arry, sizeof(SLDataType) * NewCapacity);if (tmp == NULL){printf("realloc fail\n");exit(-1);}ps->arry = tmp;ps->capacity = NewCapacity;}} 
void SLPushBack(SL* ps, SLDataType x)
{assert(ps != NULL);SLCheckCapacity(ps);ps->arry[ps->size] = x;ps->size++;
}void SLPrint(SL* ps)
{assert(ps != NULL);int i = 0;for (i = 0; i < ps->size; i++){printf("%d ", ps->arry[i]);}printf("\n");
}void SLPopBack(SL* ps)
{assert(ps);assert(ps->size > 0);ps->size--;}void SLPushFront(SL* ps, SLDataType x)
{assert(ps);SLCheckCapacity(ps);int end = ps->size - 1;while (end >= 0){ps->arry[end + 1] = ps->arry[end];end--;}ps->arry[0] = x;ps->size++;}void SLPopFront(SL* ps)
{assert(ps);assert(ps->size > 0);int begin = 0;while (begin < ps->size-1){ps->arry[begin] = ps->arry[begin + 1];begin++;}ps->size--;
}void SLInsert(SL* ps, int pos, SLDataType x)
{assert(ps);assert(pos >= 0 && pos <= ps->size);SLCheckCapacity(ps);int end = ps->size - 1;while (end >= pos){ps->arry[end + 1] = ps->arry[end];end--;}ps->arry[pos] = x;ps->size++;
}void SLErase(SL* ps, int pos)
{assert(ps);assert(pos >= 0 && pos < ps->size);int begin = pos;while (begin < ps->size-1){ps->arry[begin] = ps->arry[begin + 1];begin++;}ps->size--;
}void SLDestory(SL* ps)
{if (ps->arry != NULL){free(ps->arry);ps->arry = NULL;}}

今天的分享就到这里了,我们下次再见!!!

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

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

相关文章

04-1_Qt 5.9 C++开发指南_常用界面设计组件_字符串QString

本章主要介绍Qt中的常用界面设计组件&#xff0c;因为更多的是涉及如何使用&#xff0c;因此会强调使用&#xff0c;也就是更多针对实例&#xff0c;而对于一些细节问题&#xff0c;需要参考《Qt5.9 c开发指南》进行学习。 文章目录 1. 字符串与普通转换、进制转换1.1 可视化U…

【Tomcat】Tomcat部署及优化

Tomcat 它是一个免费、开源的web应用服务器&#xff1b;基于java代码开发的软件&#xff1b;处理动态请求和基于Java代码的页面开发&#xff1b; 可以在html当中写入Java代码&#xff0c;Tomcat可以解析html页面当中的Java代码&#xff0c;执行动态请求以及动态页面 缺点&#…

springboot文件上传和下载接口的简单思路

springboot文件上传和下载的简单思路 文件上传文件下载 文件上传 在springboot中&#xff0c;上传文件只需要在接口中通过 MultipartFile 对象来获取前端传递的数据&#xff0c;然后将数据存储&#xff0c;并且返回一个对外访问路径即可。一般对于上传文件的文件名&#xff0c…

多用户微商城多端智慧生态电商系统搭建

多用户微商城多端智慧生态电商系统的搭建步骤如下&#xff1a; 系统规划&#xff1a;在搭建多用户微商城多端智慧生态电商系统之前&#xff0c;需要进行系统规划。包括确定系统的目标、功能、架构、技术选型、开发流程等方面。市场调研&#xff1a;进行市场调研&#xff0c;了…

unity 修改默认脚本

using System.Collections; using System.Collections.Generic; using UnityEngine; //***************************************** //创建人&#xff1a; xxxx //功能说明&#xff1a; //***************************************** #ROOTNAMESPACEBEGIN# public class #SCRI…

C# PDF加盖电子章

winform界面 1.选择加签pdf按钮代码实现 private void button1_Click(object sender, EventArgs e){OpenFileDialog op new OpenFileDialog();op.Filter "PDF文件(*.pdf)|*.pdf";bool flag op.ShowDialog() DialogResult.OK;if (flag){string pdfPath Path.Get…

栈和队列详解(2)

目录 一、什么是队列&#xff1f; 二、创建一个我们自己的队列 1.前置准备 1.1需要的三个文件 1.2结构体的创建和头文件的引用 2.接口的实现 2.1初始化队列 2.2入队 2.3队列元素个数和判空 2.4取队头元素和队尾元素 2.5出队 2.6摧毁队列 2.7测试接口 三、所有代码 1.…

系列七、RocketMQ如何保证顺序消费消息

一、概述 所谓顺序消费指的是可以按照消息的发送顺序来进行消费。例如一笔订单产生了3条消息&#xff0c;即下订单》减库存》增加订单&#xff0c;消费时要按照顺序消费才有意义&#xff0c;要不然就乱套了&#xff08;PS&#xff1a;你总不能订单还没下&#xff0c;就开始减库…

既然jmeter也能做接口自动化,为什么还需要pytest自己搭框架?

今天这篇文章呢&#xff0c;我会从以下几个方面来介绍&#xff1a; 1、首先介绍一下pytest框架 2、带大家安装Pytest框架 3、使用pytest框架时需要注意的点 4、pytest的运行方式 5、pytest框架中常用的插件 一、pytest框架介绍 pytest 是 python 的第三方单元测试框架&a…

springBoot整合RabbitMq实现手动确认消息

如何保证消息的可靠性投递&#xff1f; 1.保证生产者向broke可靠性投递&#xff0c;开启ack投递成功确认&#xff0c;如果失败的话进行消息补偿 /*** author yueF_L* date 2023-08-10 01:32* ConfirmCallback&#xff1a;消息只要被 RabbitMQ broker 接收到就会触发confirm方…

整理mongodb文档:collation

文章连接 整理mongodb文档:collation 看前提示 对于mongodb的collation。个人主要用的范围是在createcollection&#xff0c;以及find的时候用&#xff0c;所以本片介绍的时候也是这两个地方入手&#xff0c;对新手个人觉得理解概念就好。不要求强制性掌握&#xff0c;但是要…

07 Ubuntu中使用poetry工具管理python环境——巨详细!!!

由于conda和ros2的环境实在太容易冲突了。我真的不敢再使用conda&#xff0c;着实是有些搞不明白这解释器之间的关系。 conda的卸载和ros2的安装暂不赘述&#xff0c;下面着重来说如何在Ubuntu中使用poetry进行包管理及遇到的问题。 1 安装poetry 由于在有写入权限的限制&am…

01:STM32点灯大师和蜂鸣器

目录 一:点亮1个LED 1:连接图 2:函数介绍 3:点灯代码 二:LED闪烁 1:函数介绍 2:闪烁代码 三:LED流水灯 1:连接图 2:函数介绍 3:流水灯代码 四:蜂鸣器 1:连接图 2:蜂鸣器代码 一:点亮1个LED 1:连接图 因为IO口与LED负极相连所以IO口输出低电频,点亮LED (采用的是低…

【LeetCode】122. 买卖股票的最佳时机 II - 贪婪算法

目录 2023-8-10 10:29:32 122. 买卖股票的最佳时机 II 2023-8-10 10:29:32 没错&#xff0c;还是用双指针思想来套出来的。 感觉步骤很复杂&#xff0c;还调试了半天。 class Solution {public int maxProfit(int[] prices) {int pre 0;int last 1;int maxProfit 0;int c…

vCenter Server Appliance(VCSA )7.0 部署指南

vCenter Server Appliance&#xff08;VCSA &#xff09;7.0 部署指南 vmware 服务器 网络 vCenter Server Appliance&#xff08;VCSA &#xff09;7.0 部署指南 部署准备 1、下载VMware-VCSA-all-7.0.0-xxxx.iso文件&#xff0c;用虚拟光驱挂载或者解压运行&#xff0c;本…

Ansible的安装和配置

安装和配置 Ansible 安装所需的软件包 创建名为 /home/greg/ansible/inventory 的静态清单文件&#xff0c;以满足以下要求&#xff1a; 172.25.250.9 是 dev 主机组的成员 172.25.250.10 是 test 主机组的成员 172.25.250.11 和 172.25.250.12 是 prod 主机组的成员 172.2…

Linux系统编程之信号(上)

一、信号概念 信号就是软件中断。每当程序收到一个信号&#xff0c;都需要按指定的方法去处理。以下是UNIX系统的信号表。 其中core表示产生一个复制了该进程内存映像的core文件&#xff0c;它保存了程序现场&#xff0c;可以使用gdb来调试。 二、signal() signal()函数用于改…

nginx负载均衡的几种配置方式介绍

一.负载均衡含义简介 二.nginx负载均衡配置方式 准备三台设备&#xff1a; 2.190均衡服务器&#xff0c;2.191web服务器1&#xff0c;2.160web服务器2&#xff0c;三台设备均安装nginx&#xff0c;两台web服务器均有网页内容 1.一般轮询负载均衡 &#xff08;1&#xff09…

9.1网络通信基础

一.基础概念: 1)IP地址:描述网络上的一个设备所在的位置. 2)端口号(port):区分一个主机上不同的进程,和pid一样的作用,但两者不同. 3)协议:网络通信传输数据的含义,协议表示一种约定,这种约定可以是任意的.协议分层之后,上层不需要知道下层协议的细节,可以灵活地调整,替换某…

Docker容器监控(Cadvisor +Prometheus+Grafana)

环境部署&#xff0c;接着上一篇文章Docker容器部署&#xff08;Cadvisor InfluxDBGrafana&#xff09;开始 目录 1、先清理一下容器 2、部署Cadvisor 3、访问Cadvisor页面 4、部署Prometheus 5、准备配置 6、运行prometheus容器 7、访问prometheus页面 8、部署Grafan…