next()
和 nextLine()
的区别:
方法 | 读取方式 | 读取范围 | 结束条件 | 是否跳过空格 |
---|---|---|---|---|
next() | 逐个读取单词 | 遇到空格、Tab 或换行就结束 | 读取一个单词 | 会跳过前面的空格 |
nextLine() | 读取整行 | 读取直到换行符 \n | 读取整个一行 | 不会跳过前面的空格 |
保留小数
默认格式输出:
double num = 3.14159;
System.out.printf("默认输出: %f%n", num);
保留小数:
double num = 3.14159;
System.out.printf("保留两位小数: %.2f%n", num);
System.out.printf("保留三位小数: %.3f%n", num);
哈希表
HashMap<K, V>
使用 键值对存储数据:
- 允许
null
作为键和值(Hashtable
不允许)。 - 非线程安全,适用于单线程环境,如果要在多线程环境下使用,需要使用
Collections.synchronizedMap()
或ConcurrentHashMap
。 - 基于哈希算法,查询效率很高(平均 O(1) 时间复杂度)。
示例
import java.util.HashMap;
public class Main {
public static void main(String[] args) {
// 创建 HashMap
HashMap<String, Integer> map = new HashMap<>();
// 添加键值对
map.put("苹果", 10);
map.put("香蕉", 5);
map.put("橙子", 8);
// 访问元素
System.out.println("苹果的价格: " + map.get("苹果")); // 10
// 遍历 HashMap
for (String key : map.keySet()) {
System.out.println(key + " 价格: " + map.get(key));
}
// 删除元素
map.remove("香蕉");
// 判断是否包含某个键或值
System.out.println("是否包含 '苹果': " + map.containsKey("苹果")); // true
System.out.println("是否包含 5: " + map.containsValue(5)); // false
// 获取大小
System.out.println("哈希表大小: " + map.size());
}
}
Hashtable
(线程安全,使用较少):
- 不允许
null
作为键或值。 - 线程安全(每个方法都用
synchronized
修饰)。 - 由于
synchronized
影响性能,现在推荐使用ConcurrentHashMap
代替Hashtable
。
示例
import java.util.Hashtable;
public class Main {
public static void main(String[] args) {
// 创建 Hashtable
Hashtable<String, Integer> table = new Hashtable<>();
// 添加元素
table.put("苹果", 10);
table.put("香蕉", 5);
table.put("橙子", 8);
// 遍历 Hashtable
for (String key : table.keySet()) {
System.out.println(key + " 价格: " + table.get(key));
}
}
}
ConcurrentHashMap
(适用于多线程)
多线程环境 下使用哈希表,推荐ConcurrentHashMap<K, V>
,它比 Hashtable
更高效:
import java.util.concurrent.ConcurrentHashMap;
public class Main {
public static void main(String[] args) {
// 创建 ConcurrentHashMap
ConcurrentHashMap<String, Integer> concurrentMap = new ConcurrentHashMap<>();
// 添加元素
concurrentMap.put("苹果", 10);
concurrentMap.put("香蕉", 5);
// 遍历
concurrentMap.forEach((k, v) -> System.out.println(k + " 价格: " + v));
}
}
总结:
HashMap
:适用于 单线程环境,允许null
,效率高。Hashtable
:适用于 多线程,不允许null
,但性能较差。ConcurrentHashMap
:推荐用于 多线程环境,比Hashtable
更高效。
多线程环境推荐 使用ConcurrentHashMap
。单线程环境,使用 HashMap
.
快读快写
BufferedReader
: 快读
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
String l=br.readLine();
System.out.println("输入的字符串"+l);
int num = Integer.parseInt(br.readLine());
System.out.println("你输入的数字:" + num);
PrintWriter
: 快写
import java.io.*;
public class FastOutput {
public static void main(String[] args) throws IOException {
PrintWriter out = new PrintWriter(System.out);
out.println("Hello, Fast Output!");
out.flush(); // 记得 flush,否则可能不会立即输出
}
}
HashSet
特点:
- 元素唯一
- 无序存储(元素的顺序可能与插入顺序不同)。
- 查询、插入、删除操作速度快(平均时间复杂度 O(1))。
基本使用
import java.util.HashSet;
import java.util.Iterator;
public class HashSetExample {
public static void main(String[] args) {
// 1. 创建 HashSet
HashSet<String> set = new HashSet<>();
// 2. 添加元素(不会存储重复元素)
set.add("Apple");
set.add("Banana");
set.add("Orange");
set.add("Apple"); // 重复元素不会被加入
// 3. 判断是否包含某个元素
System.out.println("包含 Apple? " + set.contains("Apple"));
// 4. 删除元素
set.remove("Banana");
// 5. 获取集合大小
System.out.println("集合大小: " + set.size());
// 6. 遍历 HashSet(方式一:增强 for 循环)
for (String fruit : set) {
System.out.println(fruit);
}
// 7. 遍历 HashSet(方式二:迭代器)
Iterator<String> iterator = set.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
// 8. 清空集合
set.clear();
System.out.println("集合是否为空? " + set.isEmpty());
}
}
HashSet
, TreeSet
, LinkedHashSet
的区别:
集合类型 | 底层结构 | 是否有序 | 查询速度 | 适用场景 |
---|---|---|---|---|
HashSet | 哈希表(HashMap ) | 无序 | O(1) | 需要快速查找 |
TreeSet | 红黑树 | 有序(按大小排序) | O(log n) | 需要排序的集合 |
LinkedHashSet | 哈希表 + 链表 | 插入顺序 | O(1) | 需要有序且快速查找 |
适用场景:
存储唯一元素(去重)
需要快速查询,但不关心顺序。
避免存储大量重复数据(如唯一用户名、唯一 ID)。
不适合:
- 需要排序的情况(用
TreeSet
)。 - 需要保持插入顺序(用
LinkedHashSet
)。
栈和队列
栈(Stack):
- 后进先出
- 插入(
push()
)和删除(pop()
)操作都在 同一端进行(栈顶)。 - 常用于 递归、回溯、括号匹配、深度优先搜索(DFS) 等。
基本操作:
import java.util.Stack;
public class StackExample {
public static void main(String[] args) {
Stack<Integer> stack = new Stack<>();
// 1. 入栈(push)
stack.push(10);
stack.push(20);
stack.push(30);
stack.push(40);
System.out.println("当前栈:" + stack); // [10, 20, 30, 40]
// 2. 查看栈顶元素(peek)
System.out.println("栈顶元素:" + stack.peek()); // 40
// 3. 出栈(pop)
System.out.println("弹出元素:" + stack.pop()); // 40
System.out.println("弹出元素:" + stack.pop()); // 30
System.out.println("当前栈:" + stack); // [10, 20]
// 4. 查找元素(search,从栈顶开始,返回1-based索引)
System.out.println("元素 10 在栈中的位置:" + stack.search(10)); // 2
System.out.println("元素 40 在栈中的位置:" + stack.search(40)); // -1(不存在)
// 5. 判断是否为空
System.out.println("栈是否为空:" + stack.isEmpty()); // false
// 6. 获取栈大小
System.out.println("栈的大小:" + stack.size()); // 2
// 7. 遍历栈(方式1:for-each)
System.out.print("栈中的元素(从栈底到栈顶):");
for (int num : stack) {
System.out.print(num + " ");
}//栈中的元素(从栈底到栈顶):10 20 30 40
System.out.println();
// 8. 遍历栈(方式2:while + pop,弹出所有元素)
System.out.print("弹出所有元素:");
while (!stack.isEmpty()) {
System.out.print(stack.pop() + " ");
}//弹出所有元素:40 30 20 10
System.out.println();
// 9. 栈是否为空(最终检查)
System.out.println("栈是否为空:" + stack.isEmpty()); // true
}
}
Deque
实现栈:
Stack
类性能差,建议用 Deque
(双端队列)来实现栈:
import java.util.Deque;
import java.util.LinkedList;
public class DequeAsStack {
public static void main(String[] args) {
Deque<Integer> stack = new LinkedList<>();
stack.push(10); // 入栈
stack.push(20);
stack.push(30);
System.out.println("栈顶元素:" + stack.peek()); // 30
System.out.println("弹出:" + stack.pop()); // 30
}
}
队列
特点:
- 先进先出
- 从队尾插入(offer/enqueue),从队头删除(poll/dequeue)
- 适用于 任务调度、消息队列、广度优先搜索(BFS)等
示例:
import java.util.Queue;
import java.util.LinkedList;
public class QueueExample {
public static void main(String[] args) {
Queue<Integer> queue = new LinkedList<>();
// 1. 入队(offer)
queue.offer(10);
queue.offer(20);
queue.offer(30);
// 2. 取队头元素(peek,不删除)
System.out.println("队头元素:" + queue.peek()); // 10
// 3. 出队(poll),会删除
System.out.println("出队:" + queue.poll()); // 10
// 4. 判断队列是否为空
System.out.println("队列是否为空:" + queue.isEmpty());
// 5. 获取队列大小
System.out.println("队列大小:" + queue.size());
// 6. 遍历队列
System.out.println("队列中的元素:" + queue);
}
}
约瑟夫问题
package test;
import java.io.*;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
import java.util.Set;
import java.util.Stack;
public class Main {
public static void main(String[] args){
Queue<Integer> queue=new LinkedList<>();
Scanner scanner=new Scanner(System.in);
int n=scanner.nextInt();
int m=scanner.nextInt();
for (int i = 0; i < n; i++) {
queue.add(i);
}
int res=0;
while (!queue.isEmpty()) {
int x=queue.poll();
res++;
if (res==m) {
System.out.println(x+" ");
res=0;
}
else {
queue.add(x);
}
}
}}