《程序是怎样跑起来的》第四章
本章主要讲的是让内存化方为圆。计算机是处理数据的机器,而程序负责规定处理步骤和数据结构。本章的主题是内存,从物理上看,内存的结构其实非常简单,但通过程序的设计,我们也可以让内存变身为各种不同的数据结构来使用。内存本质上是一种名为内存芯片的装置,内存芯片分为RAM ROM等不同类型,但从外部来看,它们的基本原理是相同的。内存芯片上有很多引脚,这些引脚负责连接电源,以及输入输出地址信号、数据信号和控制信号,通过指定地址就可以对数据进行读写。
在程序语言中,数据类型代表要存储哪一类数据,以及该数据在内存上占多少空间。从物理上说,内存是以一字节为单位读写数据的,但在程序中,我们通过指定类型就可以以特定字节数为单位来读写数据。指针是一种变量,它不存储数据本身的值,而是存储数据所在的内存地址,使用指针可以读写任意地址的数据。栈和队列都是无需指定地址和下标,就可以对数组元素进行读写的结构,在需要临时保存计算机中间结果或计算机外部设备的输入输出数据时,经常会以这些方式来使用内存。栈和队列的区别在于数据的出入顺序,在对内存进行读写时,栈采用的是LIFO方式,而队列采用的是FIFO方式,事先在内存中预留栈和队列所需要的空间,并确定数据的读写顺序,就不需要指定地址和下标了。要在程序中实现栈和队列,需要先声明一个包含若干元素的数组,用来存放数据,然后编写用于读写元素的函数。当然,这些函数会在内部对下标进行管理,以便读写数据。但从使用函数的角度来说,我们就不需要考虑数组和下标了。
接下来我们来说,在链表中添加和删除元素链表的实践方式是对于数组中的每个元素,不仅保存它的值,还要额外保存其下一个元素的下标。也就是说,数据的值和下一个元素的下标合在一起,形成了数组的一个元素,这样数组的元素就像项链一样被串起来了,从而形成链表,链表的末尾元素,后面没有其他元素了。因此,下一个元素的下标可以设为一个不存在的值数据的添加和删除,才是链表真正发挥威力的地方。那我们先来看看和删除数据。假设链表的正数的第3个数据删除,此时只要将第2个数据的下一元素2修改为下一元素3,即可在一般的数组中,元素的顺序取决于下标的顺序。但在链表中,我们访问某个元素后,会根据该元素的下标信息来找到下一个元素。因此,如果第3个元素的下一个元素改成了第4个元素,从结果上就相当于删除了第3个元素。尽管从物理上看,第3个元素依然存在内存中,但从逻辑上看,它已经从链表中删除了。接下来我们来看如何向列表中添加元素。假设我们要在链表的正数的第5个位置添加一个新元素,此时首先要将新的数据存放在之前删除的第3个元素位置,然后将第4个元素的下一元素5改为下一元素2,最后将添加的元素下标设置为下一元素5。尽管新添加的元素在物理上处于第3个位置,但在逻辑上处于第5个位置。如果不使用链表而使用一般的数组,当需要删除的中间元的元素,或需要在中间添加元素时,就需要移动其后面的所有元素。其实我们可以用二叉查找树高效的查找数据。二叉查找树在链表的基础上做进一步的扩展,当向数组中添加元素时,根据其大小关系向左右两个方向分支。假设我们先在数组中存入50个数,后面存入的数如果比它大,就放在右边,比它小,就放在左边。实际的内存,当然不可能向两个方向分支,这是通过程序在逻辑上实现的。实现二叉查找树,就是让数组中的每个元素除了保存其本身的值,再额外保存两个下标就可以了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗