数据结构
数据结构是计算机存储、组织数据的方式。是指相互之间存在一种或多种特定关系的数据元素的集合
通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率
持续更新,学一个记一个~
栈
栈模型:
一端开口 ==栈顶==
| |
| |
| |
| |
| |
|____________________|
一端封闭 ==栈底==
- 数据进入栈模型的过程称为:压/进栈
| | | |
| | [数据 A] | [数据 D] | <- 栈顶元素
| | [数据 B] | [数据 C] |
| | [数据 C] | [数据 B] |
| | [数据 D] | [数据 A] | <- 栈底元素
|____________________| |____________________|
- 数据离开栈模型的过程称为:弹/出栈
出栈顺序为从栈顶元素到栈底元素
栈是一种先进后出的模型
队列
队列模型:
一端开口 ==后端==
| |
| |
| |
| |
| |
| |
一端开头 ==前端==
- 数据从后端进入队列模型的过程称为:入队列
| |
| | [数据 A]
| | [数据 B]
| | [数据 C]
| | [数据 D]
| |
----------------------------------------------------------
入队列方向
\|/ 后端
| |
| [数据 D] |
| [数据 C] |
| [数据 B] |
| [数据 A] |
| |
\|/ 前端
出队列方向
- 数据从前端离开队列模型的过程称为:出队列
队列是一种先进先出的模型
数组
数组模型:
___0___1___2___3___4___5___6___
| [A] [B] [C] [D] [E] [F] [G] |
|_____________________________|
- 查询数据通过索引定位,查询任意数据耗时相同,查询数度快
- 删除数据时,要将原始数据删除,同时后面每个数据前移,删除效率低
- 添加数据时,添加位置后的每个数据后移,再添加元素,添加效率极低
数组是一种查询快,增删慢的模型
链表
链表的每一个元素被称为结点
结点模型:
[地址1]
________________
| [数据] [地址2] |
|_______________|
-----------------------------------------
地址1:结点的==存储位置(地址)==
数据:存储具体的==数据==
地址2:下一个结点的==地址==
头结点模型:
______________
| [head] [^] |
|____________|
-----------------------------------------
^:结点指向==空地址(表示结束)==
链表模型链接过程示例
- 给头结点存储一个数据A,保存在地址11的位置:
[11]
_______________ ___________
| [head] [11] | --> | [A] [^] |
|_____________| |_________|
- 再存储一个数据C,保存在地址37位置
[11] [37]
_______________ ____________ ___________
| [head] [11] | --> | [A] [37] | --> | [C] [^] |
|_____________| |__________| |_________|
- 再存储一个数据D,保存在地址96位置
[11] [37] [96]
_______________ ____________ ____________ ____________
| [head] [11] | --> | [A] [37] | --> | [C] [96] | --> | [D] [^] |
|_____________| |__________| |__________| |__________|
链表模型添加数据过程示例
在数据AC之间添加一个数据B,保存在地址54地址
[11] [37] [96]
_______________ ____________ ____________ ____________
| [head] [11] | --> | [A] [37] | --> | [C] [96] | --> | [D] [^] |
|_____________| |__________| |__________| |__________|
[54]
___________
| [B] [^] |
|_________|
- 数据B对应的下一个数据地址指向数据C
[11] [37] [96]
_______________ ____________ ____________ ____________
| [head] [11] | --> | [A] [37] | --> | [C] [96] | --> | [D] [^] |
|_____________| |__________| |__________| |__________|
↑
[54]
____________
| [B] [37] |
|__________|
- 数据A对应的下一个数据地址指向数据B
[11] [37] [96]
_______________ ____________ ____________ ____________
| [head] [11] | --> | [A] [54] | | [C] [96] | --> | [D] [^] |
|_____________| |__________| |__________| |__________|
| ↑
| [54]
| ____________
|--------> | [B] [37] |
|__________|
链表模型删除数据过程示例
删除数据BD之间的数据C
[11] [37] [96]
_______________ ____________ ____________ ____________
| [head] [11] | --> | [A] [54] | | [C] [96] | --> | [D] [^] |
|_____________| |__________| |__________| |__________|
| ↑
| [54]
| ____________
|--------> | [B] [37] |
|__________|
- 数据B对应的下一个数据地址指向数据D
[11] [37] [96]
_______________ ____________ ____________ ____________
| [head] [11] | --> | [A] [54] | | [C] [96] | --> | [D] [^] |
|_____________| |__________| |__________| |__________|
| ↑
| [54] |
| ____________ |
|--------> | [B] [96] |-------|
|__________|
- 数据C删除
[11] [96]
_______________ ____________ ____________
| [head] [11] | --> | [A] [54] | | [D] [^] |
|_____________| |__________| |__________|
| ↑
| [54] |
| ____________ |
|--------> | [B] [96] |-------|
|__________|
- 查询数据D是否存在,必须从头(head)开始查询
- 查询第n个数据,也必须从头(head)开始查询
链表是一种增删快,查询慢的模型(对比数组)
哈希表
JDK 8 之前,底层采用数据+链表实现,可以说是一个元素为链表的数组
JDK 8 以后,在长度比较长的时候,底层实现了优化
哈希表存储元素示例(如何保证元素唯一性)
待存储元素为:
“hello”
“world”
“java”
“world”
“通信”
“软件”
为了方便演示,计算各元素的哈希值为(实际计算机操作是每一次添加都进行独立计算):
“hello” ---- 99162322
“world” ---- 113318802
“java” ---- 3254818
“world” ---- 113318802
“通信” ---- 1179395
“软件” ---- 1179395
在JDK说明文档中看到HashSet的空参构造方法的描述为:
HashSet():构造一个空的集合;支持HashMap实例具有默认初始容量(16)和加载因子(0.75)。
对于这个加载因子为什么是0.75我在晚上查阅了很多资料,大部分说它是与泊松分布直接相关,直到后面我又看到一篇反驳的博客,链接都放在这里了,对学术研究还是要保持好奇,保持质疑的精神啊
支持与泊松分布直接相关
反驳
据此我们得到HashSet的模型:
[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15]
_________________________________________________________________________________
| | | | | | | | | | | | | | | | |
|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|
那么如何存储各元素的哈希值到哈希表中呢?
将各元素的哈希值进行对16取余,余数是几就存储到几中
“hello” ---- 99162322 % 16 => 2
“world” ---- 113318802 % 16 => 2
“java” ---- 3254818 % 16 => 2
“world” ---- 113318802 % 16 => 2
“通信” ---- 1179395 % 16 => 3
“软件” ---- 1179395 % 16 => 3
显然我们只需要用到编号为2的位置和编号为3的位置,所以下面的演示省略未用到的部分(实际没用到也是存在的)
[2] [3]
___________________________
..... | | | .....
|____________|____________|
- 尝试添加“hello”
根据“hello”的哈希值计算出它的存储位置是2,此时2号位没有元素,所以直接添加元素:
[2] [3]
___________________________
| “hello” | |
|_____________|____________|
- 尝试添加“world”
根据“world”的哈希值计算出它的存储位置也是2,此时2号位已经有元素,所以需要和已存在的元素进行比较,首先比较哈希值:
99162322 != 113318802
“hello” “world”
第一步对比发现二者哈希值不同,所以直接添加元素,元素也存储在2号位,但是是以链表的形式存储:
[2] [3]
___________________________
| “hello” | |
|______|______|____________|
↑
___________
| “world” |
|_________|
- 尝试添加“java” 同第二步,比较待添加元素和已存在所有元素的哈希值
99162322 != 3254818
“hello” “java”
---------------------------
113318802 != 3254818
“world” “java”
依次比较所有已存在元素后发现哈希值均不同,所以直接添加元素,同样以链表的形式存储在2号位:
[2] [3]
___________________________
| “hello” | |
|______|______|____________|
↑
___________
| “world” |
|_________|
↑
___________
| “java” |
|_________|
- 尝试添加“world”
同第二步,比较待添加元素和已存在所有元素的哈希值
99162322 != 113318802
“hello” “world”
---------------------------
113318802 == 113318802
“world” “world”
---------------------------
3254818 != 113318802
“java” “world”
依次比较所有已存在元素后发现哈希值存在相同值,所以继续比较相同哈希值的元素内容是否相同:
113318802 == 113318802
“world” == “world”
比较后发现内容一致,故跳过添加操作。
- 尝试添加“通信”
根据“通信”的哈希值计算出它的存储位置是3,此时3号位没有元素,所以直接添加元素:
[2] [3]
____________________________
| “hello” | “通信” |
|______|______|____________|
↑
___________
| “world” |
|_________|
↑
___________
| “java” |
|_________|
- 尝试添加“软件”
根据“软件”的哈希值计算出它的存储位置也是3,此时3号位已经有元素,所以需要和已存在的元素进行比较,首先比较哈希值:
1179395 == 1179395
“通信” “软件”
比较后发现二者哈希值相同,所以继续比较元素内容是否相同:
1179395 == 1179395
“通信” != “软件”
发现内容并不相同,故以链表的形式添加元素:
[2] [3]
____________________________
| “hello” | “通信” |
|______|______|_____|______|
↑ ↑
___________ __________
| “world” | | “软件” |
|_________| |_______|
↑
___________
| “java” |
|_________|
至此,哈希表添加元素操作演示完毕