目录
数据结构的定义
数据结构的分类
逻辑结构分类
物理结构分类
相关概念
时间复杂度
hash
hash冲突
Java中的数组结构
线性表
ArrayList
LinkedList
链表
Java中的实现
Vector
栈和队列
栈在Java中的应用
JDK1.7中HashMap的实现
哈希表
Hashtable
HashMap
树
平衡二叉树的创建及遍历
红黑树
JDK1.8中的HashMap
在面试大数据工作的过程中。中大型公司,都会对数据结构和算法方面的知识有一定的要求。
由于是从Java开发转的大数据,那么在学习数据结构,也是与Java语言相关的数据结构学习为主,总结一下数据结构的知识。
百度的定义:数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率。
自己理解:数据结构就是定义数据的逻辑结构和物理存储结构,并且分析两者之间的联系。
即平时以代码开发的形式操作的数据结构,可以分为2类8种。
逻辑结构一般分为2大类:线性结构和非线性结构。线性结构中有且仅有一个开始结点和一个终端结点,并且所有的结点最多只能有一个前驱和一个后继。线性表是典型的线性结构。非线性结构的一个结点可能有多个前驱和后继。如果一个结点最多只有一个前驱,而可以有多个后继,这种结构就是树。树是最重要的非线性结构之一。如果对结点的前驱和后继的个数不做限制,这种结构就是图。图是最一般的非线性结构。
数据结构一般分为以下8种:
在面试中常常问到的是树形结构。
物理结构即数据的存储结构,描述的是数据具体在内存中的存储。
这个概念可以在后期补充,主要是体现数据结构或者算法的高效性。
如果学过高等数学,可以类比为程序执行次数的高阶无穷小/同阶无穷小函数。
被翻译成“散列”,也可以直译成哈希。就是把任意长度的输入,通过hash函数,变成固定长度的输出。该输出值就是散列值。
表达式:value=hash(key)。
在Java中的应用:即每个对象的hashCode()方法。
详细分析的链接:https://www.cnblogs.com/dolphin0520/p/3681042.html
以Java中的HashMap举例。即以key经过hash函数计算后得到的地址去存入value的时候,发现此地址已经存在了value值。此时即产生了hash冲突。
解决办法:
重点了解链地址法,在JDK1.7中HashMap解决hash冲突的方式就是链地址法。面试中不需要了解解决办法,若想了解可自行百度。
Java中声明一个数组就是在内存空间中开辟出一段连续的空间。
数组的特性
数组可以看做是一种特殊的线性表。特殊之处在于:数组的元素也是以一种线性表。根据下标读/写任何元素的时间复杂度都为o(1)
但是二维数组、广义表、树、图等都是非线性结构。
线性表是一种典型的线性结构,头结点无前驱,尾结点无后驱。
面试时仅需了解基本的线性表:数组、单项链表、双向链表。
在Java中,若是实现了AbstractList的集合类,都可认为是线性表结构,例如ArrayList、Vector、LinkedList。
注:List中的元素是有序排列且可重复,故称之为序列。
ArrayList的底层实现仍然是数组。ArrayList在创建的时候,会默认创建一个长度固定的数组,对于数量小于这个长度的数据来说,在存入的过程中,可以说ArrayList是动态的。当数据的原始数组容量,会将原来元素拷贝到一个容量更大的数组中。
ArrayList的缺点
ArrayList的源码分析:https://www.cnblogs.com/skywang12345/p/3308556.html
一般仅需要知道单向链表即可。
链表的特点:增删快,查询慢。
链表数据结构学习链接:http://www.cnblogs.com/skywang12345/p/3561803.html
https://www.cnblogs.com/skywang12345/p/3308556.html
由于ArrayList不是线程安全的,故仅能在单线程时使用。在多线程时使用Vector或者CopyOnWriteArrayList。
栈(stack)是一种线性存储结构,有以下特点:
在JVM中的栈区,就是使用的这种理念。故在每次程序的方法进行递归的时候,都会调用一次方法进行压栈。当递归的方法找到出口的时候,即是最后一次调用递归方法。运行栈中的方法时,遵循的便是后进先出。
百度百科:散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数(哈希函数),存放记录的数组叫做散列表。
给定表M,存在函数f(key),对任意给定的关键字值key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表M为哈希(Hash)表,函数f(key)为哈希(Hash) 函数。
Hashtable由于为了线程安全,在每个方法都加了锁。而在平时开发中多是在单线程情况下操作,故在JDK1.2中HashMap出现后,逐渐被被淘汰,如今已经过时。
HashMap维护了一张哈希表,用来解决哈希冲突问题。在JDK1.8之前,HashMap主要是由数组+链表的方式实现的。而链表主要的目的就是为了解决Hash冲突问题。哈希表即哈希数组,数组中的每个元素即单链表的头结点。如果不同数据映射到了数组的同一个位置,就存放在Entry链表中。
HashMap的底层源码及细节分析:https://blog.csdn.net/ns_code/article/details/36034955
HashMap与Hashtable的对比分析:https://blog.csdn.net/fujiakai/article/details/51585767
树的基本概念网上一搜便可学习,这里我附上一个连接:https://blog.csdn.net/DouBoomFly/article/details/70171410
掌握以下基本概念:
二叉树的先序遍历:根结点->左结点->后结点
二叉树的中序遍历:左结点->根结点->后结点
二叉树的后序遍历:左结点->右结点->根结点
//二叉树结点
public class BSTree{
private int val;
private BSTree left;
private BsTree right;
BSTree(int data){
val=data;
left=null;
right=null;
}
}
public class BSTreeBuilder{
/*给二叉树中添加值
*root:结点
*data:待插入的值
**/
public static insert(BSTree root,int data){
if(root.val>data){
if(root.left==null)
root.left=new BSTree(data);
else
insert(root,data);
}else{
if(root.right==null)
root.right=new BSTree(data);
else
insert(root,data);
}
}
//先序遍历二叉树
public static binSearch(BSTree root){
if(root!=null){
System.out.println("root.value: "+root.val);
binSearch(root.left);
binSearch(root.right);
}
}
//中序遍历二叉树
public static binSearch(BSTree root){
if(root!=null){
binSearch(root.left);
System.out.println("root.value: "+root.val);
binSearch(root.right);
}
}
//后序遍历二叉树
public static binSearch(BSTree root){
if(root!=null){
binSearch(root.left);
binSearch(root.right);
System.out.println("root.value: "+root.val);
}
}
}
注:在Java中的多数遍历方式的实现,都是采用中序遍历的方式,故主要记住中序遍历。
红黑树的概念比较复杂,由于在JDK1.8之后,HashMap采用红黑树来取代了原来的链表结构,以解决链表存储数据导致的死循环问题,所以红黑树还是有学习的必要的。但是仅仅从顺序二叉树、平衡二叉树的角度去掌握红黑树就行。至于它的时间复杂度等,都可以暂时不去考虑。
红黑树的特性:
(1)每个节点或者是黑色,或者是红色。
(2)根节点是黑色。
(3)每个叶子节点(NIL)是黑色。 [注意:这里叶子节点,是指为空(NIL或NULL)的叶子节点!]
(4)如果一个节点是红色的,则它的子节点必须是黑色的。
(5)从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。
注意:
(01) 特性(3)中的叶子节点,是只为空(NIL或null)的节点。
(02) 特性(5),确保没有一条路径会比其他路径长出俩倍。因而,红黑树是相对是接近平衡的二叉树。
红黑树的深入学习的链接:https://www.cnblogs.com/CarpenterLee/p/5503882.html