老程序员分享:java之数据结构【入门篇】

简介: 老程序员分享:java之数据结构【入门篇】

定义


数据结构是指相互之间存在着一种或多种关系的数据元素的集合 。


常见的数据结构


数据存储的常用结构有数组,栈,队列,链表,树,图,堆,散列表等,如下图所示。


数组(Array)


数组是连续存储多个元素的序列,在内存中的分配也是连续的,数组中的元素通过下标进行访问。


String【】 data = new String【】{"Tom","Jack","Jessica","Katherine","Layman"};


System.out.println(data【3】);


优点:


1、查找元素快:通过索引,可以快速访问指定位置的元素


2、遍历数组快:通过索引,能够快速遍历数组


缺点:


1、数组的大小一旦确定就无法再扩容


2、数组只能存储单一类型的数据


3、添加,删除的操作慢,因为要移动其他的元素。


增加元素:需要创建一个新数组,将指定新元素存储在指定索引位置,再把原数组元素根据索引,复制到新数组对应索引的位置。


删除元素:需要创建一个新数组,把原数组元素根据索引,复制到新数组对应索引的位置,原数组中指定索引位置元素舍弃,不复制。


适用场景:


频繁查询,对存储空间要求不大,很少增加和删除的情况。


栈(Stack)


栈,又称堆栈,是一种特殊的(运算受限)线性表,其限制是仅允许在栈顶允许进行操作(类似弹匣)。


从栈顶放入元素的操作叫入栈,也叫压栈,取出元素叫出栈,也叫弹栈。


特点


先进后出,后进先出(类比弹匣上子弹)


适用场景:


递归,例如斐波那契数列。


队列(Queue)


队列和堆栈一样,也是一种运算受限的线性表,其限制是仅允许在表的一端进行插入,而在表的另一端进行删除。


可以把队列想象成两端开口的栈


特点


先进先出。


试用场景


因为队列具有先进先出的特点,因此非常适用于多线程阻塞队列管理。


链表(Linked List)


链表是由一系列结点node(链表中每一个元素称为结点)组成,每个结点至少有两个域,一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。


链表的第一个节点和最后一个节点,分别称为头节点和尾节点。


尾节点的特征是其 next 引用为空(null)。


单向链表


单向链表中,每个节点的数据域都是通过一个 Object 类的对象引用来指向数据元素。


与数组类似,单向链表中的节点也具有线性次序,即如果节点 a1 的 next 引用指向节点 a2,则 a1 是 a2 的直接前驱节点,a2 是 a1 的直接后续节点。


只能通过前驱节点找到后续节点,而无法从后续节点找到前驱节点。


特点


查询慢: 存储地址不连续,每次查询元素都需要从头开始增删快:不必移动节点,只要改变节点中的指针,但是需要先定位到元素上。不保证元素的顺序:存储元素和取出元素的顺序有可能不一致。只能通过前驱节点找到后续节点,而无法从后续节点找到前驱节点。


双向链表


单向链表中找到某个节点的前驱节点,必须从链表的头节点出发依次向后寻找,需要Ο(n)时间。


因此我们可以扩展单向链表的节点结构,使得通过一个节点的引用,不但能够访问其后续节点,也可以访问其前驱节点。这就是双向链表。


双向链表,就是在单链表节点结构中新增一个域,该域存储指向该节点的前驱节点。


单向链表只能从一个方向遍历,双向链表可以从两个方向遍历。


双向链表头节点的前驱节点(pre)为空,而尾节点的后续节点(Next)为空


在双向链表中插入和删除节点,无//代码效果参考:http://www.jhylw.com.cn/184920699.html

论插入和删除的节点位置在何处。因为首尾节点的存在,插入、删除操作都可以被归结为某个中间节点的插入和删除。

因为首尾节点的存在,双向链表永不为空。


简单用双向列表模拟LinkedList,代码如下:


import lombok.Data;


/


简单用双向列表模拟LinkedList


@author layman


@date 2021/2/24


/


public class MyLinkedList {


//首节点


private Node first;


//尾节点


private Node last;


public void add(Object obj){


if(first==null){


//说明该元素存于首节点上


Node firstNode = new Node();


firstNode.setPrevious(null);


firstNode.setObj(obj);


firstNode.setNext(null);


//此时该LinkedList只存了一个元素,所以首尾节点都设置为首节点


first //代码效果参考:http://www.jhylw.com.cn/023035215.html

= firstNode;

last = firstNode;


}else{


//存入的不是首节点,则该元素存于首节点之后,指向前一个节点的last


Node node=new Node();


node.setPrevious(last);


node.setObj(obj);


node.setNext(null);


//将链表的last指针指向node


last.setNext(node);


//将链表的last改为node


last = node;


}


}


}


// 节点类


@Data


class Node {


//前驱节点


private Object previous;


//存储的数据


private Object obj;


//后续节点


private Object next;


}


循环链表


头节点和尾节点被连接在一起的链表称为循环链表,这种方式在单向和双向链表中皆可实现。


循环链表中第一个节点之前就是最后一个节点,反之亦然。


总结


链表的优点:


链表不需要初始化容量,可以任意加减元素;查询慢: 存储地址不连续,每次查询元素都需要从头开始,非常耗时增删快:不必移动节点,只要改变节点中的指针,但是需要先定位到元素上。因为含有大量的指针域,所以占用空间较大


适用场景:


数据量较小,需要频繁增加,删除操作的场景


树(Tree)


树是一种数据结构,它是由n(n>=1)个有限节点组成一个具有层次关系的集合。


之所以把它叫做 “树”, 是因为它看起来像一棵倒挂的树(根朝上,叶朝下)。


特点


每个节点有零个或多个子节点。没有父节点的节点称为根节点。每一个非根节点有且仅有一个父节点。除了根节点外,每个子节点可以分为多个不相交的子树。


树分为二叉树,平衡树,红黑树等。


在Java语言中,讨论和使用最多的是二叉树。


二叉树(binary tree)是每个结点不超过2的有序树(tree),具有如下特点:


每个结点最多有两颗子树,结点的度最大为2。左子树和右子树是有顺序的,次序不能颠倒。即使某结点只有一个子树,也要区分左右子树。


适用场景:


二叉树添加,删除元素都很快,并且在查找方面也有很多的算法优化,所以,二叉树既有链表的好处,也有数组的好处,是两者的优化方案,在处理大批量的动态数据方面具有得天独厚的优势。


扩展:


二叉树有很多扩展的数据结构,比如平衡二叉树、红黑树、B+树等。


这些数据结构在二叉树的基础上衍生了很多的功能,在实际应用中被广泛使用。


比如MySQL数据库索引结构用的是B+树,HashMap的底层源码中用到了红黑树。这些二叉树的功能强大,但算法比较复杂,想学习的话需要花时间深入,本文限于篇幅不再一一展开。


图(Graph)


(了解即可)


图是由结点的有穷集合V和边的集合E组成。其中,为了与树形结构加以区别,在图结构中常常将结点称为顶点,边是顶点的有序偶对,若两个顶点之间存在一条边,就表示这两个顶点具有相邻关系。


按照顶点指向的方向可分为无向图和有向图。


图是一种比较复杂的数据结构,有着非常复杂和高效的算法,这里不做展开,读者有兴趣可以自己学习深入


堆(Heap)


堆是一种比较特殊的数据结构,可以被看做一棵树的数组对象,具有以下的性质:


堆中某个节点的值总是不大于或不小于其父节点的值;


堆总是一棵完全二叉树。


将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。


常见的堆有二叉堆、斐波那契堆等。


堆的定义如下:n个元素的序列{k1,k2,ki,…,kn}当且仅当满足下关系时,称之为堆。


(ki <= k2i,ki = k2i,ki >= k2i+1), (i = 1,2,3,4…n/2),满足前者的表达式的成为小顶堆,满足后者表达式的为大顶堆,这两者的结构图可以用完全二叉树排列出来,示例图如下:


因为堆有序的特点,一般用来做数组中的排序,称为堆排序。


散列表(Hash)


散列表,也叫哈希表,是根据关键码和值 (Key和Value) 直接进行访问的数据结构。


哈希值(hashCode):是一个十进制整数,由系统随机给出(就是对象的地址值,是一个逻辑地址, 不是数据的实际存储地址。)


public class Demo02 {


public static void main(String【】 args) {


Layman layman = new Layman("layman",18);


/


public native int hashCode() : Object类中的方法,可以返回对象的哈希值(一个十进制整数)。


/


System.out.println(layman.hashCode()); //-1109720331


}


//Object类中toString()的源码


public String toString() {


return getClass().getName() + "@" + Integer.toHexString(hashCode());


}


}


@Data


@AllArgsConstructor


class Layman{


private String name;


private Integer age;


}


记录的存储位置=F(key)


散列表就是把Key通过算法函数F(哈希函数)转换成一个十进制整数,然后将该整数对数组长度进行取余,取余的结果当作数组下标,将value存储在以该数字为下标的数组空间中。


这种存储空间充分利用数组的查找优势来查找元素,所以查找速度快。


哈希表应用广泛,比如Java中有些集合类(HashMap,HashTable)就是借鉴了哈希原理构造的,查找元素时非常方便。


然而,因为哈希表是基于数组衍生的数据结构,所以增删元素慢。出于解决增删元素慢的问题,哈希表的底层采用数组+链表(数组查询快,链表增删快)。


JDK1.8之前,哈希表底层采用数组+链表实现,即使用链表处理冲突,同一hash值的数据都存储在一个链表里。但是当hash值相等的元素较多时,通过key值依次查找的效率较低。JDK1.8中,哈希表存储采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。

相关文章
|
2月前
|
存储 Oracle Java
java零基础学习者入门课程
本课程为Java零基础入门教程,涵盖环境搭建、变量、运算符、条件循环、数组及面向对象基础,每讲配示例代码与实践建议,助你循序渐进掌握核心知识,轻松迈入Java编程世界。
315 0
|
3月前
|
Java
java入门代码示例
本文介绍Java入门基础,包含Hello World、变量类型、条件判断、循环及方法定义等核心语法示例,帮助初学者快速掌握Java编程基本结构与逻辑。
421 0
|
4月前
|
安全 Java 数据库连接
2025 年最新 Java 学习路线图含实操指南助你高效入门 Java 编程掌握核心技能
2025年最新Java学习路线图,涵盖基础环境搭建、核心特性(如密封类、虚拟线程)、模块化开发、响应式编程、主流框架(Spring Boot 3、Spring Security 6)、数据库操作(JPA + Hibernate 6)及微服务实战,助你掌握企业级开发技能。
664 3
|
6月前
|
Java API 微服务
2025 年 Java 从入门到精通学习笔记全新版
《Java学习笔记:从入门到精通(2025更新版)》是一本全面覆盖Java开发核心技能的指南,适合零基础到高级开发者。内容包括Java基础(如开发环境配置、核心语法增强)、面向对象编程(密封类、接口增强)、进阶技术(虚拟线程、结构化并发、向量API)、实用类库与框架(HTTP客户端、Spring Boot)、微服务与云原生(容器化、Kubernetes)、响应式编程(Reactor、WebFlux)、函数式编程(Stream API)、测试技术(JUnit 5、Mockito)、数据持久化(JPA、R2DBC)以及实战项目(Todo应用)。
388 5
|
3月前
|
前端开发 Java 数据库连接
帮助新手快速上手的 JAVA 学习路线最详细版涵盖从入门到进阶的 JAVA 学习路线
本Java学习路线涵盖从基础语法、面向对象、异常处理到高级框架、微服务、JVM调优等内容,适合新手入门到进阶,助力掌握企业级开发技能,快速成为合格Java开发者。
571 3
|
4月前
|
NoSQL Java 关系型数据库
Java 从入门到进阶完整学习路线图规划与实战开发最佳实践指南
本文为Java开发者提供从入门到进阶的完整学习路线图,涵盖基础语法、面向对象、数据结构与算法、并发编程、JVM调优、主流框架(如Spring Boot)、数据库操作(MySQL、Redis)、微服务架构及云原生开发等内容,并结合实战案例与最佳实践,助力高效掌握Java核心技术。
438 1
|
4月前
|
Java 测试技术 API
Java IO流(二):文件操作与NIO入门
本文详解Java NIO与传统IO的区别与优势,涵盖Path、Files类、Channel、Buffer、Selector等核心概念,深入讲解文件操作、目录遍历、NIO实战及性能优化技巧,适合处理大文件与高并发场景,助力高效IO编程与面试准备。
|
4月前
|
Java 编译器 API
Java Lambda表达式与函数式编程入门
Lambda表达式是Java 8引入的重要特性,简化了函数式编程的实现方式。它通过简洁的语法替代传统的匿名内部类,使代码更清晰、易读。本文深入讲解Lambda表达式的基本语法、函数式接口、方法引用等核心概念,并结合集合操作、线程处理、事件回调等实战案例,帮助开发者掌握现代Java编程技巧。同时,还解析了面试中高频出现的相关问题,助你深入理解其原理与应用场景。
|
3月前
|
Java API 数据库
2025 年最新 Java 实操学习路线,从入门到高级应用详细指南
2025年Java最新实操学习路线,涵盖从环境搭建到微服务、容器化部署的全流程实战内容,助你掌握Java 21核心特性、Spring Boot 3.2开发、云原生与微服务架构,提升企业级项目开发能力,适合从入门到高级应用的学习需求。
774 0
|
4月前
|
前端开发 Java 数据库
Java 项目实战从入门到精通 :Java Web 在线商城项目开发指南
本文介绍了一个基于Java Web的在线商城项目,涵盖技术方案与应用实例。项目采用Spring、Spring MVC和MyBatis框架,结合MySQL数据库,实现商品展示、购物车、用户注册登录等核心功能。通过Spring Boot快速搭建项目结构,使用JPA进行数据持久化,并通过Thymeleaf模板展示页面。项目结构清晰,适合Java Web初学者学习与拓展。
359 1

热门文章

最新文章