1. 内存
- 计算机的作用
用来存储和运算二进制的数据
- 问题:计算机如何计算1+2?
将1和2的二进制劣行的数据加载到计算机的内存中(当有额外的内存时才能加载成功),然后使用寄存器进行数值运算。
- 变量
变量是内存空间的地址。(不严谨的说法变量就是某一块内存空间)
内存空间有两个默认的属性:
(1)内存空间的大小:
-bit(位),一个bit大小的内存空间只能存放一位二进制的数;
-byte(字节),8bit;
-kb,1024byte。
(2)内存空间的地址:
-使用一个16进制的数值表示,
-作用:用来让cpu来寻址
由此可知,将一个值赋给变量,该值加载到内存中,所以说变量是某一块内存空间,但是实则变量是内存空间的地址。
-
形象话理解内存(内存的大小和地址)
-
理解a=10使的内存图(引用,指向)
-引用:引用就是变量==>内存空间的地址
-a=10:a变量/引用/内存空间地址
-指向:如果某一个变量或者引用表示某一块内存空间地址的话,则该变量或者引用指向了该块内存
2. 顺序表
-
集合中存储的元素是有顺序的,顺序表的结构可以分为两种形式:单数据类型(数据类型一致)和多数据类型(不同的数据类型)。
-
python中数组属于单数据类型的顺序表;列表和元组属于多数据类型的顺序表。
-
数组为什么要数据类型一致
数组在内存中是以链表的方式进行存储,会在内存中连续开辟一个空间给元素进行存储.比如数组中存储了a =array([1,2,3]),那么会在内存中连续开辟3个空间,变量a指向第一个空间地址也就是元素1的存储地址,暂且空间地址记为0x0.整型在内存中默认开辟4个字节大小,那么1向后偏移4个字节为2,内存地址记为0x4,同理元素3为0x8.所以只需记录了第一个元素1的内存地址,那么只要向后偏移以4位单位的字节就能找到连续开辟内存空间的其他元素. -
单数据类型数据表的内存图(内存连续开启)。
一个整型占4个字节,如果含有其他类型那么无法做到精准寻址,
-
为什么数组索引从0开始?
为了更方便的让计算机进行变量寻址和偏移.
a[0] -> 0-> 0x0 偏移0个单位
a[1] -> 1-> 0x4 偏移1个单位
a[2] -> 2-> 0x8 偏移2个单位 -
多数据类型顺序表的内存图(内存非连续开辟)。
这么设计的目的是为了存储多种类型的数据,并且可以做到精准寻址。但是如果想要在列表中间插入元素,地址的处理就是比较麻烦的事情了,需要做批量的移动和偏移,耗时。 -
顺序表的弊端:顺序表的结构需要预先知道数据大小来申请连续的存储空间,而进行扩充时又要进行数据的搬迁。
3. 链表
- 链表:相对于顺序表,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理且进行扩充是不需要进行数据迁移。
- 链表(Linkedlist)是一种常见的基础数据结构,是一种线性表,但是不像顺序表一样连续存储数据,而是每一个节点(数据存储单元)里存放下一个节点的信息(即地址)
- is_empty():链表是否为空
- length():链表的长度
- travel():遍历整个链表
- add(item):链表头部添加元素 这个方法一定要想明白,是后面的基础
- append(item):链表尾部添加元素
- insert(pos,item):链表指定位置添加元素
- remove(item):删除节点
- search(item):查找结点是否存在
3.1单链表
由此图可以看出,在中间添加或者删除不会影响后续链,即不用移动或者迁移后面的链。
3.2 向头部插入节点
代码如下:
# 单链表
# 节点
class Node():
def __init__(self, item):
self.items = item # 存储当前节点数据
self.next = None # 下一个节点信息(地址) 刚开始没有next
# 链表
class Link():
def __init__(self):
self._head = None # 初始化一个空链表 head用于记录第一个节点的地址
# 向链表的头部添加元素
def add(self, item):
# 创建一个新的节点
node = Node(item)
# 让新加入的节点next地址 == _head连接原来的节点地址,使新节点next得到连接
node.next = self._head
# node ==> 变量 ==> 内存空间地址
self._head = node
# 这一部分一直在改变指向,如果一个引用或者变量表示某一内存空间地址
# 那么这个引用或变量就指向了内存空间
link = Link()
link.add(3)
link.add(4)