Java Nâng cao
Chú ý
Nội dung dưới đây được viết dựa trên Java JDK 8, không loại trừ khả năng có thay đổi ở các phiên bản cao hơn.
Nhập/xuất nhanh hơn
Scanner và System.out.print hoạt động tốt lúc đầu, nhưng sẽ giảm hiệu suất khi xử lý input lớn, vì vậy cần dùng một số cách để tăng tốc IO.
Dùng Kattio + StringTokenizer cho input
Một trong những cách phổ biến là dùng Kattio.java từ Kattis để tăng tốc IO.1 Cách này bọc StringTokenizer và PrintWriter vào một lớp để tiện sử dụng. Khi giải bài (nếu BTC/đơn vị tổ chức cho phép) có thể dùng trực tiếp mẫu này.
Mẫu IO bên dưới là phiên bản đã chỉnh sửa từ Kattio gốc (Kattio gốc có một số chức năng ít dùng, và dùng giấy phép MIT):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | |
Ví dụ sử dụng Kattio:
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
Dùng StreamTokenizer cho input
Trong một số trường hợp dùng StringTokenizer có thể gây MLE (Memory Limit Exceeded), khi đó cần dùng StreamTokenizer để nhập.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | |
Phân tích và so sánh Kattio + StringTokenizer với StreamTokenizer
StreamTokenizerdùng ít bộ nhớ hơnStringTokenizer, khi Java MLE có thể thửStreamTokenizer, nhưngStreamTokenizercó thể mất độ chính xác khi đọc một số dữ liệu;- Mã nguồn
StreamTokenizercóType, kiểu này quyết định theo nội dung nhập. Nếu input dạng123oi(bắt đầu bằng số), nó sẽ ép kiểu thànhdouble, vì vậy khi đọc kiểuStringsẽ ném exception; StreamTokenizersẽ mất độ chính xác khi đọc số lớn hơn1e14;
- Mã nguồn
- Khi dùng
PrintWriter, chú ý cuối chương trình phảiclose()hoặc khi cần xuất thìflush()để xả buffer, nếu không nội dung sẽ không được ghi ra console/file. Kattiokế thừaPrintWriter, nên đối tượng có luôn các hàm củaPrintWriterđể xuất, đồng thời dùngStringTokenizerlàm biến thành viên. Còn cáchMainthứ hai dùngStreamTokenizervàPrintWriternhư các biến thành viên riêng, nên cách dùng hơi khác.
Tóm lại, đa số trường hợp StringTokenizer ưu thế hơn StreamTokenizer. Khi MLE cực hạn có thể thử StreamTokenizer, nhưng dữ liệu vượt phạm vi int thì StreamTokenizer cũng không xử lý tốt.
BigInteger và số học
BigInteger là lớp tính toán độ chính xác cao trong Java, rất tiện để xử lý bài toán số lớn.
Khởi tạo
BigInteger có hai cách tạo thường dùng:
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
Phép toán cơ bản
Dùng this để chỉ BigInteger hiện tại:
| Tên hàm | Chức năng |
|---|---|
abs() |
Trả về giá trị tuyệt đối của this |
negate() |
Trả về số đối của this |
add(BigInteger val) |
Trả về tổng của this và val |
subtract(BigInteger val) |
Trả về hiệu của this và val |
multiply(BigInteger val) |
Trả về tích của this và val |
divide(BigInteger val) |
Trả về thương của this và val |
remainder(BigInteger val) |
Trả về số dư của this chia val |
mod(BigInteger val) |
Trả về this mod val |
pow(int val) |
Trả về this mũ val |
and(BigInteger val) |
Trả về phép AND bit của this và val |
or(BigInteger val) |
Trả về phép OR bit của this và val |
not() |
Trả về phép NOT bit của this |
xor(BigInteger val) |
Trả về phép XOR bit của this và val |
shiftLeft(int n) |
Trả về this dịch trái n bit |
shiftRight(int n) |
Trả về this dịch phải n bit |
max(BigInteger val) |
Trả về giá trị lớn hơn giữa this và val |
min(BigInteger val) |
Trả về giá trị nhỏ hơn giữa this và val |
bitCount() |
Trả về số bit 1 (không tính bit dấu) trong this |
bitLength() |
Trả về độ dài nhị phân (không tính bit dấu) của this |
getLowestSetBit() |
Trả về vị trí bit 1 thấp nhất của this |
compareTo(BigInteger val) |
So sánh giá trị this và val |
toString() |
Trả về biểu diễn thập phân của this |
toString(int radix) |
Trả về biểu diễn this theo cơ số radix |
Ví dụ sử dụng:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | |
Toán học
Dùng this để chỉ BigIntger hiện tại:
| Tên hàm | Chức năng |
|---|---|
gcd(BigInteger val) |
Trả về gcd của |this| và |val| |
isProbablePrime(int val) |
Trả về this có phải số nguyên tố không |
nextProbablePrime() |
Trả về số nguyên tố đầu tiên lớn hơn this |
modPow(BigInteger b, BigInteger p) |
Trả về this^b mod p |
modInverse(BigInteger p) |
Trả về nghịch đảo nhân của this theo mod p |
Ví dụ sử dụng:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | |
Về Miller-Rabin, tham khảo Miller–Rabin 素性测试.
Kiểu dữ liệu cơ bản và kiểu bao (wrapper)
Giới thiệu
Do kiểu cơ bản không mang tính hướng đối tượng, Java cung cấp 8 lớp wrapper cho 8 kiểu cơ bản: Byte、Double、Float、Integer、Long、Short、Character、Boolean. Tương ứng như sau:
| Kiểu cơ bản | Kiểu wrapper |
|---|---|
byte |
Byte |
short |
Short |
boolean |
Boolean |
char |
Character |
int |
Integer |
long |
Long |
float |
Float |
double |
Double |
Khác biệt
Lấy int và Integer làm ví dụ:
Integerlà wrapper củaint,intlà kiểu cơ bản.Integerphải khởi tạo đối tượng mới dùng được,intthì không.Integerthực chất là tham chiếu;new Integertạo một đối tượng, cònintlưu trực tiếp giá trị.Integermặc định lànull, nhậnnullvàint;intmặc định 0 và không nhậnnull.- So sánh
Integerbằng==có thể sai, chỉ nên dùngequals(), cònintcó thể dùng==.
Autoboxing và unboxing
Ví dụ với int và Integer:
Integer là đối tượng, int là kiểu cơ bản, không thể gán trực tiếp. Cần chuyển kiểu: từ cơ bản sang wrapper gọi là boxing, ngược lại là unboxing.
1 2 3 4 5 6 | |
Java 5 thêm cơ chế auto boxing/unboxing:
1 2 | |
Chú ý
Dù có auto boxing/unboxing, vẫn nên chọn kiểu phù hợp khi khai báo biến vì wrapper Integer nhận null, còn int thì không. Unboxing từ null sẽ ném exception. Ví dụ:
1 2 3 4 5 | |
Kế thừa
Tạo thiết kế mới dựa trên thiết kế có sẵn là kế thừa trong OOP. Lớp mới được định nghĩa dựa trên lớp đã có. Qua kế thừa, lớp mới nhận được tất cả thành viên của lớp cơ sở, gồm biến và phương thức, gồm cả public và private. Nhờ vậy, định nghĩa lớp mới nhanh và tiện hơn so với viết từ đầu. Kế thừa là một cách quan trọng để tái sử dụng code.
Trong Java, từ khóa kế thừa là extends, Java chỉ hỗ trợ đơn kế thừa nhưng có thể implements nhiều interface.
Mọi lớp đều là con của Object.
Lớp con kế thừa mọi thành viên của lớp cha, trừ constructor. Constructor là đặc trưng của lớp cha và không tồn tại trong lớp con. Ngoài ra, lớp con thừa hưởng tất cả thành viên.
Mỗi thành viên có mức truy cập khác nhau. Lớp con nhận tất cả thành viên, nhưng mức truy cập ảnh hưởng cách sử dụng: có thành viên trở thành giao diện công khai, có thành viên bị ẩn và ngay cả lớp con cũng không truy cập được.
Bảng mức truy cập:
| Mức truy cập ở lớp cha | Ý nghĩa trong lớp cha | Ý nghĩa trong lớp con |
|---|---|---|
public |
Mở cho mọi lớp | Mở cho mọi lớp |
protected |
Chỉ lớp cùng package, chính nó và lớp con truy cập | Chỉ lớp cùng package, chính nó và lớp con truy cập |
Mặc định (default) |
Chỉ lớp cùng package truy cập | Nếu lớp con cùng package, chỉ lớp cùng package truy cập; nếu khác package thì như private, không truy cập |
private |
Chỉ chính nó truy cập | Không truy cập được |
Đa hình
Trong Java, khi gán một đối tượng cho một biến, kiểu của đối tượng phải khớp với kiểu của biến. Nhưng do có kế thừa, một biến có thể lưu kiểu được khai báo hoặc bất kỳ kiểu con nào.
Nếu một kiểu implements interface, nó cũng là kiểu con của interface đó.
Biến lưu đối tượng trong Java là biến đa hình. “Đa hình” nghĩa là một biến có thể lưu các đối tượng khác kiểu (kiểu khai báo hoặc các kiểu con).
Biến đa hình:
- Biến đối tượng trong Java là đa hình, có thể lưu nhiều kiểu đối tượng.
- Có thể lưu đối tượng đúng kiểu khai báo hoặc kiểu con.
- Gán đối tượng con cho biến kiểu cha gọi là upcasting.
Generic
Generic là khi định nghĩa lớp không cố định kiểu thuộc tính/tham số, mà chỉ xác định kiểu khi sử dụng (hoặc tạo đối tượng). Bản chất là tham số hóa kiểu dữ liệu.
Generic cung cấp cơ chế kiểm tra an toàn kiểu ở thời điểm biên dịch, cho phép phát hiện kiểu không hợp lệ.
Interface
Giới thiệu
Interface trong Java là một kiểu trừu tượng, tập hợp các phương thức trừu tượng, khai báo bằng interface. Một lớp implements interface để “kế thừa” các phương thức trừu tượng.
Interface không phải là class. Cách viết gần giống class, nhưng khái niệm khác nhau. Class mô tả thuộc tính và phương thức của đối tượng; interface chứa các phương thức cần được triển khai.
Trừ khi lớp implements là abstract, lớp phải định nghĩa tất cả phương thức trong interface.
Interface không thể khởi tạo, nhưng có thể được implement. Một lớp implement interface phải hiện thực mọi phương thức mô tả trong interface, nếu không phải khai báo abstract. Kiểu interface cũng có thể dùng để khai báo biến; biến này có thể là null hoặc trỏ tới đối tượng implement interface.
Khác biệt với class
- Interface không thể tạo instance.
- Interface không có constructor.
- Mọi phương thức trong interface phải là abstract; từ Java 8 có thể có phương thức
default. - Interface không chứa biến thành viên, trừ
staticvàfinal. - Class không kế thừa interface mà là implement.
- Interface hỗ trợ đa kế thừa, class thì không.
Khai báo
1 2 3 4 | |
Implement
1 | |
Biểu thức Lambda
Giới thiệu
Lambda là một tính năng quan trọng nhất của Java 8.
Lambda cho phép truyền hàm như tham số của phương thức (hàm là tham số).
Dùng lambda giúp code gọn và súc tích hơn.
Cú pháp
- Kiểu tham số có thể bỏ: compiler tự suy ra.
- Dấu ngoặc tham số có thể bỏ nếu chỉ có một tham số.
- Dấu ngoặc nhọn có thể bỏ nếu thân chỉ có một câu lệnh.
- Từ khóa
returncó thể bỏ nếu chỉ có một biểu thức trả về; nếu dùng{}phải córeturn.
Ví dụ:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
Ví dụ sắp xếp mảng chuỗi theo độ dài:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
Ví dụ dùng nhiều câu lệnh trong lambda:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | |
-> là ký hiệu suy diễn, biểu thị nhận tham số bên trái và trả về/thi hành phần bên phải (tức truyền phương thức).
Functional Interface
- Là một interface theo định nghĩa của Java.
- Chỉ chứa một phương thức trừu tượng.
- Vì chỉ có một phương thức chưa hiện thực, lambda có thể tự động điền vào.
Ví dụ dùng functional interface:
In ra các chuỗi có độ dài chia hết cho 2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | |
Thực hiện 4 phép tính cộng trừ nhân chia
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | |
Collection
Collection là một interface trong Java, được nhiều interface container generic implement. Ở đây Collection chỉ cấu trúc dữ liệu lưu đối tượng.
Trong Java, phần tử của Collection phải là kiểu đối tượng, không thể là kiểu cơ bản.
Nội dung dưới đây dựa trên tính đa hình của Java, đều dùng dạng implement interface.
Các interface thường dùng: List、Queue、Set、Map.
Định nghĩa container
Khi định nghĩa container generic, cần chỉ rõ kiểu dữ liệu. Nếu không chỉ rõ kiểu (dùng Object), Java 8 vẫn compile được nhưng có nhiều cảnh báo.
Ví dụ an toàn:
1 | |
Ví dụ gây cảnh báo:
1 2 3 4 5 6 | |
Vì vậy nếu không có nhu cầu đặc biệt thì không khuyến nghị cách thứ 2. Compiler không thể kiểm tra an toàn kiểu; list.get(index) trả về Object nên phải tự ép kiểu, dễ sai.
Nếu xác định kiểu như List<Integer>, compiler sẽ kiểm tra kiểu phần tử, chỉ nhận số nguyên. Khi khai báo collection, phải dùng wrapper như List<Integer> hoặc class tự định nghĩa, không thể dùng List<int>.
List
ArrayList
ArrayList là mảng có thể mở rộng, kích thước mặc định 10. Nếu vượt quá sẽ mở rộng theo tỷ lệ \(\dfrac{3}{2}\).
Khởi tạo
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
LinkedList
LinkedList là danh sách liên kết đôi.
Khởi tạo
1 2 3 4 5 6 7 8 9 10 11 12 | |
Phương thức thường dùng
Dùng this để chỉ List<Integer> hiện tại:
| Tên hàm | Chức năng |
|---|---|
size() |
Trả về độ dài của this |
add(Integer val) |
Thêm val vào cuối this |
add(int idx, Integer e) |
Chèn e vào vị trí idx trong this |
get(int idx) |
Lấy phần tử tại idx, nếu vượt sẽ ném exception |
set(int idx, Integer e) |
Gán this[idx] = e |
Ví dụ và so sánh:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | |
Duyệt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | |
Chú ý
Không xóa phần tử trong for hoặc foreach khi đang duyệt List, nếu không sẽ ném exception.
Lý do: list.size() thay đổi nhưng số lần lặp dự kiến không đổi. Phần tử ở index kế tiếp bị xóa sẽ dồn lên, vòng lặp tiếp theo sẽ xử lý phần tử sai, gây kết quả không mong muốn.
Queue
LinkedList
Có thể dùng LinkedList làm queue thường, nền là danh sách liên kết.
Khởi tạo
1 | |
LinkedList implement List và Deque, mà Deque kế thừa Queue, nên LinkedList vừa là List vừa là Queue.
ArrayDeque
Có thể dùng ArrayDeque làm queue thường, nền là mảng.
Khởi tạo
1 | |
ArrayDeque implement Deque, mà Deque kế thừa Queue, nên ArrayDeque là Queue.
Khác biệt khi implement Queue giữa LinkedList và ArrayDeque
- Cấu trúc dữ liệu:
ArrayDequevàLinkedListđều implementDeque. NhưngArrayDequekhông implementList, nên không có thao tác theo chỉ số. - Thread safety: cả hai không đồng bộ, không thread-safe.
- Cài đặt:
ArrayDequedựa trên mảng động;LinkedListdựa trên danh sách liên kết đôi. - Tốc độ duyệt:
ArrayDequelà vùng nhớ liên tục, tận dụng cache tốt;LinkedListrời rạc, kém cache. - Tốc độ thao tác: stack/queue đều O(1),
ArrayDequeđôi khi mở rộng nhưng xét amortized vẫn O(1). - Bộ nhớ:
ArrayDequecó chỗ trống đầu/cuối;LinkedListcó con trỏ prev/next.
PriorityQueue
PriorityQueue là hàng đợi ưu tiên, mặc định là heap nhỏ.
Khởi tạo
1 2 | |
Phương thức thường dùng
Định nghĩa queue là Queue<Integer>:
| Tên hàm | Chức năng |
|---|---|
size() |
Trả về độ dài queue |
add(Integer val) |
Thêm val vào queue; nếu vượt giới hạn sẽ ném exception |
offer(Integer val) |
Thêm val vào queue; nếu vượt giới hạn thì thất bại nhưng không ném exception |
isEmpty() |
Kiểm tra queue rỗng, rỗng trả true |
peek() |
Trả về phần tử đầu; nếu rỗng trả null |
poll() |
Trả về và xóa phần tử đầu; nếu rỗng trả null |
Ví dụ và so sánh:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | |
Duyệt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | |
Deque
Deque là hàng đợi hai đầu trong Java, thường dùng cho thao tác queue và stack.
Hàm chính
Định nghĩa là Deque<Integer>:
| Tên hàm | Chức năng |
|---|---|
addFirst(Integer val) |
Thêm val vào đầu; nếu vượt giới hạn ném exception |
offerFirst(Integer val) |
Thêm val vào đầu; nếu vượt giới hạn thất bại nhưng không ném exception |
removeFirst() |
Trả về và xóa phần tử đầu; nếu rỗng ném exception |
pollFirst() |
Trả về và xóa phần tử đầu; nếu rỗng trả null |
peekFirst() |
Trả về phần tử đầu; nếu rỗng trả null |
push(Integer val) |
Thêm val vào đầu, tương đương addFirst |
pop() |
Trả về và xóa phần tử đầu, tương đương removeFirst |
remove() |
Xóa phần tử đầu, tương đương removeFirst |
poll() |
Xóa phần tử đầu, tương đương pollFirst |
addLast(Integer val) |
Thêm val vào cuối; nếu vượt giới hạn ném exception |
offerLast(Integer val) |
Thêm val vào cuối; nếu vượt giới hạn thất bại nhưng không ném exception |
removeLast() |
Trả về và xóa phần tử cuối; nếu rỗng ném exception |
pollLast() |
Trả về và xóa phần tử cuối; nếu rỗng trả null |
peekLast() |
Trả về phần tử cuối; nếu rỗng trả null |
add(Integer val) |
Thêm val vào cuối, tương đương addLast |
offer(Integer val) |
Thêm val vào cuối, tương đương offerLast |
Thao tác stack
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
Thao tác deque
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | |
Set
Set là cấu trúc dữ liệu đảm bảo phần tử không trùng.
HashSet
Set chèn ở vị trí ngẫu nhiên.
Khởi tạo
1 | |
LinkedHashSet
Set giữ thứ tự chèn.
Khởi tạo
1 | |
TreeSet
Set giữ phần tử có thứ tự, mặc định tăng dần.
Khởi tạo
1 2 | |
Dùng TreeSet nâng cao
Các phương thức này do TreeSet cung cấp riêng, không thể gọi từ Set, nên cần khai báo:
1 2 | |
Dùng this để chỉ TreeSet<Integer> hiện tại:
| Tên hàm | Chức năng |
|---|---|
first() |
Trả về phần tử đầu; không có trả null |
last() |
Trả về phần tử cuối; không có trả null |
floor(Integer val) |
Trả về phần tử lớn nhất ≤ val; không có trả null |
ceiling(Integer val) |
Trả về phần tử nhỏ nhất ≥ val; không có trả null |
higher(Integer val) |
Trả về phần tử nhỏ nhất > val; không có trả null |
lower(Integer val) |
Trả về phần tử lớn nhất < val; không có trả null |
pollFirst() |
Trả về và xóa phần tử đầu; không có trả null |
pollLast() |
Trả về và xóa phần tử cuối; không có trả null |
Ví dụ:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | |
Phương thức thường dùng của Set
| Tên hàm | Chức năng |
|---|---|
size() |
Trả về kích thước hiện tại |
add(Integer val) |
Thêm val vào tập |
contains(Integer val) |
Kiểm tra tập có phần tử val |
addAll(Collection e) |
Thêm tất cả phần tử của e vào tập hiện tại |
retainAll(Collection e) |
Xóa phần tử không nằm trong e, tức là lấy giao với e |
removeAll(Collection e) |
Xóa phần tử nằm trong e, tức là lấy hiệu với e |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | |
Duyệt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
Map
Map là cấu trúc dữ liệu lưu cặp khóa-giá trị <Key, Value> với Key là duy nhất.
HashMap
Map chèn ngẫu nhiên.
Khởi tạo
1 | |
LinkedHashMap
Map giữ thứ tự chèn.
Khởi tạo
1 | |
TreeMap
Map giữ key có thứ tự, mặc định tăng dần.
Khởi tạo
1 2 | |
Phương thức thường dùng
Dùng this cho Map<Integer, Integer> hiện tại:
| Tên hàm | Chức năng |
|---|---|
put(Integer key, Integer value) |
Chèn <key, value> vào this |
size() |
Trả về kích thước this |
containsKey(Integer key) |
Kiểm tra this có khóa key không |
get(Integer key) |
Trả về giá trị ứng với khóa key |
keySet() |
Trả về tập các khóa của this |
Ví dụ:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | |
Duyệt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
Kiểu của key và value cũng có thể đổi, ví dụ:
1 | |
Arrays
Arrays là lớp công cụ trong java.util để thao tác mảng. Các phương thức là static.
Arrays.sort()
Arrays.sort() sắp xếp mảng, các overload chính:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | |
Ý nghĩa các overload:
- Sắp xếp
atăng dần. - Sắp xếp đoạn
[firstIdx, lastIdx)củaatăng dần. - Sắp xếp
atheo comparator; với kiểu đối tượng mới dùng comparator. - Sắp xếp đoạn
[firstIdx, lastIdx)theo comparator. - Tương tự 3, dùng lambda.
- Tương tự 4, dùng lambda.
Arrays.sort() bên dưới dùng thuật toán
- Nếu phần tử là kiểu cơ bản (
byte、short、char、int、long、double、float) thì dùngDualPivotQuicksort, trường hợp xấu nhất \(O(n^2)\). - Nếu phần tử là kiểu đối tượng thì dùng
legacyMergeSortvàTimSort, độ phức tạp \(O(n\log n)\).
Có thể kiểm chứng qua:
Codeforces 1646B - Quality vs Quantity
Có \(n\) số nguyên, cần chia thành 2 nhóm sao cho tồn tại nhóm có số phần tử ít hơn nhóm kia nhưng tổng lớn hơn.
Code mẫu
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | |
Arrays.binarySearch()
Arrays.binarySearch() tìm nhị phân trên đoạn liên tiếp của mảng đã được sắp xếp, độ phức tạp \(O(\log_n)\), overload chính:
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
Nguồn:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
Ý nghĩa:
- Tìm
keytronga, nếu có trả về chỉ số, nếu không trả về số âm. - Tìm
keytrong đoạn[firstIdx,lastIdx), nếu có trả về chỉ số, nếu không trả về số âm.
Arrays.fill()
Arrays.fill() gán một giá trị cho đoạn liên tiếp của mảng. Tham số là mảng, fromIndex, toIndex và giá trị cần điền. Sau khi chạy, các phần tử trong đoạn [firstIdx,lastIdx) đều nhận giá trị đó.
Collections
Collections là lớp công cụ trong java.util thao tác trên collection, các phương thức là static.
Collections.sort()
Collections.sort() chuyển tất cả phần tử thành mảng, gọi Arrays.sort(), rồi gán lại. Vì Collection chỉ chứa đối tượng nên luôn dùng merge sort.
Không thể sắp xếp theo đoạn.
Nguồn:
1 2 3 4 5 6 7 8 9 | |
Collections.binarySearch()
Collections.binarySearch() tìm nhị phân trên collection, tương tự Arrays.binarySearch().
1 | |
Không thể chỉ định đoạn.
Collections.swap()
Collections.swap() hoán đổi phần tử ở hai vị trí.
1 | |
Khác
So sánh số
Trong Java, nếu là kiểu số, -0.0 = 0.0. Nếu là kiểu đối tượng, -0.0 != 0.0. Khi dùng Set đếm số lượng hệ số góc, vấn đề này gây rắc rối. Cách giải là cộng 0.0 vào mọi hệ số góc trước khi đưa vào Set.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | |
Tài liệu tham khảo
Last updated on this page:, Update history
Found an error? Want to help improve? Edit this page on GitHub!
Contributors to this page:OI-wiki
All content on this page is provided under the terms of the CC BY-SA 4.0 and SATA license, additional terms may apply