30/09/2018, 16:23
Xin nhận xét class Ma Trận trong C++
file header của e như sau:
matran.h
#include <iomanip>
#include <complex>
#include <iostream>
using namespace std;
#define MAX 10
class MaTran
{
public:
MaTran(int soHang, int soCot);
~MaTran();
void inMaTran(float a[][MAX],int soHang,int soCot);
void nhapMaTran();
void chuyenVi(int in);
bool dinhThuc(int in);
float phuHop(float a[][MAX],int hangXoa, int cotXoa);
void nghichDao();
int hang();
void xoaHang();
void xoaCot();
void congMaTran();
void truMaTran();
void nhanMT_So();
void nhanMT_MT();
private:
int soHang,soCot;
float det;
float mt[MAX][MAX];
};
MaTran::MaTran(int soHang, int soCot){
this->soHang=soHang;
this->soCot=soCot;
}
MaTran::~MaTran(){
for(int i=0;i<MAX;i++)
for(int j=0;j<MAX;j++)
mt[i][j]=0;
soHang=soCot=det=0;
}
void MaTran::inMaTran(float a[][MAX],int soHang,int soCot){
cout<<fixed<<setprecision(2);
for(int i=0;i<soHang;i++){
cout<<"
";
for(int j=0;j<soCot;j++) cout<<setw(5)<<a[i][j]<<" ";
}
cout<<endl;
}
void MaTran::nhapMaTran(){
for(int i=0;i<soHang;i++)
for(int j=0;j<soCot;j++){
cout<<" Phan tu ["<<i+1<<","<<j+1<<"] = ";
cin>>mt[i][j];
}
cout<<"Ma tran ban vua nhap la:";
inMaTran(mt,soHang,soCot);
}
void MaTran::chuyenVi(int in=0){
float cv[MAX][MAX];
for(int i=0;i<soCot;i++){
for(int j=0;j<soHang;j++)
cv[i][j]=mt[j][i];
}
cout<<"Ma tran chuyen vi cua ma tran A la:";
inMaTran(cv,soCot,soHang);
}
bool MaTran::dinhThuc(int in=0){
if(soHang==soCot){
//Dua ma tran ve ma tran tam giac tren
int d=0; //Bien d: dem so lan doi 2 hang cua ma tran
//B1: tim gia tri khac 0 dau tien cua moi cot cho vao duong cheo chinh
for(int i=0;i<soHang;i++){
if(mt[i][i]==0)
//Neu phan tu mt[i][i]=0 thi tim phan tu khac 0 dau tien trong cot i roi doi cho 2 hang
for(int k=i+1;k<soHang;k++){
if(mt[k][i]!=0){
for(int j=0;j<soCot;j++){
float t=mt[i][j];
mt[i][j]=mt[k][j];
mt[k][j]=t;
}
d++;
break; //Khi doi cho xong thi thoat ra, khong tim nua
}
}
if(mt[i][i]!=0)
//Neu phan tu mt[i][i]!=0 thi dua cac phan tu cot i phia duoi mt[i][i] ve 0
for(int k=i+1;k<soHang;k++){
double tl=mt[k][i]/mt[i][i]; //bien tl de tim ti le 2 hang
for(int j=0;j<soCot;j++)
mt[k][j]-=mt[i][j]*tl;
}
else{
//Neu sau cac buoc tren ma phan tu mt[i][i]=0 thi dinh thuc cua ma tran = 0, ta dua ra ket luan va thoat ra.
det=0;
if(in==1) cout<<" Dinh thuc cua ma tran A la: det(A)="<<det<<endl;
return 1;
}
}
//Tinh dinh thuc bang tich cac phan tu tren duong cheo chinh
det=1.0;
for(int i=0;i<soCot;i++) det*=mt[i][i];
det*=pow(-1,d); //ham pow(x,n)=x^n
if(in==1) cout<<" Dinh thuc cua ma tran A la: det(A)="<<det<<endl;
return 1;
} else{
return 0;
}
}
float MaTran::phuHop(float a[][MAX],int hangXoa, int cotXoa){
//Ma tran phu hop xoa di 1 hang va 1 cot
MaTran ph(soHang-1,soCot-1);
for(int i=0;i<hangXoa;i++){
for(int j=0;j<cotXoa;j++)
ph.mt[i][j]=a[i][j];
for(int j=cotXoa;j<ph.soCot;j++)
ph.mt[i][j]=a[i][j+1];
}
for(int i=hangXoa;i<ph.soHang;i++){
for(int j=0;j<cotXoa;j++)
ph.mt[i][j]=a[i+1][j];
for(int j=cotXoa;j<ph.soCot;j++)
ph.mt[i][j]=a[i+1][j+1];
}
ph.dinhThuc(); //tinh dinh thuc
if(ph.det==0) return 0; //neu dinh thuc bang 0 thi phan tu phu hop se bang 0
float pTu=(float) ph.det/det; //neu khong thi tinh phan tu phu hop bang thuong cua dinh thuc ma tran phu hop
pTu*=pow(-1,hangXoa+cotXoa); //va dinh thuc ma tran can tim nghich dao nhan voi -1^(hangxoa+cotxoa).
//if(abs(pTu)<0.01 && abs(pTu)>0) cout<<pTu*10000000000<<endl; //Kiem tra xem phan tu -0.00 co phai la do lam tron khong.
return pTu;
}
void MaTran::nghichDao(){
if(!dinhThuc() || det==0) cout<<" Ma Tran A khong kha nghich
";
else{
dinhThuc();
//Tao ma tran lay gia tri cua ma tran chuyen vi
float cv[MAX][MAX];
for(int i=0;i<soHang;i++)
for(int j=0;j<soCot;j++)
cv[i][j]=mt[j][i];
//Ma tran co cac phan tu la ti le dinh thuc cua ma tran phu hop va dinh thuc ma tran A
for(int i=0;i<soHang;i++)
for(int j=0;j<soCot;j++)
mt[i][j]=phuHop(cv,i,j);
cout<<"Ma tran nghich dao cua ma tran A la:";
inMaTran(mt,soHang,soCot);
}
}
int MaTran::hang(){
//Dua ma tran ve ma tran tam giac tren
for(int i=0;i<soHang-1;i++){
for(int j=i;j<soCot;j++){
if(mt[i][j]==0)
for(int k=i+1;k<soHang;k++)
if(mt[k][j]!=0){
for(int u=0;u<soCot;u++){
float t=mt[i][u];
mt[i][u]=mt[k][u];
mt[k][u]=t;
}
break;
}
if(mt[i][j]!=0){
for(int k=i+1;k<soHang;k++){
double tl=(double) mt[k][j]/mt[i][j];
for(int u=0;u<soCot;u++){
mt[k][u]-=mt[i][u]*tl;
}
}
break;
}
}
}
//Tim hang (dem hang chua phan tu != 0 co chi so lon nhat, chi so do chinh la hang cua ma tran
int r=0;
for(int i=soHang-1;i>=0;i--){
for(int j=0;j<soCot;j++)
if(abs(mt[i][j])!=0){
r=i+1;
break;
}
if(r>0) break;
}
return r;
}
void MaTran::xoaHang(){
int x=0;
do{
cout<<"Nhap vao hang thu x (0<x<"<<soHang+1<<") ban muon xoa: ";
cin>>x;
} while(x<1 || x>soHang);
x--;
soHang--;
for(int j=0;j<soCot;j++)
for(int i=x;i<soHang;i++)
mt[i][j]=mt[i+1][j];
cout<<"Ma tran A sau khi xoa hang thu "<<x+1<<" la:";
inMaTran(mt,soHang,soCot);
}
void MaTran::xoaCot(){
int x=0;
do{
cout<<"Nhap vao cot thu x (0<x<"<<soCot+1<<") ban muon xoa: ";
cin>>x;
} while(x<1 || x>soCot);
x--;
soCot--;
for(int i=0;i<soHang;i++){
for(int j=x;j<soCot;j++)
mt[i][j]=mt[i][j+1];
}
cout<<"Ma tran A sau khi xoa cot thu "<<x+1<<" la:";
inMaTran(mt,soHang,soCot);
}
void MaTran::congMaTran(){
float b[MAX][MAX];
cout<<"Nhap ma tran B:
";
for(int i=0;i<soHang;i++)
for(int j=0;j<soCot;j++){
cout<<" Phan tu ["<<i+1<<","<<j+1<<"] = ";
cin>>b[i][j];
}
cout<<"Ma tran ban vua nhap la:";
inMaTran(b,soHang,soCot);
for(int i=0;i<soHang;i++)
for(int j=0;j<soCot;j++){
mt[i][j]+=b[i][j];
}
cout<<"Tong cua 2 ma tran A va B la:";
inMaTran(mt,soHang,soCot);
}
void MaTran::truMaTran(){
float b[MAX][MAX];
cout<<"Nhap ma tran B:
";
for(int i=0;i<soHang;i++)
for(int j=0;j<soCot;j++){
cout<<" Phan tu ["<<i+1<<","<<j+1<<"] = ";
cin>>b[i][j];
}
cout<<"Ma tran ban vua nhap la:";
inMaTran(b,soHang,soCot);
for(int i=0;i<soHang;i++)
for(int j=0;j<soCot;j++){
mt[i][j]-=b[i][j];
}
cout<<"Hieu cua 2 ma tran A va B la:";
inMaTran(mt,soHang,soCot);
}
void MaTran::nhanMT_So(){
float x=1;
cout<<"Nhap vao so x: ";
cin>>x;
for(int i=0;i<soHang;i++)
for(int j=0;j<soCot;j++)
mt[i][j]*=x;
cout<<"Tich cua "<<x<<" voi ma tran A la:";
inMaTran(mt,soHang,soCot);
}
void MaTran::nhanMT_MT(){
float b[MAX][MAX];
int cotB=10;
cout<<"Nhap so cot cua ma tran B: ";
cin>>cotB;
int hangB=soCot;
cout<<"
Nhap ma tran B:
";
for(int i=0;i<hangB;i++)
for(int j=0;j<cotB;j++){
cout<<" Phan tu ["<<i+1<<","<<j+1<<"] = ";
cin>>b[i][j];
}
cout<<"Ma tran ban vua nhap la:";
inMaTran(b,hangB,cotB);
float tong[MAX][MAX]={};
for(int i=0;i<soHang;i++)
for(int j=0;j<cotB;j++){
for(int k=0;k<soCot;k++)
tong[i][j]+=mt[i][k]*b[k][j];
}
cout<<"Tich cua ma tran A va ma tran B la:";
inMaTran(tong,soHang,cotB);
}
file main.php
#include "matran.h"
int main(){
int soHang,soCot;
cout<<"Nhap so hang cua ma tran A: ";
cin>>soHang;
cout<<"Nhap so cot cua ma tran A: ";
cin>>soCot;
MaTran a(soHang,soCot);
cout<<"
Nhap ma tran A:
";
a.nhapMaTran();
cout<<"
+ Danh sach thao tac:
";
cout<<" Chuyen vi: 1| Dinh thuc: 2| Nghich dao: 3|";
cout<<"
Hang: 4| Xoa hang: 5| Xoa cot: 6|";
cout<<"
Cong ma tran: 7| Tru ma tran: 8|";
cout<<"
Ma tran x So: 9| Ma tran x Ma tran: 10|";
cout<<"
Ket thuc phien lam viec: 0
";
while(true){
int tt=0;
cout<<"
+ Chon thao tac ma ban muon thuc hien (0->10): ";
cin>>tt;
cout<<endl;
MaTran b(soHang,soCot);
b=a;
switch(tt){
case 1: b.chuyenVi(1); break;
case 2: if(!b.dinhThuc(1)) cout<<" Ma tran khong hop le!
"; break;
case 3: b.nghichDao(); break;
case 4: cout<<" Hang cua ma tran A la: "<<b.hang()<<endl; break;
case 5: b.xoaHang(); break;
case 6: b.xoaCot(); break;
case 7: b.congMaTran(); break;
case 8: b.truMaTran(); break;
case 9: b.nhanMT_So(); break;
case 10: b.nhanMT_MT(); break;
default: tt=0; break;
}
if(tt==0) break;
}
return 0;
}
e không biết như thế đã ổn chưa ạ, a @ltd cho e nhận xét với
Bài liên quan
cái này có bị gì ko ạ?
e thấy nó hình như ko cần thiết
xem hộ e với mấy a ơi @ltd @david15894
Hàm hủy để như thế thì không cần thiết cho lắm. Có một số lưu ý sau: hàm hủy nên để là virtual. Hàm tạo thì nên viết thế này
Cuối cùng là nên phân ra file header riêng và file .cpp riêng.
1. Tại sao lại phải in ma trận sau mỗi lần thực hiện các hàm cộng/trừ/nhân? Cứ thực hiện âm thầm rồi để người ta gọi hàm in lúc cần thiết có phải hay hơn không?
2. Tại sao lại yêu cầu nhập các ma trận để cộng/trừ/nhân? Thiết kế các hàm đó lấy tham số là một ma trận khác rồi mới thực hiện phép tính.
3. Nói chung là các phép xuất nhập chỉ nên xuất hiện ở trong các hàm xuất/nhập. Không nên cho vào các hàm tính toán.
Nếu làm cả một class Ma Trận chỉ để làm bài tập này thì cứ thực hiện theo kiểu hướng thủ tục còn hơn. Còn nếu muốn sử dụng class Ma Trận sau này nữa thì nên làm cho chuẩn.
Lúc đầu e định làm cấp phát động, nhưng nó cứ thay đổi giá trị ma trân gốc dù đã gán ma trận b=a để thao tác trên b. nên là e bỏ cấp phát động, làm mảng cứng.
cái này e học trên mạng ko hiểu nên e ko dùng.
e ko biết làm ạ.
thuật toán nhân là e làm theo công thức trong sách giáo khoa mà a.
vâng, cái này chắc là e sẽ khắc phục
là sao ạ? e ko hiểu câu này lắm ạ
tại sao phải dùng hàm ảo ạ?
trước e có đọc thấy người ta làm thế, nhưng kết quả giống với cách gán trong {}
tại sao lại nên viết như vậy ạ?
có 1 file header và .cpp rồi à a.
Giải thích về hàm tạo, nếu em không init giá trị cho các thuộc tính trước khi vào thân hàm tạo thì bước 1: nó sẽ gán một giá trị bất kì nào đó cho biến đấy, bước 2, em vào thân hàm tạo và gán giá trị lần nữa, tổng cộng là 2 lần.
Về hàm hủy: em tạo 1 con trỏ base class để trỏ tới 1 đối tượng ở class được kế thừa. Khi em hủy con trỏ đó thì nó chỉ gọi hàm hủy của base class và không gọi hàm hủy của lớp được kế thừa. Như vậy có khả năng là memory leak.
VD:
Sẽ gọi hàm hủy của Matrix.
Về vấn đề này thì cần viết lại operator=.
Khoan đã nói về thuật toán nhân. Ở bài này bạn sử dụng cấu trúc dữ liệu mảng hai chiều, điều này không hề hiệu quả, vì mỗi lần truy cập một phần tử nào đó đều phải cần thêm một phép nhân. VD: mt[i][j] tương đương với (mt + iMAX+j).
Giải pháp: sử dụng mảng một chiều.
Tức là viết dưới dạng các hàm, không cần phải bọc trong một class.
cái này e không hiểu lắm ạ
operator e ko hiểu a ạ. nó cứ rắc rối thế nào ấy ạ.
e biết Mảng 2 chiều thực chất cũng là mảng 1 chiều, nhưng mà khi thao tác thì cũng phải nhân mới ra đc phần tử dòng khác chứ ạ?
à, thầy giáo e bảo làm hướng đối tượng mới được cộng điểm thêm ạ.
nói chung em cứ hiểu là để việc hủy nó diễn ra ok nhất thì cần virtual ở đằng trước.
VD anh đã nêu ở dưới đó, MatrixXX là đối tượng kế thừa từ matrix, đối tượng em tạo ra có type là MatrixXX* nhưng con trỏ đến nó lại có type là Matrix*, dẫn đến việc gọi hàm hủy nó gọi vào hàm hủy của Matrix chứ không phải là MatrixXXX.
[quote=“htwap, post:10, topic:3244”]
e biết Mảng 2 chiều thực chất cũng là mảng 1 chiều, nhưng mà khi thao tác thì cũng phải nhân mới ra đc phần tử dòng khác chứ ạ?[/quote]
Không phải lúc nào cũng cần làm việc đó.
Ví du phép trừ và cộng ma trận: chỉ cần một vòng lặp qua tất cả các phần tử là đủ. Với mảng 2 chiều thì cần 2 vòng lặp lồng nhau và thêm O(n^2) phép nhân. Phép nhân và các phép toán khác có thể cải tiến mà không cần phải truy cập theo cặp <hàng, cột>
Chương trình của bạn không phải là lập trình hướng đối tượng, nó chỉ là các thủ tục bọc trong một class. Hướng đối tượng là “đóng gói”, “kế thừa”, “đa hình”. Về hình thức thì nó có class nhưng bản chất thì có cũng được mà không có cũng được.
Đây là mẫu của lớp Ma trận, bạn có thể điền code vào những chỗ cần điền:
Đoạn code để test lớp MaTran:
link ideone: http://ideone.com/JIwTpb
Có thể thấy là bây giờ sử dụng đối tượng ma trận rất đơn giản, y như các kiểu dữ liệu bình thường.
Bạn có thể thêm vào các hàm cần thiết vào lớp ma trận. Còn về bài tập thì các chức năng như in, yêu cầu nhập, … nên đưa ra các hàm ngoài thay vì cho vào lớp ma trận.
:d bạn @noname_nofame lập trình hệ thống à?
Không, vẫn chưa đi làm ngày nào.
cái này video của a Đạt có.
vâng, e cảm ơn a ạ, e sẽ cố phân tích cái bài của a.
Viết class không phải là hướng đối tượng là ý làm sao hả bạn. Mình không hiểu lắm