个人认为非常棒的学习网站:
Hello算法
代码随想录
图解算法与数据结构
小林coding
如何理解数据结构
什么是数据
对于数据的理解:
★ 数据是一种存在形式
,是蕴藏信息的物质实体
。
比如一块化石
,存储了无数碳酸钙、二氧化硅等分子的数据,而这些分子又是由无数钙、硅等原子(一种物质单元)所构成,可以由这些原子来计算出这块化石来自哪个年代。
比如一本书
,存储了由无数符号
所记录下的奇思妙想。
再比如人的思想
,也许是大脑中神经元细胞之间通过释放化学物质、传递电信号所产生的一些细胞分泌物
,也可以看作是数据。
数据本身是一种客观存在
,只有当人类为之创建出一套公认的秩序和规则才能从中挖掘出信息。比如人的语言体系,比如阿拉伯数字1234,这种抽象的概念并不是数据,而是一种社会普遍认同的规则和定义。当涉及到具体的一个人的存在,一束花的存在,才可以说,这是“1”个人,这是“1”束花,“1”这个数据才得以产生,也就是说在这个人身上蕴含着“1”个人这个数据,当看到这束花的时候,才产生这里有一束花的想法,“1”束花这个数据才在大脑中的神经元细胞中存在。
★ 所以数据
必须依托于物理实体
,通过人类社会的一种约定俗成,可以按照既定的规则从中解读出信息
。
什么是计算机中的数据
计算机中的数据:
计算机中的数据
显然也是一种物理实体
,屏幕上的每个画面
是由屏幕上led像素点的亮度(电压
)数据组成,显示的每一个字符、观看的视频数据、运行的程序代码都是存储在计算机存储器
中的物理实体,那么计算机的存储器是如何将这些信息存储下来呢?
计算机的底层:
简单来说,是借助一种叫做晶体管
的电子器件,这种电子器件在输入高电压时导通,输入低电压时不导通,由此可代表最基本的0 和 1
这两种概念,通过多种晶体管的电路组合,在0/1的基础上又可以表示与或非
这三种逻辑
操作,也就是基础门电路
,有了这些基础逻辑,就可以组合出无数功能,比如加减乘除
、条件判断
,至此,如果能通过电路电压的组合表示出数字、语言,那么就可以通过逻辑+数据
完成许多功能!比如做一个简单的贪吃蛇、俄罗斯方块这样的小游戏。
存储器如何表示数据:
因为计算机底层是由晶体管组成的,所以计算机硬件能够操作的对象只有代表0/1
这种简单的电路,要么通电,要么不通电,因此计算机只能通过这种电路的阵列
来表示信息,比如100111,111001,每一个0/1都代表了一个晶体管电路的闭合和连通,于是人们定义了一种规则
把每一个数字和字符对应到唯一
的一个二进制编码
,比如ASCII码(之后还有UTF-8、ISO-8859、GB2312等编码规则),这样在ASCII码规则下,晶体管电路开关阵列00110001就代表了数字“1”,于是通过庞大复杂的电子器件网中电路的开关,可以表示出数字、文字
,进而可以表示出图像、视频、书籍、三维模型、音乐
等等基本的数据形式,通过将对数据的逻辑操作编写为代码,于是产生了各种计算机软件
如PhotoShop、Unreal Engine等软件数据,他们全部作为晶体管电路的电压这种物理实体存储在计算机存储器中,当计算机需要查找某些信息时,就通过这些电路的编号去找到数据存放在哪一个电路中,然后取出数据进行处理。
计算机如何处理数据
计算机的运行原理:
有了存储器,就可以将一系列操作
抽象成文本描述
,再根据计算机语言抽象成一些逻辑+数据的编码
,最终计算机将这些编码翻译
为电路的开关与闭合
操作。这样只要给计算机通上电,其核心电路(CPU)按照一个固定的时钟频率工作,根据代码翻译出来的指令
,需要数据的时候就去存储器中取,并对数据进行运算,一个自动化
的机器执行流程就确定下来了。
在这个过程中,有一些专门用来存放静态数据
的存储器,无论通电还是断电,其中的数据不会消失
,比如写好的代码、用来在屏幕上显示的图像、用来播放的音频等数据,这种存储器叫做非易失性存储器
,其原理
是将晶体管电路开关所需的电荷永久性
的存储
下来,那么其所表示的信息也就固定了下来。
还有一种存储器,用来存放经常变动
的数据。其原理是将电路开关所需的电荷
存储在电容
之中,电容这种电子器件只有通电时才能保存电荷,断电后电荷会慢慢消散,所以这种存储器存储的数据在断电后会消失。这种存储器叫做易失性存储器
。
计算机的硬件结构
为了提高CPU的运行速度
,需要让CPU的电信号
能够尽快到达目标数据所在的电路
,而距离CPU最近
的硬件电路显然能够更快
与CPU进行电信号的通信
,于是在CPU周围,用来存储数据的容器一层一层往外铺开,距离最近
的读写速度最快
、空间也最小
,称为寄存器
,用来直接接入运算电路进行数学运算,次之的则是三级缓存Cache
,用来存放一些中间重要数据,避免每次从更远的存储器加载,再远一点是内存
,CPU执行的指令,也就是程序代码会存放于此,并且运行过程中依赖的数据也存放于此,最后是硬盘
,没有经过预处理-编译-汇编-链接
的代码即文本文件、各种静态数据存放在这里。
因此,计算机中的数据
就是这样以电信号
的方式一层一层
的流转到CPU中的寄存器,通过运算电路计算出的结果也以电信号的方式一层一层的流转到外围的每一层存储器中。CPU执行过程的一个基本单元
所需的数据也就是程序块会从硬盘加载到内存
中,执行完毕再从内存中擦除
。在程序执行过程中,会涉涉及到CPU频繁地去缓存、内存、硬盘中读写
数据。这就涉及到了一个问题
:CPU如何查找某个数据,将其加载到寄存器?
如何查找数据:
计算机在存储器中查找指定数据就类似人回想某些记忆
,可要在大脑的庞大神经元细胞群中找到存放指定记忆数据的区域,并不容易
。人类可能通过为记忆体建立某种联系
,比如联想、对比等方法为这些数据的存放设定了一种规则
,比如人脑中存在有很多人的记忆,可能一想到重要的人,会立马筛选出家人朋友这些人的信息,这种机制使得查找信息更加容易。
虽然人脑的记忆到底如何存储仍是个未解之谜,但计算机存储器中是将数据根据其满足的某种关系
存放在规则排列的存储单元
中,每个存储单元也是由晶体管电路组成,可以存放一个字节也就是8 Bit的信息(八个0/1),每个存储单元都有一个唯一的编号也就是地址
,通过这个地址计算机可以快速找到这块电路,由此可以简单将计算机中的数据总结为:一个地址
和一块存储实体
。
下图中为存储器的示意图,每个存储单元都为8位/1字节(1位代表了一个基本的晶体管电路,可以用来表示0和1),对于字符型数据,每个字符占用1个字节的空间即可表示,根据32位CPU进行4字节的内存对齐。
基础数据类型
不同类型的数据,所占据的存储空间也是不同的,以下是基础的数据类型及其所占据地空间大小:
1.短整型short
:2 byte 即 16 bit
作为有符号数
(最高位作为符号位)表示的范围为: −32768 ∼ 32767 (-
2
15
2^{15}
215 ~
2
15
−
1
2^{15}-1
215−1)
作为无符号数
表示的范围为:0 ~ 65535 (0 ~
2
16
−
1
2^{16}-1
216−1)
2.整型int
: 4 byte 即 32 bit
作为有符号数
表示的范围为: −2147483648 ∼ 2147483647(-
2
31
2^{31}
231 ~
2
31
−
1
2^{31}-1
231−1)
作为无符号数
表示的范围为:0 ~ 4294967295(0 ~
2
32
−
1
2^{32}-1
232−1)
3.长整型long
:
在32位CPU
下:为 4 byte 即 32 bit,因为此CPU数据总线只有32位,一次只能读取32位的数据,如果想要表示64位的数据,需要分两次取,第一次取高32位,第二次取低32位,因此使用long long 表示 8 byte / 64 bit
在64位CPU
下:long 和 long long 均表示8 byte / 64 bit ,并无差别
默认使用long的场景下我们是想要使用一个8 byte 的大小来存放数据:
作为有符号数
表示的范围为: −9223372036854775808 ∼ 9,223372036854775807(-
2
63
2^{63}
263 ~
2
63
−
1
2^{63}-1
263−1)
作为无符号数
表示的范围为:0 ~ 18446744073709551615(0 ~
2
64
−
1
2^{64}-1
264−1)
4.单精度浮点型float
: 4 byte 即 32 bit
浮点型用来表示小数,在内存中按科学计数法来存储的,浮点数的精度是由尾数的位数决定。对于小数在计算机中的存储,见下文:小林coding
表示范围:
1.175
×
1
0
−
38
1.175×10^{-38}
1.175×10−38 ~
3.403
×
1
0
38
3.403×10^{38}
3.403×1038
5.双精度浮点型double
: 8 byte 即 64 bit
表示范围:
2.225
×
1
0
−
308
2.225×10^{-308}
2.225×10−308 ~
1.798
×
1
0
308
1.798×10^{308}
1.798×10308
6.字符型char
: 1 byte 即 8 bit
根据ASCII码,将一个8位的二进制数映射到一个唯一的字符比如’0-9’、‘a-z’
7.布尔型bool
: 1 byte 即 8 bit
用来表示ture 和 false
基础数据结构
根据数据在存储器中的存放原理自然会想到一些问题:既然存储数据的基本单位为一个字节,按照存储空间的顺序依次存放,一个萝卜一个坑,万一下方的存储空间已经被存储了别的数据呢?更具体的,一句话如何存储?一张数据表格如何存储?满足某种规律的数据如何存储?又如何知道一段数据的起始与终止?这就需要为一个数据集合
指定一个规则
,来合理的在存储器中放置数据,这就是数据结构的诞生
。
因此数据结构是为了:
1.便于在存储器中快速查找
数据
2.具象化
数据集合本身满足某种的规律和关系
数据结构有哪些:
常见的数据结构有数组、链表、队列、栈、哈希表、树、图、堆,可以从逻辑结构和物理结构的角度来分类。
逻辑结构
上根据数据集合每个元素之间的排列次序可分为线性结构和非线性结构。
线性数据结构: 数组、链表、栈、队列、哈希表(有不同的实现形式),元素之间是一对一的关系
非线性数据结构: 又分为树形结构
和图状结构
①树形结构: 树、堆、哈希表,元素之间是一对多
的关系
②图状结构: 图,元素之间是多对多
的关系
物理结构
上按照数据在存储器中是否顺序存放分为连续型
和分散型
结构,连续型数据结构在存储器中占用的空间是连续的,而分散型则在空间上不连续,能够充分地利用内存碎片空间,并且对于数据的添加和删除更加高效。
连续型数据结构: 以数组
为代表,每个数据元素在存储空间
上紧密相邻
,通过地址偏移可以访问到数组中的任一个元素,也即支持随机访问
。
分散型数据结构: 以链表
为代表,每个数据元素不仅存放数据本身
,还存放了指向下个存储空间的地址
,这样的一个结构被称为节点
,而对于一个数据集和,知道了一个节点,只能访问到其指向的下一个节点,也即不支持随机访问
,必须挨个遍历节点。