In ra các phần tử trên đường biên của ma trận la các số chính phương
Dưới đây là một số bài tập về ma trận dành cho các bạn học Nhập môn lập trình tham khảo. Các ví dụ mình chỉ thao tác với ma trận nguyên bằng ngôn ngữ C, với ma trận thực cũng tương tự 1. Viết hàm nhập một ma trận Show
//Cách 1: Nhập m, n trong hàm void InputMatrix(int a[][20], int &m, int &n) { printf("Nhập số hàng m: "); scanf("%d", &m); printf("Nhập số cột n: "); scanf("%d", &n); for(int i = 0; i < m; i++) for(int j = 0; j < n; j++) { printf("A[%d][%d] = ", i, j); scanf("%d", &a[i][j]); } } //Cách 2: Nhập m, n ngoài hàm void InputMatrix(int a[][20], int m, int n) { for(int i = 0; i < m; i++) for(int j = 0; j < n; j++) { printf("A[%d][%d] = ", i, j); scanf("%d", &a[i][j]); } } 2. Viết hàm xuất một ma trận void OutputMatrix(int a[][20], int m, int n) { for(int i = 0; i < m; i++) { for(int j = 0; j < n; j++) printf("%d\t", a[i][j]); printf("\n"); } } 3. Viết hàm tìm giá trị lớn nhất trong ma trận int MaxOfMatrix(int a[][20], int m, int n) { int max = a[0][0]; for(int i = 0; i < m; i++) for(int j = 0; j < n; j++) if(a[i][j]>max) max = a[i][j]; return max; } 4. Viết hàm tính tổng các số chẵn trong ma trận int SumEven(int a[][20], int m, int n) { int sum = 0; for(int i = 0; i < m; i++) for(int j = 0; j < n; j++) if(a[i][j]%2==0) sum += a[i][j]; return sum; } 5. Viết hàm đếm số nguyên tố trong ma trận int PrimeMatrix(int a[][20], int m, int n) { int dem = 0; for(int i = 0; i < m; i++) for(int j = 0; j < n; j++) if(IsPrime(a[i][j])) dem++; return dem; } 6. Viết hàm xóa một dòng HOẶC một cột trong ma trận void DeleteRow(int a[][20], int &m, int n, int indexRow) { for(int i=indexRow;i void DeleteRowColumn(int a[][20], int &m, int &n, int indexRow, int indexColumn) { for(int i=0;i 8. Viết hàm hoán vị hai cột/hai dòng trong ma trận void swap(int &a, int &b) { int temp = a; a = b; b = temp; } void swapRow(int a[][20], int m, int n, int row1, int row2) { if((row1>=0 && row1 int Sum(int a[][20], int m, int n) { int sum = 0; for(int i = 0; i < m; i++) { sum += a[i][0]; sum += a[i][n-1]; } for(int j = 0; j < n; j++) { sum += a[0][i]; sum += a[n-1][i]; } return sum; } 10. Viết hàm tìm và xuất vị trí xuất hiện của phần tử lớn nhất trong ma trận void IndexOfMax(int a[][20], int m, int n) { int iMax = 0, jMax = 0; for(int i = 0; i < m; i++) for(int j = 0; j < n; j++) if(a[i][j]>a[iMax][jMax]) { iMax = i; jMax = j; } } Các ví dụ với ma trận vuông Viết hàm tính tổng các phần tử trên đường chéo chính int Sum(int a[][20], int n) { int sum = 0; for(int i = 0; i < n; i++) sum += a[i][i]; return sum; } Viết hàm tìm phần tử lớn nhất, nhỏ nhất trên đường chéo chính //Tìm max int Max(int a[][20], int n) { int max = a[0][0]; for(int i = 1; i < n; i++) if(a[i][i] > max) max = a[i][i]; return max; } //Tìm min int Min(int a[][20], int n) { int min = a[0][0]; for(int i = 1; i < n; i++) if(a[i][i] < min) min = a[i][i]; return min; } Viết hàm tính tổng các phần tử trên đường chéo phụ int Sum(int a[][20], int n) { int sum = 0; for(int i = 0; i < n; i++) sum += a[i][n-1-i]; return sum; } //Cách khác int Sum(int a[][20], int n) { int sum = 0; for(int i = 0, j = n-1; i < n; i++, j--) sum += a[i][j]; return sum; } Viết hàm kiểm tra đường chéo chính có tăng dần từ trên xuống dưới int IsIncreasingDiagonal(int a[][20], int n) { for(int i = 0; i < n-1; i++) if(a[i][i]>a[i+1][i+1]) return 0; return 1; } Viết hàm kiểm tra ma trận có phải là ma trận đối xứng Ma trận đối xứng là ma trận có các phần tử đối xứng nhau qua đường chéo chính.int IsSymmetric(int a[][20], int n) { for(int i = 0; i < n; i++) for(int j = 0; j < i; j++) if(a[i][j] != a[j][i]) return 0; return 1; } Viết hàm chuyển vị ma trận void swap(int &a, int &b) { int temp = a; a = b; b = temp; } void Transpose(int a[][20], int n) { for(int i = 0; i < n; i++) for(int j = 0; j < i; j++) swap(a[i][j], a[j][i]); }
Ngoài kiểu dữ liệu mảng một chiều, C++ hỗ trợ kiểu dữ liệu mảng từ hai chiều tới nhiều chiều. Mảng hai chiều là ví dụ rất trực quan và dễ tưởng tượng, ta có thể xem nó như một bảng hình chữ nhật gồm có MMM hàng và NNN cột. Cú pháp khai báo rất đơn giản: {Kiểu_phần_tử} {Tên_mảng}[{Số_hàng}][{Số_cột}];Khi đó, tổng số phần tử của mảng sẽ là {Số_hàng} ×\times× {Số_cột}. Chẳng hạn, khai báo một mảng hai chiều gồm 101010 hàng và 121212 cột chứa toàn số nguyên, ta viết như sau: int a[10][12];Các hàng và cột của mảng hai chiều đều sẽ được đánh số từ 000. Cách truy cập phần tử tương tự như ở mảng một chiều, chỉ cần dùng toán tử [] ở từng chiều để đưa ra một phần tử nào đó. Ví dụ, muốn truy cập phần tử ở hàng 3,3,3, cột 4,4,4, ta chỉ cần viết: a[3][4];Để tiện cho việc đánh số và biểu diễn trên hình, thường người ta sẽ quy ước đánh số các hàng từ trên xuống dưới và các cột từ trái qua phải: Tuy nhiên, có một lưu ý nho nhỏ, đó là khi khai báo mảng hai chiều các bạn không nên khai báo bằng biến cục bộ. Lí do là vì, khi khai báo biến cục bộ thì bộ nhớ cấp phát cho biến sẽ lưu trong stack của máy tính, và đối với một số trình biên dịch có thể gây ra lỗi không đáng có! 2. Khởi tạo mảng hai chiềuGiống như mảng một chiều, mảng hai chiều cũng có thể khởi tạo trước giá trị. Cú pháp như sau: {Kiểu_phần_tử} {Tên_mảng}[{Số_hàng}][{Số_cột}] = { {{Danh_sách_phần_tử_của_hàng_0}}; {{Danh_sách_phần_tử_của_hàng_1}}; ... {{Danh_sách_phần_tử_của_hàng_cuối}}; };Ví dụ: Khởi tạo mảng hai chiều kích thước 3×43 \times 43×4 gồm 121212 số nguyên: int a[3][4] = { {1, 2, 3, 4}; {5, 6, 7, 8}; {9, 10, 11, 12}; };Ngoài cách khởi tạo mảng với số phần tử cố định, trên mảng hai chiều cũng có thể khởi tạo với các cách không khai báo số lượng hàng, cột hoặc không khởi tạo hết các phần tử giống như mảng một chiều. Bạn đọc có thể tự mình cài đặt các cách khởi tạo khác nhau để kiểm chứng. Trong C++ không chỉ có mảng hai chiều, mà còn có mảng nhiều chiều, nhưng sẽ khá khó tưởng tượng và cũng không thường xuyên sử dụng, vì vậy chúng ta không cần đề cập đến ở đây. 3. Nhập xuất dữ liệu trên mảng hai chiềuVí dụ dưới đây sẽ minh hoạt một chương trình yêu cầu nhập vào một mảng hai chiều kích thước M×NM\times NM×N và in ra toàn bộ mảng đó theo thứ tự hàng cột. Bạn đọc có thể áp dụng đúng phương pháp này cho việc nhập và truy xuất dữ liệu trên các mảng 333 chiều, 444 chiều,...: Giả sử nhập vào mảng kích thước 3×43 \times 43×4 với các giá trị từ 111 tới 12,12,12, chạy chương trình sẽ thu được kết quả sau: Mảng đã nhập vào là: 1 2 3 4 5 6 7 8 9 10 11 12II. Một vài bài toán với mảng hai chiềuCho mảng hai chiều AAA gồm mmm hàng nnn cột, các hàng được đánh số từ 111 tới mmm từ trên xuống dưới, các cột được đánh số từ 111 tới nnn từ trái qua phải. Ô nằm trên giao của hàng i,i,i, cột jjj gọi là ô (i,j)(i, j)(i,j) và có chứa số nguyên ai,ja_{i, j}ai,j. Hãy xác định giá trị lớn nhất trong mảng A?A?A? Input:
Output:
Sample Input: 4 5 1 2 3 4 5 -1 -2 0 3 5 10 4 -5 -10 6 4 4 4 4 4Sample Output: 10Ý tưởngSử dụng kĩ thuật đặt cờ, gán một biến res=a1,1res = a_{1, 1}res=a1,1 để coi như phần tử lớn nhất trong mảng là a1,1a_{1, 1}a1,1. Sau đó duyệt qua tất cả các giá trị trong bảng, nếu phần tử nào lớn hơn resresres thì cập nhật lại resresres bằng phần tử đó. Kết quả cuối cùng chính là resresres. Cài đặt#include2. Tính tổng các phần tử trong mảngĐề bàiCho mảng hai chiều AAA gồm mmm hàng nnn cột, các hàng được đánh số từ 111 tới mmm từ trên xuống dưới, các cột được đánh số từ 111 tới nnn từ trái qua phải. Ô nằm trên giao của hàng i,i,i, cột jjj gọi là ô (i,j)(i, j)(i,j) và có chứa số nguyên ai,ja_{i, j}ai,j. Hãy tính tổng các phần tử trong mảng? Input:
Output:
Sample Input: Sample Output: 45Ý tưởngGiống như mảng một chiều, chúng ta chỉ cần sử dụng một biến sumsumsum để lưu tổng các phần tử trong mảng, rồi duyệt qua toàn bộ các phần tử và tính tổng của chúng. Cài đặt#include3. Tổng đường chéoĐề bàiCho mảng hai chiều dạng vuông AAA gồm mmm hàng mmm cột, các hàng được đánh số từ 111 tới mmm từ trên xuống dưới, các cột được đánh số từ 111 tới nnn từ trái qua phải. Ô nằm trên giao của hàng i,i,i, cột jjj gọi là ô (i,j)(i, j)(i,j) và có chứa số nguyên ai,ja_{i, j}ai,j. Đường chéo chính của ma trận là đường chéo nối ô (1,1)(1, 1)(1,1) với ô (m,m)(m, m)(m,m). Đường chéo phụ của ma trận là đường chéo nối ô (1,m)(1, m)(1,m) với ô (m,1)(m, 1)(m,1). Hãy tính tổng các số trên đường chéo chính và đường chéo phụ của ma trận vuông? Input:
Output:
Sample Input: 3 1 2 1 3 1 8 2 5 4Sample Output: 6 4Ý tưởngMột ô (i,j)(i, j)(i,j) sẽ thuộc đường chéo chính của ma trận nếu như i=ji = ji=j. Còn nếu như i=m−i+1,i = m - i + 1,i=m−i+1, thì ô đó sẽ thuộc đường chéo phụ của ma trận. Ta duyệt qua các phần tử của ma trận và kết hợp câu lệnh if để tính tổng hai đường chéo. Cài đặt#includeIII. Truyền mảng vào hàm như một tham sốMảng cũng có thể được truyền vào hàm giống như một tham số để tính toán. Có 333 cách để truyền mảng vào hàm: Sử dụng tham số mảng có kích cỡ, sử dụng tham số mảng không có kích cỡ và sử dụng con trỏ. Trong bài học này chúng ta sẽ tập trung vào hai cách đầu tiên, còn cách thứ ba với C++ là không cần thiết nên sẽ không đề cập ở đây. Cú pháp:
Khác với việc truyền biến vào hàm, việc truyền mảng vào hàm không phân biệt ra tham trị hay tham chiếu. Khi truyền mảng, hệ thống luôn luôn truyền trực tiếp địa chỉ của phần tử đầu tiên của mảng ban đầu vào hàm, dẫn đến mọi thay đổi trên tham số đại diện trong hàm sẽ tác động đến mảng gốc bên ngoài, dù là theo cách nào trong số các cách trên. Vì vậy cần hết sức chú ý đến dữ liệu khi thực hiện truyền mảng vào hàm. Dưới đây là ví dụ cụ thể: #includeKhi biên dịch và chạy chương trình này, ta sẽ thu được kết quả: Mảng sau khi tăng lên: 2 3 4 5 6Trong phần tham số của hàm void increase(int b[]), nếu ta thay int b[] bằng int b[5] thì cũng vẫn trả ra kết quả tương tự, do hệ thống sẽ không tạo ra một bản sao của mảng mà lấy trực tiếp địa chỉ của mảng gốc rồi truyền vào hàm. Một lưu ý khác là C++ không cho phép trả về trực tiếp một mảng như là kết quả của hàm. Để trả ra kết quả cho hàm là một mảng, cần phải sử dụng con trỏ, nhưng việc đó khá phức tạp. Để tránh việc phải trả ra kết quả là một mảng, ta nên khai báo các mảng là biến toàn cục hoặc sử dụng kiểu mảng động 2. Truyền mảng hai chiềuVề bản chất, mảng hai chiều thực ra là một "mảng chứa các mảng", nghĩa là nó giống như một mảng một chiều nhưng mỗi phần tử lại là một mảng một chiều khác. Do đó, trên bộ nhớ, toàn bộ các phần tử của mảng hai chiều thực ra được viết liền kề với nhau, chứ không phải tạo thành một bảng số như chúng ta vẫn tưởng tượng. Chính vì thế, khi truyền mảng hai chiều vào hàm thì thực chất chương trình vẫn sẽ truyền địa chỉ của phần tử đầu tiên trong mảng hai chiều vào hàm. Chẳng hạn, với một mảng hai chiều 3×33 \times 33×3 thì địa chỉ của các phần tử trên thanh RAM sẽ trông như thế này: Mảng hai chiều cũng có thể được truyền vào hàm như mảng một chiều, tuy nhiên có một số lưu ý khi khai báo tham số hình thức. Có ba cách để truyền mảng hai chiều vào hàm:
Ví dụ, nếu truyền mảng 3×33 \times 33×3 vào hàm void function() thì ta có thể khai báo tham số hình thức theo các cách sau đều được: typedef int arr[100][100]; void function(int a[3][3]); void function(int a[][3]); void function(arr a);Thông thường, cách thứ 222 và 333 sẽ được ưu tiên sử dụng hơn. Lưu ý nhỏ, nếu các bạn truyền mảng từ hai chiều trở lên thì chỉ có chiều đầu tiên được phép để trống kích thước, còn các chiều sau đó đều phải xác định kích thước. Ví dụ, cách khai báo tham số int a[][] sẽ là không hợp lệ và bị báo lỗi khi biên dịch. IV. Tài liệu tham khảo |