Giải thuật 03/09/2026 8 phút

Cùng dữ liệu, chỉ xếp lại trong bộ nhớ, một vòng lặp nhanh gấp 4,7 lần

Gói các trường của một object lại thành struct (AoS) là cách tự nhiên nhất. Nhưng khi chỉ cộng một trường của struct rộng, AoS chậm tới 4,7 lần SoA vì mỗi dòng cache kéo cả struct về mà chỉ dùng một trường. Đọc hết mọi trường thì AoS lại ngang. Mẫu truy cập quyết định bố cục, không phải cái nào nghe tự nhiên hơn. Tôi đo.

Giải thuật 03/09/2026 8 phút

Sắp mảng trước khi chạy, cùng code lại nhanh gấp 1,7 lần — vì sao?

Cùng một đoạn code, cùng những con số, chỉ khác mảng được sắp trước hay chưa: bản chưa sắp chạy 660 ms, bản đã sắp 379 ms — chênh 1,7 lần. Không phải ít phép tính hơn, không phải cache. Thủ phạm là dự đoán nhánh của CPU, thứ big-O không hề thấy. Viết không nhánh xóa hẳn (183 ms). Tôi đo.

Giải thuật 03/09/2026 10 phút

Bật -O3 nhanh gấp 4 lần — rồi đổi một dấu, tụt xuống chậm gấp 11

Bật -O3, vòng nhân mảng float nhanh 3,9 lần nhờ NEON làm 4 float mỗi lệnh. Nhưng chỉ thêm một phụ thuộc chuỗi là trình biên dịch lặng lẽ bỏ vector hóa, tụt về scalar chậm 11,6 lần — không một dòng cảnh báo. SIMD không phải phép màu của cờ, mà là phần thưởng cho vòng viết đúng dạng. Tôi đo.

Giải thuật 03/09/2026 10 phút

'Thêm phần tử là O(1)' — vậy sao có một lần nó ngốn 392 micro giây?

Thêm vào mảng động là O(1) khấu hao, nhưng đo đường cong từng thao tác thấy gai O(n): lần cấp phát cuối sao chép 2,1 triệu phần tử mất 392µs, gấp 400.000 lần một lần thêm thường. Và tăng dung lượng mỗi lần +1 để 'tiết kiệm bộ nhớ' hóa ra là O(n²), chậm 17.851 lần. Tôi đo cả đường cong.

Giải thuật 03/09/2026 9 phút

Một dòng tung xúc xắc cắt 2 tỉ phép so sánh xuống còn 1,3 triệu

Quicksort pivot cố định gặp mảng đã sắp xếp làm 2,05 tỉ so sánh (901 ms); pivot ngẫu nhiên chỉ 1,3 triệu (1,1 ms) — ít hơn 1524 lần. Và skip list cân bằng bằng tung đồng xu, đạt ~log n mà không một phép xoay. Gieo ngẫu nhiên đúng chỗ là tăng an toàn, không phải thêm rủi ro. Tôi đo.