持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情
简介
数据结构是计算机存储、组织数据的方式。数据结构是将多种数据相互之间以某种特定的关系组合在一起形成,在各种场景下精心选择好合适的数据结构能够给计算机存储运行带来更好的效率,数据结构往往同高效的检索算法和索引技术有者紧密的联系。
常用的数据结构有:数组(Array)、链表(Linked)、树(Tree)、堆(Heap)、栈(Stack)、队列(Queue)、散列表(Hash)、图(Graph),那么这篇文章我们主要介绍以下三种数据结构。
数组
数组在内存中数据存储是连续的,所以数组创建时要在内存中分配数组存放空间,必须指定数组大小。
在java中数组的声明方式有三种:
- 声明数组变量,直接赋值,花括号中元素数量就是数组大小,并以该数组大小开辟内存空间,属于静态创建(这或许是我们常用的写法)。
char[] cs1 = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'};
- 声明数组变量,以花括号元素数量作为数组大小创建内存空间,并对数组元素进行值填充,属于动态创建。
char[] cs2 = new char[]{'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'};
- 声明数组变量,并创建内存空间,属于动态创建,等待使用者对数组元素进行赋值。
char[] cs3 = new char[11];
上图数组声明完成后内存空间结构就是这样连续的,并且已经固定了元素个数,所以在数组需要进行增删元素就需要创建出一个新的数组,如下图:
-
增加数组元素,只能更换新数组重新分配内存空间,原数组进行销毁等待内存回收。
-
删除数组元素,并不能直接删除对应下标位置的数据,也需要更换数组重新分配内存空间。
优点:可以通过数组下标的方式访问数组成员,查询效率高。
缺点:数组增删操作会给系统带来性能消耗,为保证数组下标越界问题,需要动态扩容(即使用新数组代替旧数组)。
注:数组需注意下标越界问题,下标从0开始到数组长度-1(0 <= n <= cs1.length - 1),如果超出下标范围即会抛出数组下标越界异常
java.lang.ArrayIndexOutOfBoundsException。
数组的动态扩容在java中的
ArrayList类中有详细的使用方法。
链表
链表分为单链表和双链表,存储空间比较灵活,不要求存储空间的连续性,创建时也不需要知道大小。
链表的具体结构以及使用方法我们就以java中的LinkedList来具体说明:
上图即是LinkedList的一个节点类,那么它的每一个节点数据如下所示:
LinkedList<String> linked = new LinkedList();
linked.add("A");
- prev:代表链表节点指向的上一个节点。
- next:代表链表节点指向的下一个节点。
- item:代表链表节点本身的数据,在此示例中我们就以A作为节点值。
多添加几个节点后,链表结构如下:
LinkedList<String> linked = new LinkedList();
linked.add("A");
linked.add("B");
linked.add("C");
linked.add("D");
linked.add("E");
删除节点结构如下直接断开C节点的prev、next引用:
linked.remove("C");
优点:由于存储空间没有连续性要求,所以在增删元素只需指定链表上下节点的关系,无需移动元素增删效率高。
缺点:不支持下标访问,只能顺序遍历(单向链表仅能正序遍历,双向链表可以双向遍历)。
注:
LinkedList有提供get(index)下标获取节点的方法,实际上就是通过逐个遍历节点获取的,可查看下图源码解释,只不过多了一步判断从链表头部还是尾部遍历更快。
树
数组与链表数据结构都有各自的优缺点,那么树结构就融合了数组与链表的优点,即保证了查询检索效率,又保证了增删的效率,在内存中的存储不连续。
- 二叉树:
特点:树节点的右子节点永远比节点大,左子节点比节点小,每个节点左右子树也是二叉树,节点有序排序。所以树结构查询时将值优先与根节点进行比较,如果小于根节点就向左子树继续查询,如果大于根节点就向右子树继续查询,否则就是与根节点等值。相比链表需要整个遍历查询效率要高一些。
- 不平衡二叉树:如果一个普通的二叉树,它的数据分部导致根节点左右子树的节点分布不均,那么就可能会导致查询效率大大降低,甚至跟链表一样几乎要整个树进行遍历。
如上图,我们如果要查询节点3,那么就几乎需要遍历整个树,效率就可能降低到跟链表一样。
- 平衡二叉树:基于不平衡二叉树做了一个去除顶端优势处理,让树结构重新排列达到一个平衡的效果。
如上图,顶端节点10被去除,改由节点7作为根节点,树的整体结构就达到了平衡。
总结
数据结构使用还需根据业务场景充分考量分析去做先择,在数据量大的场景下大量查询少做增删肯定得用数组,大量增删少遍历查询的就使用链表,如果两者都需要那就考虑使用树结构,不过还是需要多做一些大数据量的压力测试看结果是否符合预期,也并不能直接一概而论。