Đoạn trích bài giảng với người cố vấn trong khóa học của Đại học Codegym. Đăng ký cho khóa học đầy đủ.


"Xin chào, Amigo!"

"Xin chào, Rishi!"

"Bạn đã biết đôi điều về mảng, và tôi hy vọng bạn thậm chí đã giải quyết được một số nhiệm vụ. Nhưng bạn không biết tất cả mọi thứ. Ví dụ, đây là một sự thật thú vị khác về mảng. Mảng không chỉ là một chiều (tuyến tính ). Chúng cũng có thể là hai chiều."

"Ừm... Nghĩa là sao?"

"Điều này có nghĩa là các ô của mảng có thể biểu thị không chỉ một cột (hoặc hàng) mà còn cả một bảng hình chữ nhật.

int[][]name = new int[width][height];

"Trong đó name là tên của biến mảng, width là chiều rộng của bảng (tính theo ô) và height là chiều cao của bảng. Hãy xem một ví dụ:

int[][] data = new int[2][5];
data[1][1] = 5;
Chúng tôi tạo một mảng hai chiều: 2 cột và 5 hàng.
Chúng tôi viết 5 trong ô (1,1).

"Đây là giao diện của nó trong bộ nhớ:

mảng hai chiều

"Nhân tiện, đối với mảng hai chiều, bạn cũng có thể sử dụng khởi tạo nhanh:

// Lengths of months of the year in each quarter
int[][] months = { {31, 28, 31}, {30, 31, 30}, {31, 31, 30}, {31, 30, 31} };

"Hmm... bây giờ điều đó thật thú vị. Nếu chúng ta tưởng tượng rằng trong dấu ngoặc trong đầu tiên đại diện cho một phần tử, tiếp theo là phần tử thứ hai... Vậy mảng hai chiều giống như mảng của các mảng?"

"Bạn đúng là một học sinh thông minh! Chính xác. Phần tử đầu tiên là mảng một chiều {31, 28, 31}, phần tử thứ hai là {30, 31, 30}, v.v. Nhưng chúng ta sẽ quay lại vấn đề đó một chút sau trong bài học này. Cho đến lúc đó, hãy thử nghĩ về một mảng hai chiều dưới dạng một bảng với các hàng và cột, tạo thành các ô ở mỗi giao điểm.

"Tôi đã có một bức tranh trong đầu về điều đó. Nhân tiện, chúng được dùng để làm gì, những mảng hai chiều này?"

"Lập trình viên cần mảng hai chiều khá thường xuyên. Nếu bạn quan sát kỹ, hầu hết mọi trò chơi trên bàn cờ đều được triển khai bằng cách sử dụng mảng hai chiều có sẵn: cờ vua, cờ đam, tic-tac-toe, hải chiến, v.v.:"

trận đánh trên biển

"Tôi hiểu rồi! Sân chơi cờ vua hay hải chiến hoàn toàn phù hợp với mảng hai chiều!"

"Có, nhưng bạn cần sử dụng các số làm tọa độ ô. Không phải 'cầm đồ e2-e4', mà là 'cầm đồ (5,2) -> (5,4)'. Nó sẽ còn dễ dàng hơn cho bạn với tư cách là một lập trình viên. "

Sắp xếp các phần tử trong mảng: (x, y) hoặc (y, x)

"Việc tạo các mảng hai chiều đặt ra một vấn đề nan giải thú vị. Khi chúng ta tạo một mảng bằng cách sử dụng new int [2][5];, chúng ta có một bảng gồm 'hai hàng và 5 cột ' hay là 'hai cột và 5 hàng'?"

"Nói cách khác, không hoàn toàn rõ ràng liệu trước tiên chúng ta chỉ định chiều rộng rồi đến 'chiều cao... hay ngược lại, đầu tiên là chiều cao rồi mới đến chiều rộng?"

"Vâng, đây là tình thế tiến thoái lưỡng nan. Và không có câu trả lời chắc chắn."

"Làm gì?"

"Đầu tiên, điều quan trọng là phải hiểu mảng hai chiều của chúng ta thực sự được lưu trữ trong bộ nhớ như thế nào . Đương nhiên, bộ nhớ máy tính không thực sự có bất kỳ bảng nào trong đó: mỗi vị trí trong bộ nhớ có một địa chỉ số tuần tự: 0, 1, 2, ... Đối với chúng tôi, đây là một bảng 2 × 5, nhưng trong bộ nhớ, nó chỉ là 10 ô, không hơn. Không phân chia thành hàng và cột."

"Tôi hiểu điều đó. Vậy làm thế nào để chúng ta xác định kích thước nào có trước - chiều rộng hay chiều cao?"

"Hãy xem xét tùy chọn đầu tiên. Đầu tiên là chiều rộng, sau đó là chiều cao. " Lập luận ủng hộ cách tiếp cận này là: mọi người đều học toán ở trường và họ biết rằng các cặp tọa độ được viết là 'x' (nghĩa là trục hoành) và sau đó là 'y' (kích thước dọc). Và đây không chỉ là tiêu chuẩn của trường học — nó là tiêu chuẩn được chấp nhận rộng rãi trong toán học. Như họ nói, bạn không thể tranh luận với toán học."

"Vậy à? Chà, nếu chúng ta không thể chiến đấu với nó, thì trước tiên là chiều rộng và sau đó là chiều cao?"

"Có một lập luận thú vị ủng hộ 'chiều cao trước, sau đó là chiều rộng' . Lập luận này xuất phát từ việc khởi tạo nhanh các mảng hai chiều. Rốt cuộc, nếu chúng ta muốn khởi tạo mảng của mình, thì chúng ta viết mã như sau:"

// Matrix of important data
int[][] matrix = { {1, 2, 3, 4, 5}, {1, 2, 3, 4, 5} };

"Vậy điều đó giúp ích gì cho chúng ta?"

"Bạn có nhận thấy bất cứ điều gì? Nếu chúng ta có cái này thì sao?

// Matrix of important data
int[][] matrix = {
  {1, 2, 3, 4, 5},
  {1, 2, 3, 4, 5}
};

"Nếu chúng tôi viết dữ liệu của mình trong từng dòng mã, thì chúng tôi sẽ nhận được một bảng có 2 hàng và 5 cột."

"Giờ thì tôi hiểu rồi. 2 là chiều cao và 5 là chiều rộng... Vậy chúng ta nên sử dụng tùy chọn nào?"

"Tùy bạn quyết định cái nào thuận tiện hơn. Điều quan trọng nhất là tất cả các lập trình viên làm việc trong cùng một dự án đều tuân theo cùng một cách tiếp cận."

"Nếu bạn làm việc trên một dự án có mã có nhiều mảng hai chiều được khởi tạo, thì rất có thể mọi thứ ở đó sẽ dựa trên khởi tạo dữ liệu nhanh, tức là bạn sẽ có 'chiều cao x chiều rộng' tiêu chuẩn.

"Nếu bạn thấy mình trong một dự án liên quan đến nhiều toán học và làm việc với tọa độ (ví dụ: công cụ trò chơi), thì mã rất có thể sẽ áp dụng phương pháp 'chiều rộng x chiều cao'.

Mảng hai chiều được sắp xếp như thế nào

"Bây giờ, bạn có nhớ tính năng đặc biệt của mảng hai chiều mà bạn đã nhận thấy ở đầu bài học không?"

"Phải! Chính là mảng hai chiều thực ra là mảng của mảng!"

"Hoàn toàn đúng." Nói cách khác, nếu trong trường hợp của một mảng thông thường, một biến mảng lưu trữ một tham chiếu đến một vùng chứa lưu trữ các phần tử của mảng, thì trong trường hợp của mảng hai chiều, tình huống sẽ bùng nổ một chút: một mảng hai chiều -biến mảng lưu trữ tham chiếu đến vùng chứa lưu trữ tham chiếu đến mảng một chiều. Tốt hơn là xem nó hoạt động một lần thay vì cố gắng giải thích nó hàng trăm lần:"

Mảng hai chiều được sắp xếp như thế nào

"Ở bên trái , chúng ta có một biến mảng hai chiều, lưu trữ một tham chiếu đến một đối tượng mảng hai chiều. Ở giữa một đối tượng mảng hai chiều có các ô lưu trữ các mảng một chiều, đó là các hàng của một mảng hai chiều. Và ở bên phải , bạn có thể thấy bốn mảng một chiều — các hàng của mảng hai chiều của chúng ta. Đây là cách mảng hai chiều thực sự hoạt động."

"Tuyệt vời! Nhưng nó mang lại cho chúng ta điều gì?"

"Vì 'vùng chứa của các vùng chứa' lưu trữ các tham chiếu đến 'mảng các hàng', nên chúng tôi có thể hoán đổi các hàng rất nhanh chóng và dễ dàng. Để có được một 'vùng chứa của các vùng chứa', bạn chỉ cần chỉ định một chỉ mục thay vì hai chỉ mục. Ví dụ:

int[][] data = new int[2][5];
int[] row1 = data[0];
int[] row2 = data[1];

"Hãy xem đoạn mã bên dưới. Chúng ta có thể sử dụng nó để đổi hàng:"

// Matrix of important data
int[][] matrix = {
  {1, 2, 3, 4, 5},
  {5, 4, 3, 2, 1}
};

int[] tmp = matrix[0];
matrix[0] = matrix[1];
matrix[1] = tmp;
Mảng hai chiều lưu





matrix[0]trữ tham chiếu đến hàng đầu tiên.
Chúng tôi trao đổi các tài liệu tham khảo.

Kết quả là, matrixmảng trông như thế này:
{
  {5, 4, 3, 2, 1},
  {1, 2, 3, 4, 5}
};

"Hiểu rồi. Nó hoạt động giống như hoán đổi hai vật phẩm bình thường bất kỳ."

"Đúng vậy. Chà, nếu bạn đề cập đến một ô của mảng hai chiều, nhưng bạn chỉ chỉ định một chỉ mục sau tên của mảng, thì bạn đang đề cập đến một vùng chứa các vùng chứa mà các ô của nó lưu trữ các tham chiếu đến một ô bình thường- mảng chiều."

"Mọi thứ có vẻ hợp lý và rõ ràng. Cảm ơn về bài giảng, Rishi!"

"Không có chi. Hãy thực hành nó một cách khôn ngoan."