2.5、java核心数据结构

数据结构是计算机存储数据的方式,选用不同的数据结构存储数据,对数据的增删改查复杂度有着重大意义。

2.5.1、线性数据结构

线性结构是指该结构中的节点之间存在一对一的关系。其特点是开始节点和终端节点都是唯一的,除了开始节点和终端节点外,其余节点都有且仅有一个直接前驱,有且仅有一个直接后继。

 

    2.5.1.1、一维数组

         数组:一组有顺序(指的是每一个元素都有一个编号–下标–索引)的数据,可以保存若干个数据。每一个数据我们称之为元素 
一旦开辟空间之后。所有的元素都会由系统分配一个默认值。整数型:0,浮点型:0.0 boolean:false char 0 复合数据类型的:null 。
        数组只能保存一种数据类型,数据类型可以是任意的类型 
        数组:有顺序,下标的顺序,从0开始,最大下标为length-1。 
        使用数组的时候经常会遇到的异常:java.lang.ArrayIndexOutOfBoundsException 数组越界的一个异常 可能你的下标是一个负数,或者是一个大于length-1的一个值。

        数组有三种初始化的方式: 
        1:动态初始化:定义和分配空间可以分开进行。也可以同时进行。 
        int[] ints; ints = new int[10]; 
        2:静态初始化:只能声明和初始化一同进行,放到同一行。 
        int[] ints = {1,2,3}; 
        3:动静结合:int[] ints = new int[]{1,2,3}; 
        4:如何访问数组元素 
        数组名+下标 例如:ints[0]。

        数组这种数据结构典型的操作方法,是根据下标进行操作的,所以insert的的时候可以根据下标插入到具体的某个位置,但是这个时候它后面的元素都得往后面移动一位。所以插入效率比较低,更新,删除效率也比较低,而查询效率非常高,查询效率时间复杂度是1。

         2.5.1.2、线性表

线性表是有序的储存结构、链式的储存结构。链表的物理储存空间是不连续的,链表的每一个节点都知道上一个节点、或者下一个节点是谁,通常用Node表示。常见的有顺序链表(LinkedList、Linked***),单项链表(里面只有Node类),双向链表(两个Node类),循环链表(多个Node类)等。

操作方法:插入效率比较高,插入的时候只需要改变节点的前后节点的连接即可。而查询效率就比较低了,如果实现的不好,需要整个链路找下去才能找到应该找的元素。所以常见的方法有:add(index,element),addFirst(element),addLast(element)。getFirst(),getLast(),get(element)等。

常见的Uitil有:LinkedList,LinkedMap等,而这两个JDK底层也做了N多优化,可以有效避免查询效率低的问题。当自己实现的时候需要注意。其实树形结构可以说是非线性的链式储存结构。

         2.5.1.3、栈

栈,最主要的是要实现先进后出,后进先出的逻辑结构。来实现一些场景对逻辑顺序的要求。所以常用的方法有push(element)压栈,pop()出栈。

java.util.Stack。就实现了这用逻辑。而Java的Jvm里面也用的到了此种数据结构,就是线程栈,来保证当前线程的执行顺序。

         2.5.1.4、队列

队列,队列是一种特殊的线性数据结构,队列只能允许在队头,队尾进行添加和查询等相关操作。队列又有单项有序队列,双向队列,阻塞队列等。

Queue这种数据结构注定了基本操作方法有:add(E e)加入队列,remove(),poll()等方法。

队列在Java语言环境中是使用频率相当高的数据结构,所有其实现的类也很多来满足不同场景。

使用场景也非常多,如线程池,mq,连接池等。

         2.5.1.5、串

串:也称字符串,是由N个字符组成的优先序列。在Java里面就是指String,而String里面是由chat[]来进行储存。

KMP算法: 这个算法一定要牢记,Java数据结构这本书里面针对字符串的查找匹配算法也只介绍了一种。关键点就是:在字符串比对的时候,主串的比较位置不需要回退的问题。

2.5.2、非线性数据结构

包括集合、树形结构、图形结构或网状结构,特点是数据元素之间存在一个对多个或多个对多个的关系,其中集合是一种关系极为松散的结构。即指在该类结构中至少存在一个数据元素,它具有两个或者两个以上的前驱或后继。

   
         2.5.2.1、多维数组

         2.5.2.2、集合

由一个或多个确定的元素所构成的整体叫做集合。在Java里面可以去广义的去理解为实现了Collection接口的类都叫集合。

         2.5.2.3、树

树形结构,作者觉得它是一种特殊的链形数据结构。最少有一个根节点组成,可以有多个子节点。树,显然是由递归算法组成。

树的特点:

  1. 在一个树结构中,有且仅有一个结点没有直接父节点,它就是根节点。
  2. 除了根节点,其他结点有且只有一个直接父节点
  3. 每个结点可以有任意多个直接子节点。

树的数据结构又分如下几种:

  • 1) 自由树/普通树:对子节点没有任何约束。

  • 2) 二叉树:每个节点最多含有两个子节点的树称为二叉树。
    2.1) 一般二叉树:每个子节点的父亲节点不一定有两个子节点的二叉树成为一般二叉树。
    2.2) 完全二叉树:对于一颗二叉树,假设其深度为d(d>1)。除了第d层外,其它各层的节点数目均已达最大值,且第d层所有节点从左向右连续地紧密排列,这样的二叉树被称为完全二叉树;
    2.3) 满二叉树:所有的节点都是二叉的二叉树成为满二叉树。

  • 3) 二叉搜索树/BST:binary search tree,又称二叉排序树、二叉查找树。是有序的。要点:如果不为空,那么其左子树节点的值都小于根节点的值;右子树节点的值都大于根节点的值。


3.1) 二叉平衡树:二叉搜索树,是有序的排序树,但左右两边包括子节点不一定平衡,而二叉平衡树是排序树的一种,并且加点条件,就是任意一个节点的两个叉的深度差不多(比如差值的绝对值小于某个常数,或者一个不能比另一个深出去一倍之类的)。这样的树可以保证二分搜索任意元素都是O(log n)的,一般还附带带有插入或者删除某个元素也是O(log n)的的性质。
为了实现,二叉平衡树又延伸出来了一些算法,业界常见的有AVL、和红黑算法,所以又有以下两种树:
3.1.1) AVL树:最早的平衡二叉树之一。应用相对其他数据结构比较少。windows对进程地址空间的管理用到了AVL树。
3.1.2) 红黑树:通过制定了一些红黑标记和左右旋转规则来保证二叉树平衡。
红黑树的5条性质:

    1. 每个结点要么是红的,要么是黑的。
    2. 根结点是黑的。
    3. 每个叶结点(叶结点即指树尾端NIL指针或NULL结点)是黑的。
    4. 如果一个结点是红的,那么它的俩个儿子都是黑的。
    5. 对于任一结点而言,其到叶结点树尾端NIL指针的每一条路径都包含相同数目的黑结点。

  • 4) B-tree:又称B树、B-树。又叫平衡(balance)多路查找树。树中每个结点最多含有m个孩子(m>=2)。它类似普通的平衡二叉树,不同的一点是B-树允许每个节点有更多的子节点。

  • 4) B+tree:又称B+。是B-树的变体,也是一种多路搜索树。

树总结:
树在Java里面应用的也比较多。非排序树,主要用来做数据储存和展示。而排序树,主要用来做算法和运算,HashMap里面的TreeNode就用到了红黑树算法。而B+树在数据库的索引原理里面有典型的应用。

         2.5.2.4、图

         2.5.2.5、散列表

Hash概念:

  • Hash,一般翻译做“散列”,也有直接音译为“哈希”的,就是把任意长度的输入(又叫做预映射, pre-image),变换成固定长度的输出,该输出就是散列值。一般通过Hash算法实现。
  • 所谓的Hash算法都是散列算法,把任意长度的输入,变换成固定长度的输出,该输出就是散列值.(如:MD5,SHA1,加解密算法等)
  • 简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。

Java中的hashCode:

  • 我们都知道所有的class都是Object的子类,既所有的class都会有默认Object.java里面的hashCode的方法,如果自己没有重写,默认情况就是native方法通过对象的内存的+对象的值然后通过hash散列算法计算出来个int的数字。
  • 最大的特性是:不同的对象,不同的值有可能计算出来的hashCode可能是一样的。

Hash表:

  • Java中数据存储方式最底层的两种结构,一种是数组,另一种就是链表。而Hash表就是综合了这两种数据结构。
  • 如:HashTable,HashMap。这个时候就得提一下HashMap的原理了,默认16个数组储存,通过Hash值取模放到不同的桶里面去。(注意:JDK1.8此处算法又做了改进,数组里面的值会演变成树形结构。)
  • 哈希表具有较快(常量级)的查询速度,及相对较快的增删速度,所以很适合在海量数据的环境中使用。一般实现哈希表的方法采用“拉链法”,我们可以理解为“链表的数组”。

一致性Hash:

  • 我们查看一下HashMap的原理,其实发现Hash很好的解决了单体应用情况下的数据查找和插入的速度问题。但是毕竟单体应用的储存空间是有限的,所有在分布式环境下,应运而生了一致性Hash算法。
  • 用意和hashCode的用意一样,只不过它是取模放在不同的IP机器上而已。具体算法可以找一下相关资料。
  • 而一致性Hash需要注意的就是默认分配的桶比较多些,而当其中一台机器挂了,影响的面比较小一些。
  • 需要注意的是,相同的内容算出来的hash一定是一样的。既:幂等性。

发布了39 篇原创文章 · 获赞 2 · 访问量 5009

猜你喜欢

转载自blog.csdn.net/u013636987/article/details/104145870