Java刷题时常用的标准库数据结构和相应算法
一、线性表(广义的数组)
在算法题中,我们一般使用到的线性表一般有两种,且它们的优缺点如下:
- 数组
- 优点:可以使用
[]运算符进行随机读写 - 缺点:数组大小固定,不能动态添加数据
- 优点:可以使用
- List对象
- 优点:可以动态添加数据
- 缺点:读写数据需要使用
get(int index)和set(int index, Object object),和数组相比比较麻烦
1. 数组
这里数组的主要用法和c++比较类似,这里主要写一下一些特殊的操作以及Arrays工具类提供的一些方法。
一维数组的定义和初始化
① 直接指定固定大小:
int[] arr = new int[n];
则开辟的空间会填充上默认值:
- 数值类型填充
0 boolean类型填充false- 对象类型填充
null
② 定义时进行初始化
int[] arr = new int[]{1, 2, 3, 4, 5};
二维数组的定义和初始化
① 和一维数组一样直接给定两个维度的大小(行数和列数):
int[][] matrix = new int[m][n];
② 和c++类似,二维数组也可以像c++中的type** matrix一样,先给第一个维度分配空间,然后再为第二个维度分配不同的空间,例如下面的代码分配下三角矩阵:
int n = 5;
int[][] matrix = new int[n][];
for (int i = 0; i < n; i++) {
matrix[i] = new int[i + 1];
}
打印展示:

Arrays工具类的一些常用方法
在Java中原生数组实际上并不是完全的面向对象的,对于List对象希望进行某项操作只需要使用.+方法即可,但数组类型本身却没有带有这些操作,因而Arrays工具类填补了这部分的空白。
① Arrays.fill()
Arrays.fill有两个常见的使用:
Arrays.fill(int[] array, int value)Arrays.fill(int[] array, int start, int end, int val)
这个函数是用于填充数组的,第一个参数是数组,第二个参数是填充的值,而第二种用法规定了填充的起止下标:[start, end)。
② Arrays.sort()
排序函数,一般也有两种参数填充方法:
Arrays.sort(int[] array)Arrays.sort(Object[] array, Comparator c)tips 只有对象数组才能使用这种方式
第一种方式是按照默认的方式进行排序,数字类型按从小到大排,字符串类型按字典序排,而第二种方式中填写的第二个参数是用于改变默认的排序规则的,例如这里我希望从大到小排序():
Integer[] arr = new Integer[]{1, 2, 3, 4, 5};
Arrays.sort(arr, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
// 或者使用下面的更加简洁的lambda表达式
Arrays.sort(arr, (num1, num2) -> num2 - num1);
由于添加Comparator对象的这种方式第一个参数只能是对象数组,因此我这里不再使用int[]而是改为了使用Integer[]。
这里就会出现一个这样的需求:如果我原来的类型是
int[],那么如何转换为Integer[]呢?这里我们可以使用下面的代码进行转化(其他的例如boolean到Boolean也可以按照如下方式转化):int[] arrOrigin = new int[]{1, 2, 3, 4, 5};
Integer[] arr = (Integer[]) Arrays.stream(arrOrigin).boxed().toArray();
即将原数组转为stream对象后调用boxed方法得到
Stream<Integer>,最后再调用Stream类中的toArray()成员方法即可从流重新转为数组。而Integer[]想要转为int[]则需要调用Stream类的mapToInt(Integer::intValue).toArray()。
③ Arrays.toString(int[] array)
这个方法可以得到数组完整的内容,而如果直接使用arr.toString()只会得到对象的地址等无用信息。
④ Arrays.asList(int[] array)
将数组转为List对象:
Integer[] arr = new Integer[]{1, 2, 3, 4, 5};
List<Integer> list = Arrays.asList(arr);
此外这个函数还可以分散填写各个List对象初始元素的值:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
⑤ 反转数组
这里可以使用工具类反转的数组也仅限是对象数组(非对象数组可能只能手写反转算法了),参考代码如下:
String[] strArr = new String[]{"e", "d", "c", "b", "a"};
Collections.reverse(Arrays.asList(strArr));
输出结果:
[a, b, c, d, e]
另外还有一些例如Arrays.copyOf等方法不太常用,这里不再详细介绍。
2. List接口容器
对象的构建
实现类一般使用ArrayList(此外还有LinkedList,但不常用),构造对象方式如下:
List<Integer> list = new ArrayList<>();
读写和插入删除数据
读:E get(int index)
写:E set(int index, E element)
插入:boolean add(E e)和void add(int index, E element)
删除:boolean remove(Object o)和E remove(int index)
排序
使用List的接口方法sort(Comparator c)(数字从大到小排):
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
list.sort((num1, num2) -> num2 - num1);
输出:
[5, 4, 3, 2, 1]
或者也可以使用Collections.sort(List l, Comparator c),可以达到相同的效果。
反转数组
// Collections工具类静态方法:Collections.reverse(List list)
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Collections.reverse(list);
二、字符串
以下api如果没有标注则默认为String类成员方法。
| 操作 | api | 说明 |
|---|---|---|
| 获取长度 | int length() |
|
| 获取下标对应字符 | char charAt(int index) |
|
| 转换为字符数组 | char[] toCharArray() |
|
| 取子串 | String substring(int beginIdx, int endIdx) |
其中endIdx是可选的 |
| 转为int等数字类型 | 静态方法 Integer.parseInt(String str) |
这是int类型的,其他类型以此类推 |
| 数值类型转为字符串 | 静态方法 String.valueOf(T val) |
这里的T可以是int、double等类型 |
| 按分隔符切分字符串 | String[] split(String regex) |
填入的是正则表达式 |
| 反转字符串 | StringBuilder成员方法 string reverse() |
需要借助StringBuilder |
这些容器类基本都会包含有获取元素数量(
size())和判断是否为空(empty()或isEmpty())等相同的方法,因此后面的api表格只列出该类特有的操作。
三、Map和Set
1. Map
Map这里一般使用的实现为HashMap,少数需要按照键进行排序时使用到TreeMap,构造对象如下:
Map<String, String> map = new HashMap<>();
常用操作和api:
| 操作 | api |
|---|---|
| 读 | V get(Object key) |
| 写 | V put(K key, V value) |
| 是否包含key | boolean containsKey(Object key) |
| 是否包含value | boolean containsValue(Object value) |
遍历Map:
// 1. 使用forEach + lambda表达式(推荐)
map.forEach((key, value)-> {
...
});
// 2. 使用for结合keySet()
for (String key : map.keySet()) {
String value = map.get(key);
...
}
2. Set
和Map类似,这里Set的实现一般也选择HashSet,少数需要按照键进行排序时使用到TreeSet,构造对象如下:
Set<String> set = new HashSet<>();
常用操作和api:
| 操作 | api |
|---|---|
| 插入元素 | boolean add(E e) |
| 删除元素 | boolean remove(Object o) |
| 是否包含元素 | boolean contains(Object o) |
同理,set也可以使用forEach+lambda以及增强for两种写法遍历元素。
四、栈Stack和队列Queue
1. 栈Stack
构造对象:
Stack<String> stack = new Stack<>();
常用操作和api:
| 操作 | api |
|---|---|
| 压栈 | E push(E item) |
| 弹栈 | E pop() |
| 查看栈顶元素 | E peek() |
2. 队列Queue
Queue是一个接口,一般实现类取ArrayDeque。构造对象代码如下:
Queue<String> queue = new ArrayDeque<>();
常用操作和api:
| 操作 | api |
|---|---|
| 入队 | boolean offer(E e) |
| 出队 | E poll() |
| 查看队首 | E peek() |
五、优先队列
构造对象:
PriorityQueue<Integer> heap = new PriorityQueue<>();
使用无参数构造函数时得到的是小顶堆,如果我们希望得到大顶堆则需要填入一个Comparator参数,如下为构造int类型大顶堆的方式:
PriorityQueue<Integer> heap = new PriorityQueue<>((o1, o2) -> o2 - o1);
其中填入的lambda表达式为新建Comparator匿名内部类的语法糖。
常用操作和api:
| 操作 | api |
|---|---|
| 入队 | boolean offer(E e) |
| 出队 | boolean poll(E e) |
| 查看队首(堆顶) | E peek() |
Java刷题时常用的标准库数据结构和相应算法的更多相关文章
- java刷题时常用容器详解
当初学java时,只是简单的把java基础知识过了一遍就跑去刷题了,很多知识都是在刷题的过程中慢慢加深理解的. 由于每次刷题时,刷到与容器有关的我基本上都跑去百度了,例如百度一下:java中List的 ...
- 牛客网Java刷题知识点之Map的两种取值方式keySet和entrySet、HashMap 、Hashtable、TreeMap、LinkedHashMap、ConcurrentHashMap 、WeakHashMap
不多说,直接上干货! 这篇我是从整体出发去写的. 牛客网Java刷题知识点之Java 集合框架的构成.集合框架中的迭代器Iterator.集合框架中的集合接口Collection(List和Set). ...
- 牛客网Java刷题知识点之Java 集合框架的构成、集合框架中的迭代器Iterator、集合框架中的集合接口Collection(List和Set)、集合框架中的Map集合
不多说,直接上干货! 集合框架中包含了大量集合接口.这些接口的实现类和操作它们的算法. 集合容器因为内部的数据结构不同,有多种具体容器. 不断的向上抽取,就形成了集合框架. Map是一次添加一对元素. ...
- JS、JAVA刷题和C刷题的一个很重要的区别
就是最近在做树方面的题时,发现JS和JAVA刷题和C刷题的一个很重要的区别就是传入null的区别 当遍历的时候,C传参数时可以传进去null的指针,因为递归进去,出来时,指针还是指着那个地方 但是JS ...
- 牛客网Java刷题知识点之为什么HashMap和HashSet区别
不多说,直接上干货! HashMap 和 HashSet的区别是Java面试中最常被问到的问题.如果没有涉及到Collection框架以及多线程的面试,可以说是不完整.而Collection框架的 ...
- 牛客网Java刷题知识点之为什么HashMap不支持线程的同步,不是线程安全的?如何实现HashMap的同步?
不多说,直接上干货! 这篇我是从整体出发去写的. 牛客网Java刷题知识点之Java 集合框架的构成.集合框架中的迭代器Iterator.集合框架中的集合接口Collection(List和Set). ...
- 牛客网Java刷题知识点之ArrayList 、LinkedList 、Vector 的底层实现和区别
不多说,直接上干货! 这篇我是从整体出发去写的. 牛客网Java刷题知识点之Java 集合框架的构成.集合框架中的迭代器Iterator.集合框架中的集合接口Collection(List和Set). ...
- 牛客网Java刷题知识点之垃圾回收算法过程、哪些内存需要回收、被标记需要清除对象的自我救赎、对象将根据存活的时间被分为:年轻代、年老代(Old Generation)、永久代、垃圾回收器的分类
不多说,直接上干货! 首先,大家要搞清楚,java里的内存是怎么分配的.详细见 牛客网Java刷题知识点之内存的划分(寄存器.本地方法区.方法区.栈内存和堆内存) 哪些内存需要回收 其实,一般是对堆内 ...
- 牛客网Java刷题知识点之HashMap的实现原理、HashMap的存储结构、HashMap在JDK1.6、JDK1.7、JDK1.8之间的差异以及带来的性能影响
不多说,直接上干货! 福利 => 每天都推送 欢迎大家,关注微信扫码并加入我的4个微信公众号: 大数据躺过的坑 Java从入门到架构师 人工智能躺过的坑 ...
随机推荐
- porcupine语音唤醒python实现
note it is not for arm pyaudio <= 3.6 version porcupine 3.5 3.6 not 3.7 code import struct import ...
- bit操作常见trick
x&(x-1)可以消去最右边的1, 如果判断一个数是否是2的指数的快捷方法,比如8,二进制位1000, 那么8&(8-1)为0,只要为0就是2的指数
- 话说C#程序员人手一个ORM
话说C#程序员人手一个ORM,确实没有必要再写ORM了,不过我的ORM并不是新的,是从DBHelper演化过来的,算是DBHelper魔改版. 目前流行的ORM有EF.Dapper.SqlSugar. ...
- python数据操作--8
转:https://www.tuicool.com/wx/MB7nieb 数据类型 整数, 浮点数, 字符串, 布林值(True,False) 列表(list), 不可变的列表 Tuple, 集合(没 ...
- C++ 微信多开
应用是如何判断多开 一.通过查找窗口标题或者类名来判断程序是否正在运行. 二.通过互斥对象确定程序是否运行,大多数软件都是使用CreateMutexW 判断多开的. 三.内存映射物理文件,控制多开. ...
- Java 继承01
继承 ●示例 class Person { public String name; Person(){ System.out.println("Person Constrctor...&qu ...
- 设置redis能远程访问
远程服务器,redis 安装在/opt下redis-4.0.10 cd redis-4.0.10 修改配置文件redis.conf配置文件:(注释掉bind:127.0.0.1)和修改保护模式为no ...
- markdown介绍和使用(超全建议收藏)
Markdown介绍 Markdown 其实在 2004 年就有了,不过之前一直很小众,这几年随着相关应用平台的发展,Markdown以其独到的优势迅速火起来了.Markdown编辑器使用一套格式标记 ...
- Nacos极简教程
简介 Nacos是服务发现与注册,服务配置中心. Nacos 具有如下特性: 服务发现和服务健康监测:支持基于DNS和基于RPC的服务发现,支持对服务的实时的健康检查,阻止向不健康的主机或服务实例发送 ...
- python开发: linux进程打开的文件数
1 #!/usr/bin/env python 2 #-*- coding:utf-8 -*- 3 4 ''' 统计linux打开的文件数 ''' 5 6 import os 7 import sys ...