C语言数据结构之顺序表

目录

    • 1.线性表
    • 2.顺序表
      • 2.1顺序表相关概念及结构
      • 2.2增删查改等接口的实现
    • 3.数组相关例题

在这里插入图片描述

在这里插入图片描述

1.线性表

线性表(linear list)是n个具有相同特性(数据类型相同)的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串…
线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的( 在内存中的储存地址可能不是连续的,但是我们可以按它的储存顺序从顺序表的开头依次找到结尾,所以逻辑上是连续的 ) ,线性表在物理上存储时,通常以数组和链式结构的形式存储。
在这里插入图片描述

2.顺序表

2.1顺序表相关概念及结构

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

顺序表一般可以分为:
1.静态顺序表:数组的长度是确定的,不可改变。

在这里插入图片描述

2.动态顺序表:使用动态开辟的数组存储数据,数组大小是可变的。

在这里插入图片描述

2.2增删查改等接口的实现

静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的数组大小N是确定的,不能改变,N如果定大了,空间开多了浪费,N定小了,空间开少了不够用。所以现实中基本都是使用动态顺序表,根据需要改变动态分配的空间大小,可以更加灵活地储存数据,所以下面我们实现动态顺序表。

test.c

#include "SeqList.h"void menu()//功能菜单
{printf("******************************************\n");printf("**************    请选择    **************\n");printf("******  1.PushFront    2.PushBack  *******\n");printf("******  3.PopFront     4.PopBack   *******\n");printf("******  5.Insert       6.Del       *******\n");printf("******  7.Modify       8.FindSct   *******\n");printf("******  9.Print        0.Exit      *******\n");printf("******************************************\n");
}int main()
{int input = 0;int value = 0;int pos = 0;SeqList sl;Init_SeqList(&sl);do{menu();scanf("%d", &input);switch (input){case 1:printf("请输入要头插的值>:");scanf("%d", &value);Push_Front_SeqList(&sl, value);break;case 2:printf("请输入要尾插的值>:");scanf("%d", &value);Push_Back_SeqList(&sl, value);break;case 3:Pop_Front_SeqList(&sl);break;case 4:Pop_Back_SeqList(&sl);break;case 5:printf("请输入你要插入的位置和要插入的值>:");scanf("%d %d", &pos, &value);Insert_SeqList(&sl, pos, value);break;case 6:printf("请输入要删除的值>:");scanf("%d", &value);Del_SeqList(&sl, value);break;case 7:printf("请输入你要修改的位置和修改的值:>");scanf("%d %d", &pos, &value);Modify_SeqList(&sl, pos, value);break;case 8:printf("请输入你要查找的值>:");scanf("%d", &value);int ret = Find_Sct_SeqList(&sl, value);if (ret == -1)printf("找不到该值\n");elseprintf("该值的下标为%d\n", ret);break;case 9:Print_SeqList(&sl);break;case 0:printf("退出成功\n");Destroy_SeqList(&sl);}} while (input);return 0;
}

SeqList.c

#include "SeqList.h"//初始化顺序表
void Init_SeqList(SeqList* ptr)
{assert(ptr);//防止ptr为空指针,空指针不能解引用SLDataType* tmp = (SLDataType*)malloc(3 * sizeof(SLDataType));//先开3个数据的大小,不够再增if (tmp == NULL)//有可能动态数组开辟不成功{perror("Init_SeqList");exit(1);}elseptr->arr = tmp;ptr->size = 0;ptr->capacity = 3;
}//销毁顺序表
void Destroy_SeqList(SeqList* ptr)//动态申请的空间使用完之后要释放,不然会造成内存泄漏
{free(ptr->arr);ptr->arr = NULL;
}//检查数组大小
void Check_Capacity(SeqList* ptr)//数组大小不够则增容
{assert(ptr);//防止ptr为空指针,空指针不能解引用if (ptr->size == ptr->capacity){SLDataType* tmp = (SLDataType*)realloc(ptr->arr, 2 * ptr->capacity * sizeof(SLDataType));//每次增容都开辟两倍的数组大小if (tmp == NULL)//有可能动态数组开辟不成功{perror("Check_Capacity");exit(1);}elseptr->arr = tmp;ptr->capacity *= 2;//扩容后不要忘记把capacity修改}
}//寻找某个数据的下标
int Find_Sct_SeqList(SeqList* ptr, SLDataType val)
{assert(ptr);//防止ptr为空指针,空指针不能解引用for (int i = 0; i < ptr->size; i++){if (ptr->arr[i] == val){return i;//找到val返回val的下标}}return -1;//找不到则返回-1,因为-1不是下标,方便区分找没找到
}//在数据dst的前面插入数据src
void Insert_SeqList(SeqList* ptr, SLDataType dst,SLDataType src)
{assert(ptr);//防止ptr为空指针,空指针不能解引用Check_Capacity(ptr);//插入前要先检查空间够不够,不够则增容int sct = Find_Sct_SeqList(ptr, dst);if(sct == -1)//有可能要插入的值的位置是不存在的{printf("找不到该值\n");return;}for (int i = ptr->size - 1; i >= sct ; i--)//插入一个值,后面的值都要往后移动{ptr->arr[i+1] = ptr->arr[i];}ptr->arr[sct] = src;ptr->size++;//插入后不要忘了给数组大小加1
}//头插一个数据
void Push_Front_SeqList(SeqList* ptr,SLDataType val)
{assert(ptr);//防止ptr为空指针,空指针不能解引用Check_Capacity(ptr);插入前要先检查空间够不够,不够则增容for (int i = ptr->size - 1; i >= 0; i--){ptr->arr[i + 1] = ptr->arr[i];}ptr->arr[0] = val;ptr->size++;//插入后不要忘了给数组大小加1
}//尾插一个数据
void Push_Back_SeqList(SeqList* ptr,SLDataType val)
{assert(ptr);//防止ptr为空指针,空指针不能解引用Check_Capacity(ptr);//插入前要先检查空间够不够,不够则增容ptr->arr[ptr->size] = val;ptr->size++;//插入后不要忘了给数组大小加1
}//修改一个给定的数据
void Modify_SeqList(SeqList* ptr, SLDataType dst, SLDataType src)
{assert(ptr);//防止ptr为空指针,空指针不能解引用int sct = Find_Sct_SeqList(ptr, dst);if (sct == -1)//有可能要修改的值是不存在的{printf("找不到该值\n");return;}ptr->arr[sct] = src;
}//删除一个给定的数据
void Del_SeqList(SeqList* ptr, SLDataType val)
{assert(ptr);//防止ptr为空指针,空指针不能解引用int sct = Find_Sct_SeqList(ptr, val);if (sct == -1)//有可能要删除的值是不存在的{printf("找不到该值\n");return;}for (int i = sct + 1; i < ptr->size; i++){ptr->arr[i - 1] = ptr->arr[i];}ptr->size--;
}//头删一个数据
void Pop_Front_SeqList(SeqList* ptr)
{assert(ptr);//防止ptr为空指针,空指针不能解引用if (ptr->size == 0)//数组内元素个数为0时不能再删了,否则会越界访问{return;}for (int i = 1; i < ptr->size; i++){ptr->arr[i - 1] = ptr->arr[i];}ptr->size--;
}//尾删一个数据
void Pop_Back_SeqList(SeqList* ptr)
{if (ptr->size == 0)//数组内元素个数为0时不能再删了,否则会越界访问{return;}assert(ptr);ptr->size--;//数组尾删就是不访问最后一个元素,将数组大小减1就可以了
}//打印顺序表
void Print_SeqList(SeqList* ptr)
{assert(ptr);//防止ptr为空指针,空指针不能解引用for (int i = 0; i < ptr->size; i++){printf("%d ",ptr->arr[i]);}printf("\n");
}

SeqList.h

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <errno.h>typedef int SLDataType; //将数据类型重命名为SLDataType,方便修改储存的数据类型typedef struct SeqList
{SLDataType* arr; //动态开辟的数组size_t size;     //数组元素个数size_t capacity; //数组大小
}SeqList;void Init_SeqList(SeqList* ptr);void Insert_SeqList(SeqList* ptr, SLDataType dst, SLDataType src);void Push_Front_SeqList(SeqList* ptr, SLDataType val);void Push_Back_SeqList(SeqList* ptr, SLDataType val);void Modify_SeqList(SeqList* ptr, SLDataType dst, SLDataType src);void Del_SeqList(SeqList* ptr, SLDataType val);void Pop_Front_SeqList(SeqList* ptr);void Pop_Back_SeqList(SeqList* ptr);int Find_Sct_SeqList(SeqList* ptr, SLDataType val);void Print_SeqList(SeqList* ptr);void Destroy_SeqList(SeqList* ptr);

3.数组相关例题

题目1:

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

不要使用额外的数组空间,你必须仅使用 O(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],也会被视作正确答案。

参考解析:

void Swap(int* a, int* b)
{int tmp = *a;*a = *b;*b = tmp;
}// 思路:用两个存下标的front和behind都先放在0的位置,front找不是val的值与behind交换,
// 这样就相当于把等于val的值往后放,不等于val的值往前放
// 最后数组的前n个数就是我们想要的删除所有val值之后的数组int removeElement(int* nums, int numsSize, int val) 
{int front, behind;front = behind = 0;while (front < numsSize){if (nums[front] == val){front++;}else{if (front != behind)Swap(&nums[front], &nums[behind]);front++;behind++;}}return behind;//每找到一个不是val的值behind就++一次,所以behind的值就是新数组的长度
}

程序执行过程图:

在这里插入图片描述


题目2:

给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。

注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。
为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。

示例 1:

输入:nums1 = [1, 2, 3, 0, 0, 0], m = 3, nums2 = [2, 5, 6], n = 3
输出:[1, 2, 2, 3, 5, 6]
解释:需要合并[1, 2, 3] 和[2, 5, 6] 。
合并结果是[1, 2, 2, 3, 5, 6] ,其中斜体加粗标注的为 nums1 中的元素。

示例 2:

输入:nums1 = [1], m = 1, nums2 = [], n = 0
输出:[1]
解释:需要合并[1] 和[] 。
合并结果是[1] 。

参考解析:

//解题思路:
//1. 从后往前遍历数组,将nums1和nums2中的元素逐个比较
//将较大的元素往nums1末尾进行搬移
//2. 第一步结束后,nums2中可能会有数据没有搬移完,将nums2中剩余的元素逐个搬移到nums1
//
//时间复杂度:O(m + n)
//空间复杂度 : O(1)void Merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n)
{// end1、end2:分别标记nums1 和 nums2最后一个有效元素位置// end标记nums1的末尾,nums1和nums2中的元素从后往前往nums1中存放,应从end开始往前放,否则会存在数据覆盖int end1 = m - 1;int end2 = n - 1;int index = m + n - 1;// 从后往前遍历,将num1或者nums2中较大的元素往num1中end位置搬移// 直到将num1或者num2中有效元素全部搬移完while (end1 >= 0 && end2 >= 0){if (nums1[end1] > nums2[end2]){nums1[index--] = nums1[end1--];}else{nums1[index--] = nums2[end2--];}}// num2中的元素可能没有搬移完,将剩余的元素继续往nums1中搬移while (end2 >= 0){nums1[index--] = nums2[end2--];}// num1中剩余元素没有搬移完 ---不用管了,因为num1中剩余的元素本来就在num1中
}

程序执行过程图:

在这里插入图片描述

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

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

相关文章

2024年阿里云服务器明细报价整理总结

2024年阿里云服务器租用费用&#xff0c;云服务器ECS经济型e实例2核2G、3M固定带宽99元一年&#xff0c;轻量应用服务器2核2G3M带宽轻量服务器一年61元&#xff0c;ECS u1服务器2核4G5M固定带宽199元一年&#xff0c;2核4G4M带宽轻量服务器一年165元12个月&#xff0c;2核4G服务…

Zynq 7000 SoC器件的复位系统

Zynq7000 SoC器件中的复位系统包括由硬件、看门狗定时器、JTAG控制器和软件生成的复位。每个模块和系统都包括一个由复位系统驱动的复位。硬件复位由上电复位信号&#xff08;PS_POR_B&#xff09;和系统复位信号&#xff08;PS_SRST_B&#xff09;驱动。 在PS中&#xff0c;有…

JAVA基础面试题(第九篇)中! 集合与数据结构

JAVA集合和数据结构也是面试常考的点&#xff0c;内容也是比较多。 在看之前希望各位如果方便可以点赞收藏&#xff0c;给我点个关注&#xff0c;创作不易&#xff01; JAVA集合 11. HashMap 中 key 的存储索引是怎么计算的&#xff1f; 首先根据key的值计算出hashcode的值…

隧道代理的优势与劣势分析

“随着互联网的快速发展&#xff0c;网络安全已经成为一个重要的议题。为了保护个人和组织的数据&#xff0c;隧道代理技术逐渐成为网络安全的重要工具。隧道代理通过在客户端和服务器之间建立安全通道&#xff0c;加密和保护数据的传输&#xff0c;有效地防止黑客入侵和信息泄…

15-partition table (分区表)

ESP32-S3的分区表 什么是分区表&#xff1f;&#x1f914; ESP32-S3的分区表是用来确定在ESP32-S3的闪存中数据和应用程序的布局。每个ESP32-S3的闪存可以包含多个应用程序&#xff0c;以及多种不同类型的数据&#xff08;例如校准数据、文件系统数据、参数存储数据等&#x…

Scala 第一篇 基础篇

Scala 第一篇 基础篇 一、变量与常量 1、变量2、常量 二、数据类型 1、数据基本类型概览2、元组的声明与使用3、Range介绍和使用4、Option 类型的使用和设计5、类型别名 三、运算符四、程序逻辑 1、一切都是表达式2、分支语句3、循环语句 五、集合 1、List2、Set3、Map4、Arra…

MySQL高级(索引-性能分析-explain执行计划)

explain 或者 desc 命令获取 MySQL 如何执行 select 语句的信息&#xff0c;包括在 select 语句执行过程中表如何连接和连接的顺序。 -- 直接在 select 语句之前加上关键字 explain / desc explain select 字段列表 from 表名 where 条件 &#xff1b; explain select * …

电机控制专题(一)——最大转矩电流比MTPA控制

文章目录 电机控制专题(一)——最大转矩电流比MTPA控制前言理论推导仿真验证轻载1Nm重载30Nm 总结 电机控制专题(一)——最大转矩电流比MTPA控制 前言 MTPA全称为Max Torque Per Ampere&#xff0c;从字面意思就可以知道MTPA算法的目的是一个寻优最值问题&#xff0c;可以从以…

SQL Server 2022 安装及使用

SQL Server 2022 前言一、安装SQL Server 2022下载SQL Server 2022安装SQL Server 2022配置SQL Server 2022 二、安装SQL Server Management Studio下载SQL Server Management Studio安装SSMS-Setup-CHS 三、使用SQL Server 2022四、解决连接到服务器报错问题 前言 SQL Serve…

git 快问快答

我在实习的时候&#xff0c;是用本地开发&#xff0c;然后 push 到 GitHub 上&#xff0c;之后再从 Linux 服务器上拉 GitHub 代码&#xff0c;然后就可以了。一般程序是在 Linux 服务器上执行的&#xff0c;我当时使用过用 Linux 提供的命令来进行简单的性能排查。 在面试的时…

应用编程之进程(三-通信篇)

所谓进程间通信指的是系统中两个进程之间的通信&#xff0c;不同的进程都在各自的地址空间中、相互独立、隔离&#xff0c;所以它们是处在于不同的地址空间中&#xff0c;因此相互通信比较难&#xff0c;Linux 内核提供了多种进程间通信的机制。 大部分的程序是不要考虑进程间…

Microchip逆市扩张,接连收购2家公司

尽管年初传来降薪停工的消息&#xff0c;全球领先的半导体解决方案供应商Microchip并未因此停下扩张的脚步。相反&#xff0c;该公司在短短的一个月内&#xff0c;接连宣布收购两家公司&#xff0c;展现了其坚定的市场布局和前瞻的战略眼光。 4月11日&#xff0c;Microchip成功…

二进制OpenStack

二进制搭建OpenStack 1.环境准备 1.1机器的准备 主机名服务器配置操作系统IP地址controller-node4C8Gcentos7.9172.17.1.117computer-node4C8Gcentos7.9172.17.1.118 1.2网络架构 [rootcotroller-node ~]# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noque…

Java JNI调用本地方法1(调用C++方法)

一、基础概念 1、JNI&#xff08;Java Native interface&#xff09;:sun公司提供的JNI是Java平台的一个功能强大的接口&#xff0c;实现java和操作系统本地代码的相互调用功能&#xff0c;系统本地代码通常是由其他语言编写的&#xff0c;如C。 二、JNI使用步骤 1、定义一个J…

选定进行压缩的卷可能已损坏。请使用chkdsk来修复损坏问题,然后尝试再次压缩该卷

Windows Server 2008R2环境下&#xff0c;进行磁盘重新分区时&#xff0c;想要对系统盘进行“压缩卷”&#xff0c;结果报错提示“选定进行压缩的卷可能已损坏。请使用Chkdsk来修复损坏问题&#xff0c;然后尝试再次压缩该卷。”这是硬盘出现了坏道导致的&#xff0c;硬盘出错无…

中仕公考:教师编制和事业单位d类一样吗?

教师编制和事业单位D类在考试内容、专业要求、晋升途径等方面有很大的不同中仕为大家介绍一下&#xff1a; 考试内容&#xff1a;教师编的考试包括教育综合知识和学科专业知识&#xff0c;有的地区会额外考公共基础知识。事业单位D类的考试更侧重于职业能力倾向测验和综合应用…

Linux的学习之路:14、文件(1)

摘要 有一说一文件一天学不完&#xff0c;细节太多了&#xff0c;所以这里也没更新完&#xff0c;这里部分文件知识&#xff0c;然后C语言和os两种的文件操作 目录 摘要 一、文件预备 二、c文件操作 三、OS文件操作 1、系统文件I/O 2、接口介绍 四、思维导图 一、文件…

uniapp全局监听分享朋友圈或朋友

把大象装进冰箱需要几步&#xff1a; 1、创建shart.js文件 export default{data(){return {//设置默认的分享参数//如果页面不设置share&#xff0c;就触发这个默认的分享share:{title:标题,path:/pages/index/index,imageUrl:图片,desc:描述,content:内容}}},onLoad(){let ro…

若依前后端部署到一起

引用&#xff1a;https://blog.csdn.net/qq_42341853/article/details/129127553 前端改造&#xff1a; 配置打包前缀 修改router.js 编程hash模式&#xff1a; 前端打包&#xff1a;npm run build:prod 后端修改&#xff1a; 添加thymeleaf包&#xff0c;和配置文件 spri…

JAVA 项目<果园之窗>_1

这几天有空看能不能把水果店管理系统整出来&#xff0c;目标是整个网页版本的&#xff0c;以我的电脑做服务器&#xff0c;数据存在mysql中 以我目前的理解整个项目大致可分为前端部分、后端部分、数据库部分&#xff0c;也就这三个部分 目前打开并运行了一个别人的项目&#…