目录
- 好文章借鉴
- 栈和队列
- 字符串
- String类型加入ArrayList后,如果对于加入的字符串进行更改,ArrayList中的字符串对象也会被更改吗?还是保持不变?
- String&StringBuilder的使用
- HashMap、TreeMap、LinkedHashMap的区别
- HashMap、LinkedHashMap和TreeMap和ConcurrentHashMap底层实现
- Map用法
- HashSet、TreeSet、LinkedHashSet的区别
- Set用法
- ArrayList的用法
- LinkedList的用法
- 创建数组
- 求数的幂
- 求两数的绝对值
- 求两数的最大值
- Arrays 对于数组进行操作
- Collections
- 报错 cannot find symbol [in __Driver__.java]
- 怎么将小数点保留2位小数(如果题目没有特殊说明,就是直接截取2位小数)
- 计算平方根(double类型)
- 获取输入
堆(优先队列)
好文章借鉴
Java集合中List,Set以及Map等集合体系详解(史上最全)
//小顶堆(从小到大) 使用Lambda表达式实现内部排列的写法(写法一,最便捷)
PriorityQueue<Integer> pri = new PriorityQueue<Integer>((o1, o2)->o1 - o2);
pri.add(1);//加入堆
pri.poll();//弹出堆顶元素
pri.size();//堆的元素数量
pri.add(22);
pri.add(3);
while(pri.size() > 0) {
System.out.println(pri.poll());
}
PriorityQueue<Integer> pri = new PriorityQueue<Integer>(new Comparator<Integer>(){
@Override
public int compare(Integer o1,Integer o2){
return o1 - o2;//实现小顶堆
}
});
结果
3
22
//大顶堆(从大到小)
PriorityQueue<Integer> pri = new PriorityQueue<Integer>((o1,o2)->o2 - o1);
pri.add(1);//加入堆
pri.poll();//弹出堆顶元素
pri.size();//堆的元素数量
pri.add(22);
pri.add(3);
while(pri.size() > 0) {
System.out.println(pri.poll());
}
22
3
如果PriorityQueue排序对象非Integer基本数据类型,比如像int[]这种类型,按照先按照int[]数组的第2个数进行从小到大排序,否则再按照int[]数组的第3个数进行从小到大排序,最后按照int[]数组的第1个数进行从小到大排序,排序写法
PriorityQueue<int[]> pri = new PriorityQueue<int[]>((o1,o2)-> {
if (o1[1] != o2[1]) {
return o1[1] - o2[1];
} else {
if (o1[2] != o2[2]) {
return o1[2] - o2[2];
} else {
return o1[0] - o2[0];
}
}
});
栈和队列
在Java中
- LinkedList通常可以作为栈使用
- ArrayDeque通常作为队列使用
- ProporityQueue用来实现堆
java堆栈队列api
//队首出队,队尾进队
//栈(LinkedList)的API
LinkedList<Integer> stack = new LinkedList();//创建新栈
stack.push(1);//向栈顶压入元素1(注意这里一定要用push,而不能用offer、add这种API,不然这又变成了队列)
stack.pop();//从栈顶弹出元素(会返回该元素)并删除
stack.peek();//从栈顶查看元素不弹出(不删除) 等同于getFirst()
stack.isEmpty();//判断栈是否为空
stack.size();//判断此时栈内大小
//队列(Deque)的API(记住队尾入队,队首出队,ArrayDeque对象中下标为0的永远是队首)
Deque<String> queue = new ArrayDeque<>();
queue.offer("a");//向队列尾部添加元素 等同于add()、addLast()都是在队尾添加元素, (注意addFirst()是往队首增加元素)
queue.poll();//向队列头部弹出元素(会返回该元素)并删除 等同于remove()、removeFirst()
queue.peek();//返回队首元素(不删除)等同于getFirst()
queue.isEmpty();//判断deque是否为空
queue.size();//判断此时队列长度
queue.getLast()//双端队列,获取队尾元素
queue.removeFirst();//双端队列,删除队首元素
ArrayDeuqe和LinkedList之间的比较:
If you need add/remove of the both ends, ArrayDeque is significantly better than a linked list. Random access each element is also O(1) for a cyclic queue.
The only better operation of a linked list is removing the current element during iteration.
如果需要对两端进行添加/删除,ArrayDeque明显优于链表。对于循环队列,随机访问每个元素也是O(1)。
更好的链表操作是在迭代期间删除当前元素。
做了以下实验:
测试设置考虑:
每个测试对象是一个500字符的字符串。每个String都是内存中的不同对象。
测试数组的大小将在测试期间变化。
对于每个数组大小/队列实现组合,将运行100个测试,并计算每个测试的平均时间。
每个测试都用所有对象填充每个队列,然后将它们全部删除。
以毫秒为单位测量时间。
测试结果:
在10,000个元素以下,LinkedList和ArrayDeque测试的平均水平都低于1毫秒。
随着数据集越来越大,ArrayDeque和LinkedList之间的平均测试时间的差异也越来越大。
在9,900,000个元素的测试大小下,LinkedList方法比ArrayDeque方法多花了大约165%的时间。
综上,如果LinkedList和ArrayDeque具备的API都可以实现功能,优先使用ArrayDeque.
字符串
字符串获取某个下标的字符charAt
- 通过charAt 遍历字符串 通过下标返回一个char类型对象,可以进行便利操作
String str = "123";
for(int i = 0;i < str.length();i++){
System.out.println(str.charAt(i));
}
字符串获取子串 substring
substring函数是Java字符串类的一个内置方法,用于从给定的字符串中获取一个子字符串。这个方法有两种签名,一种是只传入一个开始索引,另一种是传入一个开始索引和一个结束索引。例如:
String s = "Hello World";
String sub1 = s.substring(6); // sub1 = "World"
String sub2 = s.substring(0, 5); // sub2 = "Hello"
这个方法的含义是:
- substring(int beginIndex) 返回从指定的开始索引beginIndex开始到字符串的最后一个字符的子字符串。例如:“Chaitanya”.substring(2) 返回 “aitanya”。开始索引是包含在子字符串中的,所以索引为2的字符也被包括在内。
- substring(int beginIndex, int endIndex) 返回从指定的开始索引beginIndex开始到指定的结束索引endIndex减一的子字符串。例如:“Beginnersbook”.substring(9, 13) 返回 “book”。开始索引是包含在子字符串中的,但结束索引是不包含在子字符串中的,所以索引为13的字符被排除在外。
for(int i = 0;i < str.length();i++){
System.out.println(str.substring(i,i + 1));
}
String与字符数组之间转换
- String到字符数组
//方法一
String s = "abc";
char[] chs = s.toCharArray();
- 字符数组到String
//方法二
char[] chs = {'a','b','c'};
String s = new String(chs);
- 字符串到字符数组后进行遍历
String s = "sdsds";
char[] chs = s.toCharArray();
for(char c : chs){
System.out.println(c);
}
String类型加入ArrayList后,如果对于加入的字符串进行更改,ArrayList中的字符串对象也会被更改吗?还是保持不变?
public static void main(String[] args) {
ArrayList<String> arr = new ArrayList<>();
String s = "before";
arr.add(s);
System.out.println("改变前:" + arr);
s = "after";
System.out.println("改变后:" + arr);
}
保持不变,结果如下:
改变前:[before]
改变后:[before]
理由如下:
如果您对加入 ArrayList 的字符串进行更改,ArrayList 中的字符串对象不会被更改,而是保持不变。这是因为 String 类是不可变的,也就是说,一旦创建了一个 String 对象,它的值就不能被修改。当您对一个 String 对象赋予一个新的值时,实际上是创建了一个新的 String 对象,并让原来的对象指向它。而 ArrayList 中存储的是对象的引用,所以当您更改字符串时,ArrayList 中的引用并没有改变,仍然指向原来的对象。
String&StringBuilder的使用
StringBuilder增加和删除元素
根据网上的信息,StringBuilder是Java中的一个类,用于创建和修改可变的字符串。StringBuilder类提供了一些方法来增加和删除元素,例如:
append方法,用于在字符串的末尾添加一个元素或者一个子字符串。例如:
StringBuilder sb = new StringBuilder("Hello");
sb.append(' '); // sb = "Hello "
sb.append("World"); // sb = "Hello World"
insert方法,用于在字符串的指定位置插入一个元素或者一个子字符串。例如:
StringBuilder sb = new StringBuilder("Hello");
sb.insert(5, ' '); // sb = "Hello "
sb.insert(6, "World"); // sb = "Hello World"
delete方法,用于删除字符串中指定范围的元素或者子字符串。例如:
StringBuilder sb = new StringBuilder("Hello World");
sb.delete(5, 6); // sb = "HelloWorld"
sb.delete(5, 11); // sb = "Hello"
deleteCharAt方法,用于删除字符串中指定位置的元素。例如:
StringBuilder sb = new StringBuilder("Hello World");
sb.deleteCharAt(5); // sb = "HelloWorld"
sb.deleteCharAt(4); // sb = "HellWorld"
StringBuilder获取长度
StringBuilder sb = new StringBuilder();
sb.length();
HashMap、TreeMap、LinkedHashMap的区别
HashMap是无序排列(不会按照插入顺序,或者按照某种顺序)。适合只需要快速访问的map的场景。
LinkedHashMap会按照插入顺序存储元素,适合读取按照插入顺序的场景。
TreeMap会按照默认顺序排序(比如说,数字按照从小到大的顺序,字符按照字典的顺序)
HashMap、LinkedHashMap和TreeMap和ConcurrentHashMap底层实现
Map用法
//1.初始化
HashMap<String,Integer> map = new HashMap<>();
//2.插入存入新值
System.out.println("插入新值:'测试',1");
map.put("测试",1);
//3.查找 获取新值
//(1).get查找
System.out.println("按照'测试'获取对应值:" + map.get("测试"));
if(map.get("未找到") == null){
System.out.println("按照'测试'获取对应值,没有存入键返回null");
}
//(2).getOrDefault查找
System.out.println("如果根据键1查找不到对应值,则返回默认值-1,map.getOrDefault('1',-1)输出结果:" + map.getOrDefault("1",-1));//如果根据键1查找不到对应值,则返回默认值-1
//4.判断某个元素是否存在 其实可以用get来判断,如果不存在则返回null
System.out.println("查找是否存在'测试'这个键:"+map.containsKey("测试"));
//5.删除元素
map.remove("测试");//根据key值删除
System.out.println("删除remove后查找是否存在'测试'这个键:"+map.containsKey("测试"));
//6.长度
map.put("测试",1);
System.out.println("重新增加'测试':1这个数据,长度为:" + map.size());
//7.循环遍历
//7.1增强for循环
for(String key : map.keySet()){//注意为keySet,不是entrySet
System.out.println("key:" + key + ",对应value:" + map.get(key));
}
//7.2Iterator遍历
Iterator it = linkedHashMap.entrySet().iterator();//注意为entrySet,不是keySet
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
System.out.println("key:" + entry.getKey() + " value:" + entry.getValue());
}
//8.对于HashMap对象,在循环其元素时,遇到特定键将对应键值对删除,但是又不影响整体的遍历
/**
* 对于HashMap对象,在循环其元素时,遇到特定键将对应键值对删除,但是又不影响整体的遍历
* 是使用Iterator来遍历HashMap对象,并使用Iterator的remove()方法来删除特定元素。
* 有一个HashMap<String, Integer>,存储了一些字符串和它们的长度,你想要删除其中键为"Java"的键值对
* @param args
*/
public static void main(String[] args) {
// 创建一个HashMap<String, Integer>对象
HashMap<String, Integer> map = new HashMap<> ();
map.put ("Hello", 5);
map.put ("Java", 4);
map.put ("World", 5);
map.put ("Bing", 4);
// 获取一个Iterator对象
Iterator<Map.Entry<String,Integer>> iterator = map.entrySet().iterator();
// 遍历HashMap对象
while(iterator.hasNext()){
// 获取当前元素
Map.Entry<String,Integer> entry = iterator.next();
// 获取当前元素的值
String key = entry.getKey ();
// 判断是否等于4
if ("Java".equals(key)) {
// 删除当前元素
iterator.remove ();
}
}
// 打印最终的HashMap对象
System.out.println (map);
}
为TreeMap对象设置一个Comparator外部排序函数,实现逆序排序(从大到小)下面以Integer对象举例
TreeMap<Integer,String> map = new TreeMap(new Comparator<Integer>(){
@Override
public int compare(Integer o1,Integer o2){
return o2 - o1;// o2 - o1逆序排序; 如果是o1 - o2是正序排序,正序就是越小越在前面
}
});
map.put(12,"Str12");
map.put(78,"Str78");
for(Integer i : map.keySet()){
System.out.println(i);
}
//第2种遍历的写法
// Iterator iter = map.entrySet().iterator();
// while(iter.hasNext()){
// Map.Entry<Integer,String> entry = (Map.Entry<Integer, String>) iter.next();
// System.out.println(entry.getKey() + " " + entry.getValue());
// }
结果
78 Str78
12 Str12
为TreeSet对象设置一个Comparator外部排序函数,实现正序排序(从小到大)下面以Integer对象举例
TreeSet<Integer> set = new TreeSet<Integer>(new Comparator<Integer>(){
@Override
public int compare(Integer o1,Integer o2){
return o1 - o2;// 如果是o1 - o2是正序排序; o2 - o1逆序排序
}
});
set.add(588);
set.add(1);
Iterator iter = set.iterator();
while(iter.hasNext()){
System.out.println(iter.next());
}
结果
1
588
为TreeSet中自定义对象设置Comparator外部排序同时实现Comparable接口,实现正序排序(从小到大)下面以Person自定义对象举例:
import java.util.Comparator;
import java.util.TreeSet;
public class Person implements Comparable<Person>{//注意这里排序Person,泛型也是Person
public Integer age;
public Person(Integer age){
this.age = age;
}
@Override
public int compareTo(Person comparePerson){
return age - comparePerson.age;//正序,越小越在前
}
public static void main(String[] args) {
Person person2 = new Person(13);
Person person = new Person(12);
TreeSet<Person> set = new TreeSet<>(new Comparator<Person>(){
@Override
public int compare(Person p1,Person p2){
return p2.age - p1.age;//Comparator的优先级高于Comparable,并且第一个参数-第2个参数是正序
}
});
set.add(person2);
set.add(person);
for(Person p : set){
System.out.println(p.age);
}
}
}
HashSet、TreeSet、LinkedHashSet的区别
HashSet是无序排列(不会按照插入顺序,或者按照某种顺序)。适合只需要快速访问的set的场景。
- LinkedHashMap<Integer, String> map = new LinkedHashMap<>();
LinkedHashSet会按照插入顺序存储元素,适合读取按照插入顺序的场景。
// 创建一个按照插入顺序排序的LinkedHashMap
LinkedHashMap<Integer, String> map = new LinkedHashMap<>();
// 添加四个键值对
map.put(1, "A");
map.put(2, "B");
map.put(3, "C");
map.put(4, "D");
// 打印LinkedHashMap的键值对
System.out.println(map); // 输出 {1=A, 2=B, 3=C, 4=D}
// 访问键为2的键值对
map.get(2);
// 打印LinkedHashMap的键值对
System.out.println(map); // 输出 {1=A, 3=C, 4=D, 2=B}
// 访问键为4的键值对
map.get(4);
// 打印LinkedHashMap的键值对
System.out.println(map); // 输出 {1=A, 3=C, 2=B, 4=D}
{1=A, 2=B, 3=C, 4=D}
{1=A, 2=B, 3=C, 4=D}
{1=A, 2=B, 3=C, 4=D}
- LinkedHashMap<Integer, String> map = new LinkedHashMap<>(16, 0.75f, true);
LinkedHashSet会按照插入顺序存储元素,适合读取按照插入顺序的场景。
// 创建一个按照访问顺序排序的LinkedHashMap
LinkedHashMap<Integer, String> map = new LinkedHashMap<>(16, 0.75f, true);
// 添加四个键值对
map.put(1, "A");
map.put(2, "B");
map.put(3, "C");
map.put(4, "D");
// 打印LinkedHashMap的键值对
System.out.println(map); // 输出 {1=A, 2=B, 3=C, 4=D}
// 访问键为2的键值对
map.get(2);
// 打印LinkedHashMap的键值对
System.out.println(map); // 输出 {1=A, 3=C, 4=D, 2=B}
// 访问键为4的键值对
map.get(4);
// 打印LinkedHashMap的键值对
System.out.println(map); // 输出 {1=A, 3=C, 2=B, 4=D}
{1=A, 2=B, 3=C, 4=D}
{1=A, 3=C, 4=D, 2=B}
{1=A, 3=C, 2=B, 4=D}
TreeSet会按照默认顺序排序(比如说,数字按照从小到大的顺序,字符按照字典的顺序)
//从小到大排序
TreeMap<Integer,Integer> map = new TreeMap<>((o1,o2)->{
return o1 - o2;
});
//从大到小排序
TreeMap<Integer,Integer> map = new TreeMap<>((o1,o2)->{
return o1 - o2;
});
//lambda表达式按照字典序排序
TreeMap<String,Integer> map = new TreeMap<>((o1,o2)-> (o1.compareTo(o2)));
map.put("boy",2);
map.put("apple",1);
for (Map.Entry<String,Integer> m : map.entrySet()){
System.out.println(m.getKey());
}
Set用法
public static void main(String[] args){
//创建set对象
Set<Integer> set = new HashSet<>();
//1.向set中加入元素
set.add(1);
System.out.println("加入值为1的元素之后:" + set);
//2.查找set对象
System.out.println("是否存在值为1的元素:" + set.contains(1));
//3.set对象的长度 size
set.add(1);
set.add(3);
System.out.println("加入值为1,3的元素之后:" + set);
System.out.println("现在set对象的长度:" + set.size());
//4.删除set对象
set.remove(1);
System.out.println("删除元素1之后:" + set);
//5.判断集合是否为空
System.out.println("set对象是否为空:" + set.isEmpty());
//6.清空集合
set.clear();
System.out.println("清空后,set对象是否为空:" + set.isEmpty());
}
ArrayList的用法
1. 遍历方式
import java.util.*;
public class Test{
public static void main(String[] args){
List<String> list = new ArrayList<String>();
list.add("Hello");
list.add("World");
list.add("Hello");
//第一种方法: for-each遍历 list
for(String str : list){ //同for(int i = 0;i<list.size();i++)
System.out.println(str);
}
//第二种方法: 把链表变为数组相关的内容进行遍历
String[] strArray = new String[list.size()];
list.toArray(strArray);
for(String str: strArray){
System.out.println(strArray[i]);
}
//第三种方法: 使用迭代器
//第三种方法不用担心在遍历过程中超过集合的长度
Iterator<String> ite = list.iterator();
while(ite.hasNext()){
System.out.println(ite.next());
}
}
}
2. [插入新值]
- 在尾部插入数据
3.修改值(根据下标)
ArrayList<String> list = new ArrayList<>();
list.add("Oscar");
list.set(0,"Jack");//第一个参数要修改的下标 第二个参数是要修改的值(将Oscar 换成 jack)
4.获取列表末尾元素
ArrayList<String> list = new ArrayList<>();
list.add("Oscar");
list.add("Jack");
//获取末尾元素
System.out.println(list.get(list.size() - 1));
Jack
5.对于ArrayList对象,在循环其元素时,遇到特定元素将其删除,
/**
* 对于ArrayList对象,在循环其元素时,遇到特定元素将其删除,但是又不影响整体的循环遍历,试写出对应java代码
* 使用Iterator来遍历ArrayList对象,并使用Iterator的remove()方法来删除特定元素。
* 例如,假设你有一个ArrayList<String>,存储了一些字符串,你想要删除其中包含"Java"的字符串
* @param args
*/
public static void main(String[] args) {
// 创建一个ArrayList<String>对象
ArrayList<String> list = new ArrayList<> ();
list.add ("Hello");
list.add ("Java");
list.add ("World");
list.add ("Bing");
// 获取一个Iterator对象
Iterator<String> iterator = list.iterator ();
// 遍历ArrayList对象
while (iterator.hasNext ()) {
// 获取当前元素
String element = iterator.next ();
// 判断是否包含"Java"
if (element.contains ("Java")) {
// 删除当前元素
iterator.remove ();
}
}
// 打印最终的ArrayList对象
System.out.println (list);
}
LinkedList的用法
1.获取末尾元素
LinkedList<Integer> list = new LinkedList();//创建新栈
list.add("Oscar");
list.add("Jack");
//获取末尾元素
System.out.println(list.getLast());
Jack
2.删除末尾元素
LinkedList<String> list = new LinkedList();//创建新栈
list.add("Oscar");
list.add("Jack");
list.removeLast();//删除末尾元素
//获取末尾元素
System.out.println(list.getLast());
Oscar
如果没有成功删除末尾元素,末尾元素就应该是Jack;现在展示的是Oscar,则说明末尾元素删除成功。
创建数组
int[] arr1 = new int[10];//注意最后没有()
int[] arr2 = {1,2,3};
求数的幂
求2的5次方
//使用pow这个API,但是返回数据类型为double,所以需要用int进行格式转换
(int)Math.pow(2,5);
求两数的绝对值
int a = 5,b = 10;
Math.abs(a - b);
求两数的最大值
int a = 5,b = 10;
Math.max(a - b);
Arrays 对于数组进行操作
Arrays将数组转化为 List对象
Integer[] a = new Integer[]{1,2,3};
List<Integer> arrList = Arrays.asList(a);//这里的数组对象必须为对象,也就是如果是int[]就不能转换成为List列表了
输出:ArrayList中{1,2,3}
int[] arr = {3,2,4};
Arrays.sort(arr);
for(int i : arr){
System.out.println(i);
}
//2,3,4
int[] in = new int[2];
Arrays.fill(in,0);//将in中的所有元素
for(int i : in){
System.out.println(i);
}
//0 0
比较两个数组内容是否相等
int[] tar = {1,2};
int[] com = {1,2};
Arrays.equals(tar,com);
Collections
List<Integer> result = new ArrayList();
//将ArrayList排序 (默认从小到大顺序)
Collections.sort(result);
//将ArrayList排序 (从大到小顺序)
Collections.sort(result,(n1,n2) -> n2 - n1);
//将ArrayList倒序
Collections.reverse(result);
报错 cannot find symbol [in Driver.java]
leetcode报错error: cannot find symbol [in Driver.java]
主函数名字不一样导致编译出错。把主函数改过来就好了
怎么将小数点保留2位小数(如果题目没有特殊说明,就是直接截取2位小数)
//小数是num,类型double
可以通过System.out.printf(“%.2f”,num);//直接截取小数点后2位小数
//通过BigDecimal可以实现小数点取舍进位
//四舍五入
double sum = 0;
BigDecimal big = new BigDecimal(sum);
//保留2位小数,四舍五入
doule sum = big.setScale(2,BigDecimal.ROUND_HALF_UP).doubleValue();
计算平方根(double类型)
使用 double sqrt(double)
double num = 0;
num = Math.sqrt(num);
获取输入
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
String s = bf.readLine();//读取整行数据(直到换行符)