链表
把一堆扑克牌丢地上,反面朝上,你能找到,哪张是梅花 A 吗?
如果正面朝上呢?
上面的例子很清晰的描述了链表的特点
链表是一种物理存储结构上非连续,非顺序的存储结构
数据元素的逻辑顺序是通过链表中的指针链接次序实现的
指针指向的就是数据的地址
反面朝上的扑克牌代表内存里的数据,如果正面朝上就代表我们赋予其地址,根据地址来操纵数据
此时你还能找到梅花 A 吗?
答:能!
*p = ♣A
所以链表的结构长这样:
无头单向非循环列表:结构简单,一般不会单独用来存放数据。实际中更多是作为其他数据结构的子结构,比如说哈希桶等等
带头双向循环链表:结构最复杂,一般单独存储数据。实际中经常使用的链表数据结构,都是带头双向循环链表。这个结构虽然复杂,但是使用代码实现后会发现这个结构会带来很多优势,实现反而简单了
单链表和双链表的区别:
单链表的每一个节点中只有指向下一个结点的指针,不能进行回溯,适用于节点的增加和删除。
双链表的每一个节点给
中既有指向下一个结点的指针,也有指向上一个结点的指针,可以快速的找到当前节点的前一个节点,适用于需要双向查找节点值的情况
为啥可以这么多样式?
因为指针就是这么方便!
话说。。有没有感觉和数组有点像了?
链表和数组的区别:
数组静态分配内存,链表动态分配内存
数组在内存中是连续的,链表是不连续的
数组利用下标定位,查找的时间复杂度是 O(1),链表通过遍历定位元素,查找的时间复杂度是 O(N)
数组插入和删除需要移动其他元素,时间复杂度是 O(N),链表的插入或删除不需要移动其他元素,时间复杂度是 O
(1)
稍微分析下是不是就会发现,各有各的优缺点?
所以存在即合理,每一种数据结构都有它的特点,并不是哪种好,哪种坏
树
直接放图:
还有比这更容易理解的了吗?
如果不理解就把"A"节点当作爷爷,“D”节点当作父亲,"H"节点当作小孩
树是一种数据结构
它是由 n(n>=1)个有限节点组成一个具有层次关系的集合。把它叫做 “树” 是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:
每个节点有零个或多个子节点;
没有父节点的节点称为根节点;
每一个非根节点有且只有一个父节点;
除了根节点外,每个子节点可以分为多个不相交的子树;
在日常的应用中,我们讨论和用的更多的是树的其中一种结构,就是
二叉树
为啥?
因为二叉树十分强大
二叉树是树的特殊一种,具有如下特点:
1、每个结点最多有两颗子树,结点的度最大为 2。
2、左子树和右子树是有顺序的,次序不能颠倒。
3、即使某结点只有一个子树,也要区分左右子树。
二叉树是一种比较有用的折中方案,它添加,删除元素都很快,并且在查找方面也有很多的算法优化,所以,二叉树既有链表的好处,也有数组的好处,是两者的优化方案,在处理大批量的动态数据方面非常有用。
扩展:
二叉树有很多扩展的数据结构,包括:
平衡二叉树、红黑树、B+树等
这些数据结构二叉树的基础上衍生了很多的功能
在实际应用中广泛用到,例如:
mysql的数据库索引结构用的就是B+树;还有HashMap的底层源码中用到了红黑树
这些二叉树的功能强大,但算法上比较复杂, 我还需要花时间去深入
哈希表
Hash table = 散列表
这两是一个东西
先看百度百科怎么说:
散列表(Hash table,也叫哈希表),是根据键(Key)而直接访问在内存存储位置的数据结构。也就是
说,它通过计算一个关于键值的函数,将所需查询的数据映射到表中一个位置来访问记录,这加快了查找速度。这个映射函数称做散列函数,存放记录的数组称做散列表
哈希表其实本质是数组
这要说到 Hash table 的两种实现方法:
1、数组+链
表
2、数组+二
叉树
区别在于:
数组中一般就是存
放的单一的数据 而哈希表中存放的是一个键值
结构示例图:
右边是数组
数组的每个成员包括一个指针,指向一个链表的头,当然这个链表可能为空,也可能元素很多
我们可以根据元素的一些特征把元素分配到不同的链表中去,也是根据这些特征,找到正确的链表,再从链表中找出这个元素
是不是感觉特别强大?
Hash Table 的查询速度非常的快,几乎是 O(1)的时间复杂度。
Java 中有些集合类就是借鉴了哈希原理构造的,例如 HashMap,HashTable 等
hash 就是找到一种数据内容和数据存放地址之间的映射关系
数据结构的魅力这不就来了吗?
讲到这里,就必须提到 Hash table 的应用了:
Hash 的应用
Hash 主要用于信息安全领域中加密算法,它把一些不同长度的信息转化成杂乱的 128 位的编码,这些编码值
叫做 Hash 值.
也可以说,Hash 就是找到一种数据内容和数据存放地址之间的映射关系
查找:哈希表,又称为散列,是一种更加快捷的查找技术。我们之前的查找,都是这样一种思路:集合中拿出来一个元素,看看是否与我们要找的相等,如果不等,缩小范围,继续查找。而哈希表是完
全另外一种思路:当我知道 key 值以后,我就可以直接计算出这个元素在集合中的位置,根本不需要一次又一次的查找!
举一个例子,假如我的数组 A 中,第 i 个元素里面装的 key 就是 i,那么数字 3 肯定是在第 3 个位置,数字 10 肯定是在第 10 个位置。哈希表就是利用利用这种基本的思想,建立一个从 key 到位置的函数,然后进行直接计算查找。
Hash 表在海量
数据处理中有着广泛应用
哈希表的应用场景很多,当然也有很多问题要考虑,比如哈希冲突的问题,如果处理的不好会浪费大量的时间,导致应用崩溃
堆
谈到堆,又得扯到数组身上了
例如现在数组长这样:
通常用数组来存储堆中的元素,但是我们却可以把数组中元素视为树:
原来虽然我们是在数组中存储的堆元素,但是这里面有一条隐藏的规律,如果你仔细看上图就会发现:
每一个左子树节点的下标是父节点
的 2 倍
每一个右子树节点的下标是父节
点的 2 倍再加 1
数组中实际上隐藏了上面的这两条规律
早说了数据结构就是数据的存储规律吧
堆这种数据结构最棒的地方在于我们无需像树一样存储左右子树的信息
只需要通过下标运算就可以轻松的找到一个节点的左子树节点、右子树节点以及父节点
相对于树这种数据结构来说堆更加节省内存
你还可以这样理解堆:
将根节点最大的堆叫做最大堆或大根堆
根节点最小的堆叫做最小堆或小根堆
常见的堆有二叉堆、斐波那契堆等
因为堆有序的特点,一般用来做数组中的排序,称为堆排序
图
图的结构长这样:
节点可以具有零个或多个相邻元素
两个节点之间的连接称为边。
节点也可以称为顶点。
图的应用
例如广度优先搜索(BFS)-图形搜索
深度优先搜索(DFS)-图形搜索
给大家推荐一篇文章:
《Graph Data Structures in JavaScript for Beginners》
作者用 Javascript 实现图形数据结构,通俗易懂
截图:
GO!