数据结构--数组(详细分析)

目录

🍉引言

🍉数组

🍈数组的特性

🍈数组的优缺点

🍍优点:

🍍缺点:

🍈数组的声明与初始化

🍈数组的常见操作

🍍 插入操作

🍍删除操作

🍍查找操作

🍅线性查找:

🍅二分查找:

🍈数组的常见问题实现

🍍反转数组

🍍数组中的最大和最小元素

🍈演示

🍍插入操作

🍍删除操作

🍍反转数组

🍉总结


🍉引言

  • 数据结构是计算机科学的基石,它们为数据的组织、管理和存储提供了不同的方法和策略。在众多数据结构中,数组和字符串是最基本且常用的两种。本教学文章将详细分析数组与字符串的特性,展示两者的示例操作与问题实现,并通过图示演示实现问题的过程。

🍉数组

🍈数组的特性

数组是一种线性数据结构,它使用连续的内存空间存储相同类型的元素。数组的主要特点如下:

  1. 固定大小:数组在声明时必须指定大小,并且在大多数编程语言中,数组的大小在其生命周期内不可改变。
  2. 随机访问:数组支持通过索引进行快速随机访问,这使得数组在查找操作中的效率很高。
  3. 相同数据类型:数组中所有元素必须是相同的数据类型,这保证了数组的内存布局的紧凑性和一致性。
  4. 低级别存储:由于数组使用连续的内存空间存储数据,它们在内存管理和访问速度方面具有优势。

🍈数组的分类

🍍基本定义

  • 数组的空间复杂度通常为 O(n),其中 n 是数组的元素个数。具体来说,如果每个元素占用的空间是固定的(比如在C语言中的 int 类型占用4个字节),那么整个数组的空间复杂度就是元素个数乘以每个元素占用的空间。

🍍静态数组 vs 动态数组

🍅静态数组
  • 静态数组在编译时确定大小,一旦分配就不能改变大小。其空间复杂度为:O(n)其中 n 是数组的长度。
🍅动态数组
  • 动态数组(如C++中的 std::vector,Java中的 ArrayList)在运行时可以调整大小。当需要扩展时,通常会以一定比例(如2倍)增加大小。因此,动态数组的空间复杂度稍微复杂一些,考虑到了扩展时的额外开销。
  • 动态数组的平均空间复杂度仍然是 O(n),但在最坏情况下,当数组需要扩展时,空间复杂度会瞬间增加到 O(2n),即需要额外的空间来存储新的元素数组。

🍍内存分配的细节

🍅连续内存分配
  • 数组元素在内存中是连续存储的,这种方式的优点是访问速度快,但缺点是需要一次性分配大块连续的内存。在内存紧张或碎片化严重的情况下,可能会导致分配失败。
🍅空间浪费
  • 由于数组在创建时必须确定大小,如果预估不准确,可能会出现空间浪费或空间不足的情况。预分配过多会导致内存浪费,预分配过少则需要重新分配更大的数组,这样不仅增加了额外的内存开销,还可能影响性能。

🍍实际示例分析

假设我们有一个包含 1000 个整数的数组 int arr[1000];

  • 每个整数占用 4 个字节。
  • 数组总共占用的空间为 1000×4=40001000×4=4000 字节,即 4 KB。

🍍 动态数组的扩展分析

假设一个动态数组在初始分配时大小为 4,存储了4个元素后需要扩展到 8:

  1. 初始状态:大小为 4,占用 4×4=164×4=16 字节。
  2. 扩展到 8:需要分配新的内存块,占用 8×4=328×4=32 字节。

在扩展过程中,原有的4个元素需要复制到新的内存块,导致在扩展的瞬间,数组占用的空间为 16+32=4816+32=48 字节。

🍍总结

  • 静态数组:空间复杂度为 O(n),其中 n 是数组长度。
  • 动态数组:平均空间复杂度为 O(n),但由于扩展过程可能导致瞬时空间复杂度达到 O(2n)。

🍈数组的优缺点

🍍优点

  • 快速访问

    • 数组提供了快速访问元素的能力。由于数组元素在内存中是连续存储的,可以通过索引直接访问任意元素,时间复杂度为 �(1)O(1)。
  • 易于遍历

    • 数组的线性结构使得遍历非常方便,可以使用简单的循环结构(如for循环)访问所有元素。
  • 内存管理

    • 数组在内存中是连续分配的,这可以提高缓存命中率,从而加快访问速度。
  • 简单性

    • 数组的数据结构和操作(如插入、删除、访问)相对简单,容易理解和实现。

🍍缺点

  • 固定大小

    • 在大多数编程语言中,数组的大小在创建时必须确定,不能动态调整。如果预估不准确,要么浪费内存,要么导致空间不足。
  • 插入和删除效率低

    • 由于数组的元素是连续存储的,在中间位置插入或删除元素需要移动大量元素,时间复杂度为 �(�)O(n),这对性能有负面影响。
  • 内存浪费

    • 如果数组大小预估过大,会浪费内存;如果预估过小,又可能导致数组溢出,需重新分配更大的数组,增加了复杂性和时间开销。
  • 类型限制

    • 数组通常只能存储相同类型的数据,这限制了数组的灵活性。如果需要存储不同类型的数据,需要使用其他数据结构(如对象或元组)。

🍈数组的声明与初始化

在C语言中,可以通过以下方式声明和初始化数组:

#include <stdio.h>int main() {// 声明一个大小为5的整数数组int arr[5];// 初始化数组int arr2[5] = {1, 2, 3, 4, 5};// 打印数组元素for(int i = 0; i < 5; i++) {printf("%d ", arr2[i]);}return 0;
}

🍈数组的常见操作

🍍 插入操作

在数组中插入元素需要将插入位置之后的所有元素向后移动一位,以腾出位置:

#include <stdio.h>void insert(int arr[], int n, int pos, int value) {for(int i = n; i > pos; i--) {arr[i] = arr[i - 1];}arr[pos] = value;
}int main() {int arr[6] = {1, 2, 3, 4, 5};int n = 5;  // 当前数组元素数量int pos = 2; // 插入位置int value = 99; // 插入值insert(arr, n, pos, value);for(int i = 0; i <= n; i++) {printf("%d ", arr[i]);}return 0;
}

🍍删除操作

删除数组中的元素需要将删除位置之后的所有元素向前移动一位:

#include <stdio.h>void delete(int arr[], int n, int pos) {for(int i = pos; i < n - 1; i++) {arr[i] = arr[i + 1];}
}int main() {int arr[5] = {1, 2, 3, 4, 5};int n = 5; // 当前数组元素数量int pos = 2; // 删除位置delete(arr, n, pos);for(int i = 0; i < n - 1; i++) {printf("%d ", arr[i]);}return 0;
}

🍍查找操作

在数组中查找元素可以通过线性查找或二分查找(如果数组有序)来实现:

🍅线性查找:
#include <stdio.h>int linearSearch(int arr[], int n, int value) {for(int i = 0; i < n; i++) {if(arr[i] == value) {return i;}}return -1;
}int main() {int arr[5] = {1, 2, 3, 4, 5};int value = 3; // 查找值int index = linearSearch(arr, 5, value);if(index != -1) {printf("Element found at index %d\n", index);} else {printf("Element not found\n");}return 0;
}
🍅二分查找:
#include <stdio.h>int binarySearch(int arr[], int left, int right, int value) {while(left <= right) {int mid = left + (right - left) / 2;if(arr[mid] == value) {return mid;}if(arr[mid] < value) {left = mid + 1;} else {right = mid - 1;}}return -1;
}int main() {int arr[5] = {1, 2, 3, 4, 5};int value = 3; // 查找值int index = binarySearch(arr, 0, 4, value);if(index != -1) {printf("Element found at index %d\n", index);} else {printf("Element not found\n");}return 0;
}

🍈数组的常见问题实现

🍍反转数组

反转数组意味着将数组中的元素顺序颠倒:

#include <stdio.h>void reverseArray(int arr[], int n) {int start = 0;int end = n - 1;while(start < end) {int temp = arr[start];arr[start] = arr[end];arr[end] = temp;start++;end--;}
}int main() {int arr[5] = {1, 2, 3, 4, 5};reverseArray(arr, 5);for(int i = 0; i < 5; i++) {printf("%d ", arr[i]);}return 0;
}

运行结果:

🍍数组中的最大和最小元素

查找数组中的最大和最小元素:

#include <stdio.h>void findMaxMin(int arr[], int n, int *max, int *min) {*max = arr[0];*min = arr[0];for(int i = 1; i < n; i++) {if(arr[i] > *max) {*max = arr[i];}if(arr[i] < *min) {*min = arr[i];}}
}int main() {int arr[5] = {1, 2, 3, 4, 5};int max, min;findMaxMin(arr, 5, &max, &min);printf("Max: %d, Min: %d\n", max, min);return 0;
}

运行结果:

🍈演示

🍍插入操作

在数组 arr = [1, 2, 3, 4, 5] 中插入值 99 到位置 2

初始数组: [1, 2, 3, 4, 5]
插入值99到位置2:
向后移动: [1, 2, 3, 3, 4, 5]
向后移动: [1, 2, 2, 3, 4, 5]
插入完成: [1, 99, 2, 3, 4, 5]

🍍删除操作

在数组 arr = [1, 2, 3, 4, 5] 中删除位置 2 的元素:

初始数组: [1, 2, 3, 4, 5]
删除位置2的元素:
向前移动: [1, 2, 4, 4, 5]
向前移动: [1, 2, 4, 5, 5]
删除完成: [1, 2, 4, 5]

🍍反转数组

将数组 arr = [1, 2, 3, 4, 5] 反转:

初始数组: [1, 2, 3, 4, 5]
反转过程:
交换位置0和4: [5, 2, 3, 4, 1]
交换位置1和3: [5, 4, 3, 2, 1]
反转完成: [5, 4, 3, 2, 1]

🍉总结

  • 数组作为一种固定大小且内存连续的线性数据结构,提供了高效的随机访问能力

 

希望这些能对刚学习算法的同学们提供些帮助哦!!!

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

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

相关文章

Touch Camera PRO 2024 Easy Mobile Desktop Camera Controller(触控相机专业版)

一个真正易于使用的移动+台式摄像机控制器,具有视角切换功能! Touch Camera PRO 是一款非常易于使用的移动+桌面相机控制器,具有透视切换功能!它在 Home Designer、Runtime Level Editor 和 Floor Map Designer 等其他插件中使用! 在桌面和移动设备上工作! 一个干…

WIireShark使用教程

文章目录 目录 文章目录 一.入门抓包示例 一.入门抓包示例 先介绍一下如何使用wireshark抓取相应网卡的流量&#xff0c;让读者可以先上手操作感受一下抓包的具体过程。 1.打开wireshark的主界面如下 2.选择需要抓包的网卡&#xff0c;鼠标左键双击&#xff0c;即可抓取该网…

Mysql常见问题总结

1、MySQL初始化报错 mysqld --initialize --usermysql --console 2024-06-02T15:52:22.645557Z 0 [System] [MY-013169] [Server] D:\installSoft\mysql-8.0.21-winx64\bin\mysqld.exe (mysqld 8.0.21) initializing of server in progress as process 8980 2024-06-02T15:52:2…

02-2.3.2_1 单链表的插入和删除

喜欢《数据结构》部分笔记的小伙伴可以订阅专栏&#xff0c;今后还会不断更新。 此外&#xff0c;《程序员必备技能》专栏和《程序员必备工具》专栏&#xff08;该专栏暂未开设&#xff09;日后会逐步更新&#xff0c; 插入 按位序插入 &#xff08;1&#xff09;带头结点 L…

量子加速超级计算简介

本文转载自&#xff1a;量子加速超级计算简介(2024年 3月 13日) By Mark Wolf https://developer.nvidia.cn/zh-cn/blog/an-introduction-to-quantum-accelerated-supercomputing/ 文章目录 一、概述二、量子计算机的构建块&#xff1a;QPU 和量子位三、量子计算硬件和算法四、…

代码随想录算法训练营第三十七 | ● 738.单调递增的数字 ● 968.监控二叉树

738.单调递增的数字 讲解链接&#xff1a;https://programmercarl.com/0738.%E5%8D%95%E8%B0%83%E9%80%92%E5%A2%9E%E7%9A%84%E6%95%B0%E5%AD%97.html class Solution { public:int monotoneIncreasingDigits(int n) {//整数转字符串&#xff0c;变为字符串访问比诸位取出数字要…

项目集成过程中的makefile记录

项目集成过程中的makefile记录 文章目录 项目集成过程中的makefile记录1.基础概念注释打印赋值方式常用变量$ 伪目标函数wildcard 多目录、文件操作 2.思路梳理**需求分析**目录结构 3.可行示例 持续更新中1.基础概念 注释 # 示例&#xff1a; # 项目名称打印 echo "H…

控制台相关

输入输出 输出 Console.WriteLine("123123");//光标空行 Console.Write("123123123123");//不空行输入 string str Console.ReadLine(); //如果在ReadKey(true)不会把输入的内容显示在控制台上 char c Console.ReadKey(true).KeyChar; Console.WriteL…

ACM实训第25天

第四套 第一道&#xff08;修改&#xff09; #include<stdio.h> #include<string.h> int cnt[10]; void count_digits(int n,int* cnt){for(int i1;i<n;i){int numi;while(num){cnt[num%10];num/10;}} } int main(){int t;scanf("%d\n",&t);whi…

力扣刷题--2553. 分割数组中数字的数位【简单】

题目描述 给你一个正整数数组 nums &#xff0c;请你返回一个数组 answer &#xff0c;你需要将 nums 中每个整数进行数位分割后&#xff0c;按照 nums 中出现的 相同顺序 放入答案数组中。 对一个整数进行数位分割&#xff0c;指的是将整数各个数位按原本出现的顺序排列成数…

名为投资实为借贷,如何处理

投资近百万参与号称“高回报、零风险”的内部商铺投资项目&#xff0c;与公司签订商铺投资合同及租赁合同。本想投资商铺收取租金&#xff0c;没想到不仅租金没拿到手&#xff0c;连本金都要不回来。 2019年底&#xff0c;原告何某&#xff08;乙方&#xff09;与被告祁东县某…

QSettings注册表 json双模式配置文件

qt QSettings 类可用来保存软件设置&#xff0c;json文件也是保存软件设置的很好的方式&#xff0e; 这里结合json文件和QSettings注册表来保存软件设置&#xff0e;区别在于json文件在软件目录&#xff0c;每次更新时会被覆盖&#xff0c;注册表中设置持久有效&#xff0c;…

14.FreeRTOS 消息缓存 Message Buffer

FreeRTOS 消息缓存&#xff08;Message Buffer&#xff09;的使用 介绍 在实时操作系统&#xff08;RTOS&#xff09;中&#xff0c;任务之间的通信是一个非常重要的方面。FreeRTOS 提供了多种机制来实现任务间通信&#xff0c;其中之一就是消息缓存&#xff08;Message Buffe…

【IC验证】一文速通多通道数据整型器(MCDF)

目录 01 README 02 MCDF设计结构 2.1 功能描述 2.2 设计结构 2.3 接口与时序 2.3.1 系统信号接口 2.3.2 通道从端接口 2.3.3 整形器接口 2.3.4 控制寄存器接口 2.3.4.1 接口时序图 2.3.4.2 各数据位信息 03 验证框图 3.1 reg_pkg 3.1.1 reg_trans 3.1.2 reg_driv…

【一刷《剑指Offer》】面试题 27:二叉搜索树与双向链表

牛客对应题目链接&#xff1a;二叉搜索树与双向链表_牛客题霸_牛客网 (nowcoder.com) 力扣对应题目链接&#xff1a;LCR 155. 将二叉搜索树转化为排序的双向链表 - 力扣&#xff08;LeetCode&#xff09; 一、《剑指 Offer》对应内容 二、分析题目 上面力扣上的这道题目和牛客…

AGM DAP-LINK 离线烧录报错信息分析

DAP-LINK 支持离线烧录。 即&#xff1a;先把要烧录的bin 烧录到DAP-LINK 中&#xff1b;然后DAP-LINK 可以脱离PC&#xff0c;上电后通过按键对目标板进行烧录。 CMSIS-DAP模式 跳线JGND断开&#xff0c;状态LED D4快闪&#xff0c;D3常亮&#xff08;串口状态&#xff09;。…

deepin开发web前端:探索、挑战与无限可能

deepin开发web前端&#xff1a;探索、挑战与无限可能 在数字化浪潮汹涌的时代&#xff0c;Web前端作为连接用户与数字世界的桥梁&#xff0c;其重要性日益凸显。而deepin作为一款优秀的开源操作系统&#xff0c;为Web前端开发者提供了广阔的舞台。本文将围绕deepin开发Web前端…

接口设计的最佳实践-下篇

大多数程序员&#xff0c;做得最多的事&#xff0c;也不过是写接口这件事而已。 今天继续总结下接口设计需要注意的点。尽量每种都给出具体的场景、案例等&#xff0c;希望大家能有所收获。 1、接口幂等 幂等性&#xff1a;是指一个操作或者一个服务&#xff0c;无论执行多少…

小程序怎样进行本地存储的读、写、删、清?

小程序进行本地存储的读、写、删、清操作&#xff0c;可以通过微信小程序提供的API来实现。这些API分为同步和异步两种类型&#xff0c;以满足不同的使用场景和需求。 同步操作 同步操作会阻塞后续的代码执行&#xff0c;直到操作完成。 写入本地缓存&#xff08;写&#xf…

Vue3 - Mac系统用文本编辑写html不显示效果的坑

平时在win系统下&#xff0c;可以直接对文本进行编辑&#xff0c;非常的舒服。 在mac系统中&#xff0c;也有类似的功能&#xff0c;就是文本编辑&#xff0c;没想到居然还有坑。 这是我mac系统中创建的html文件&#xff0c;想着没有几行代码&#xff0c;就没有开编辑器了&am…