本文参考了
zejian_ 的博文系列:《 java数据结构与算法》
拭心 的博文系列:《Java 集合框架》
数组可以存储具有相同数据类型的元素集合,如int,float或者自定义类型等,当我们创建一个数组时,计算机操作系统会为该数组分配一块连续的内存块,这也就意味着数组中的每个存储单元的地址都是连续的,因此只要知道了数组的起始内存地址就可以通过简单的乘法和加法计算出数组中第n-1个存储单元的内存地址,从而获取对应的值。
引申:
线性表是由n(n>=0)个类型相同的数据元素a0,a1,…,an-1组成的有限的序列,在数学中记作(a0,a1,…,an-1),其中ai的数据类型可以是基本数据类型(int,float等)、字符或类。n代表线性表的元素个数,也称其为长度(Length)。若n=0,则为空表;若n > 0,则ai(0 < i < n-1)有且仅有一个前驱(Predecessor)元素ai-1和一个后继(Successor)元素ai+1,a0没有前驱元素,ai没有后继元素。线性表的顺序存储设计与实现(顺序表)(数组)
线性表的链式存储设计与实现(链表)
栈是一种用于存储数据的简单数据结构,有点类似链表或者顺序表(统称线性表)。栈与线性表的最大区别是数据的存取的操作,我们可以这样认为栈(Stack)是一种特殊的线性表。其插入和删除操作只允许在线性表的一端进行,一般而言,把允许操作的一端称为栈顶(Top),不可操作的一端称为栈底(Bottom),同时把插入元素的操作称为入栈(Push),删除元素的操作称为出栈(Pop),栈的特点就是后进先出LIFO(Last In First Out)。若栈中没有任何元素,则称为空栈 。
队列同样是一种特殊的线性表,其插入和删除的操作分别在表的两端进行,队列的特点就是先进先出FIFO(First In First Out)。我们把向队列中插入元素的过程称为入队(Enqueue),删除元素的过程称为出队(Dequeue)并把允许入队的一端称为队尾,允许出的的一端称为队头,没有任何元素的队列则称为空队。
线性链表的存储结构是用若干个地址分散的存储单元存放数据元素的,逻辑上相邻的数据元素在物理位置上不一定相邻,因此每个存储单元中都会有一个地址指向域,这个地址指向域指明其后继元素的位置。在链表中存储数据的单元称为结点(Node),一个结点至少包含了数据域和地址域,其中数据域用于存储数据,而地址域用于存储前驱或后继元素的地址。链表的插入和删除都相当便捷,这是由于链表中的结点的存储空间是在插入或者删除过程中动态申请和释放的,不需要预先给单链表分配存储空间的,从而避免了顺序表因存储空间不足需要扩充空间和复制元素的过程,提高了运行效率和存储空间的利用率。
强烈推荐博客:https://blog.csdn.net/javazejian/article/details/53727333
树是数据元素之间具有次层关系的非线性的结构,树是由n(n≥0)个结点组成的有限集合,n=0的树是空树,n大于0的树T由以下两个条件约定构成:
定义:
二叉树(Binary Tree)是n(n≥0)个结点组成的有限集合,n=0时称为空二叉树;n>0的二叉树由一个根结点和两棵互不相交、分别称为左子树和右子树的子二叉树构成。二叉树也是递归定义的,上节定义的度、层次等术语,同样适用于二叉树。
性质:
一棵高度为h的满二叉树(Full Binary Tree)是具有2h−1(h≥0)个结点的二叉树。
最大特点是每一层次的结点数都达到最大值
对于完全二叉树,假设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。
二叉树存储结构:链式存储结构 + 顺序存储结构(仅适用于完全二叉树或满二叉树)
BinaryNode(T data , BinaryNode left , BinaryNode right )
采用二叉链表存储结构,每个结点只存储了到其孩子结点的单向关系,而没有存储到父结点的关系,这样的话,每次要获取父结点时将消耗较多的时间,因为需要从root根结点开始查找,花费的时间是遍历部分二叉树的时间,而且与该结点的位置有关。为了更高效的获取父结点,三叉链表存储结构孕育而生了。
三叉链表存储结构
三叉链表主要是在二叉链表的基础上多添加了一个指向父结点的域,这样我们就存储了父结点与孩子结点的双向关系,当然这样也增加了一定的空开销其结点结构如下:
ThreeNode(T data ,ThreeNode parent,ThreeNode left,ThreeNode right)
二叉查找树的特性是,对于树中的每个结点T(T可能是父结点),它的左子树中所有项的值小T中的值,而它的右子树中所有项的值都大于T中的值。这意味着该树所有的元素可以用某种规则进行排序(取决于Comparable接口的实现)。
二叉树的遍历规则主要有四种:先根次序遍历,中根次序遍历,后根次序遍历以及层次遍历。
1.3.1 先根次序遍历
访问规则是先遍历根结点,再遍历左子树,最后遍历右子树。如下图遍历的次序为ABEFC
1.3.2 中根次序遍历
访问规则是先遍历左子树,再遍历根结点,最后遍历右子树。如下图遍历的次序为EBFACH
1.3.3 后根次序遍历
访问规则是先访问左子树,再访问右子树,最后访问根结点。如下图遍历的次序为EFBHCA
1.3.4 层次遍历
访问规则是特性就是兄弟优先访问,两个兄弟结点的访问顺序是先左后右的。同样它们的后代结点的访问次序也是先左后右,左兄弟的所有孩子结点一定优先右兄弟的孩子访问。如下图遍历的次序为ABCDEHG
散列表,也叫哈希表,是根据关键码和值 (key和value) 直接进行访问的数据结构,通过key和value来映射到集合中的一个位置,这样就可以很快找到集合中的对应元素。
记录的存储位置=f(key)
这里的对应关系 f 成为散列函数,又称为哈希 (hash函数),而散列表就是把Key通过一个固定的算法函数既所谓的哈希函数转换成一个整型数字,然后就将该数字对数组长度进行取余,取余结果就当作数组的下标,将value存储在以该数字为下标的数组空间里,这种存储空间可以充分利用数组的查找优势来查找元素,所以查找的速度很快。
哈希表在应用中也是比较常见的,就如Java中有些集合类就是借鉴了哈希原理构造的,例如HashMap,HashTable等,利用hash表的优势,对于集合的查找元素时非常方便的,然而,因为哈希表是基于数组衍生的数据结构,在添加删除元素方面是比较慢的,所以很多时候需要用到一种数组链表来做,也就是拉链法。拉链法是数组结合链表的一种结构,较早前的hashMap底层的存储就是采用这种结构,直到jdk1.8之后才换成了数组加红黑树的结构,其示例图如下:
从图中可以看出,左边很明显是个数组,数组的每个成员包括一个指针,指向一个链表的头,当然这个链表可能为空,也可能元素很多。我们根据元素的一些特征把元素分配到不同的链表中去,也是根据这些特征,找到正确的链表,再从链表中找出这个元素。
哈希表的应用场景很多,当然也有很多问题要考虑,比如哈希冲突的问题,如果处理的不好会浪费大量的时间,导致应用崩溃。
略
略