一个关于行列试的问题(请一定要研究一下)

我是先让用户输入行列数,然后动态生成一个行列式。代码如下:
void TDvalueForm::makecomponents(int row,int col)
{int temptop=8;
int templeft=8;
int k=0;
for(int i=0;i<row;i++)
{for(int j=0;j<col;j++,k++)
{TEdit *tempEdit=new TEdit(this);
tempEdit->Parent=this;
tempEdit->Top=temptop;
tempEdit->Left=templeft;
tempEdit->Width=65;
tempEdit->Height=21;
list->Add(tempEdit);
templeft+=8+65;
}
templeft=8;
temptop+=8+21;
}
//以下生成一个Label
TLabel *label=new TLabel(this);
label->Parent=this;
label->Top=temptop;
label->Left=templeft;
label->Width=65;
label->Height=21;
label->Caption="Answer:";
//以下生成一个Edit用于显示结果
answerEdit=new TEdit(this);
answerEdit->Parent=this;
answerEdit->Top=temptop;
answerEdit->Left=templeft+8+65;
answerEdit->Height=21;
answerEdit->Width=100;
answerEdit->ReadOnly=true;
//以下生成一个button
okbutton=new TButton(this);//okbutton是TDvalueForm的一个private成员
okbutton->Parent=this;
okbutton->Top=temptop+8+21;
okbutton->Left=templeft;
okbutton->Height=21;
okbutton->Width=65;
okbutton->Caption="Ok";
okbutton->OnClick=okbuttonclick;
}

然后就是运算,代码如下:

void __fastcall TDvalueForm::okbuttonclick(TObject *Sender)
{
bool notzero=true;
double r=1.0,l;
int t,i,j,k;
if(RowN!=ColN)notzero=false;//行列数不等当然值是0啦
//以下是将Edit中的数存放到数组a[]中
for(k=0,i=0;i<RowN;i++)
for(j=0;j<ColN;k++,j++)
a[i][j]=((TEdit*)list->Items[k])->Text.ToDouble();

//以下是行列式值的计算
for(i=0;i<RowN-1;i++)
{for(t=i+1;t<RowN;t++)
{if(a[i][i]==0)notzero=treatzero(a,i,RowN);
if(!notzero)break;
l=a[t][i]/a[i][i];
for(j=i+1;j<2*RowN;j++)
a[t][j]-=a[i][j]*l;
}
if(!notzero)break;
}

if(notzero)
for(i=0;i<RowN;i++)
{r*=a[i][i];answerEdit->Text=AnsiString(r);}
else
answerEdit->Text=0;


问题是:我的程序能运行,而且在输入的行列数少于5的时候能工作,但是如果是大于5虽然他能够产生相应的控键,但是当你输入完数值后,一按那个okbutton它就会出问题,而且c++ uilder的出错信息是"Abstract Error"(好像是无法判断的错误!)
请问哪位知道是什么回事。正无穷个谢谢!
[2344 byte] By [hillhero789-丘] at [2007-12-16]
# 1
当行列式变大时,你在循环中动态生成的tempEdit的次数增多,内存可能出错,建议加入delete tempEdit试试看
jone7318-jone at 2007-10-22 > top of Msdn China Tech,C++ Builder,基础类...
# 2
同意楼上的
xuby5228-潇湘大少 at 2007-10-22 > top of Msdn China Tech,C++ Builder,基础类...
# 3
不知道你是怎么算行列式的.

可以用Guass消去法或者LU decomposition.

我不知道你怎梓treatzero的, 可能你的算法有问题.为什么出奇怪的错误就不知道了.
把你的单元文件贴出来, 一定可以搞定.


ALNG-? at 2007-10-22 > top of Msdn China Tech,C++ Builder,基础类...
# 4
哦不好意思我漏了treatzero它的代码是:
bool TDvalueForm::treatzero(double b[20][40],int i,int n)
{int j,t,k=1;
for(k=1;k<n-i;k++)
if(b[i+k][i]!=0)
{for(j=0;j<n;j++)
{t=b[i+k][j];b[i][j]=b[i+k][j];b[i+k][j]=t;}
return true;
}
return false;
}

其实算法很简单的就是:使矩阵变成是对脚矩阵
然后把它的对角线元素累乘就是了
hillhero789-丘 at 2007-10-22 > top of Msdn China Tech,C++ Builder,基础类...
# 5
to jone7318(jone):
不行啊,因为你知道TList的Items是存储指针数组的啊,如果我把tempEdit delete 了那Tlist 的Item指像什么好呢?
hillhero789-丘 at 2007-10-22 > top of Msdn China Tech,C++ Builder,基础类...
# 6
to ALNG(?) :
Guass和LU decomposition是什么啊?怎么用?告诉我,如果试了不行我再把所有的代码贴出来好不好呢?(因为整个程序的代码不少的)
hillhero789-丘 at 2007-10-22 > top of Msdn China Tech,C++ Builder,基础类...
# 7
如果你只是要算行列式,恐怕也不用派生那么多控件吧?界面那么花哨,华而不实。

ALNG说的对,计算行列式最简单的是用高斯消去法,效率高一点的用LU消去法。如果你没有掌握这两个方法的话,是无法进行行列式的运算的。
TR@SOE at 2007-10-22 > top of Msdn China Tech,C++ Builder,基础类...
# 8
光是计算行列式,Gauss消去法和LU decomposition效率差不多。

听你说的,你应该是用了Gauss elimination.

LU decomposition是把方阵化为一个上三角阵和一个下三角阵之积,这一分解本身很高效,而且分解结果可以存储多次使用,如求逆阵,解线性方程组。

关于LU decomposition, 查一下crout's algorithm, 很妙的。

有个建议,写界面和处理分离的代码。你的计算行列式的代码大量使用了界面元素,这种完全没有意义的紧耦合,使你的代码:调试困难;重用几乎不可能。计算行列式的代码只需要知道有一个矩阵,不需要知道什么list, 而且list里面装的是TEdit, 试问如果你要把程序port到VC++, 他根本没有TList, 也没有TEdit, 你不光要重写界面,还要重写这些界面无关的函数。这样你的代码根本没有积累性,都要从0开始。

现在假如你的矩阵是存储在一个vector of vectors of doubles 里面,或者是一块连续的内存区域里面,或者是一个doulbe **里面[每个double*又指向一行],那么其他人要验证或调试你的代码该多么容易,同样你调试起来也会省事的多。
ALNG-? at 2007-10-22 > top of Msdn China Tech,C++ Builder,基础类...
# 9
to TR@SOE():
如果不产生n行m列个TEdit那我又有什么办法能接受用户输入的行列试呢?
如果有更好的办法我很乐意尝试,请赐教。
to ALNG(?):
很感谢你的建议,我只是一个c++builder的初学者,所以还不能很好的优化我的代码,我会尽量努力的了,但是我很快我就要交我的程序上去(因为我参加了学校的科技节),所以现在我只能尽快把它搞定(只要能无障碍运行了)
如果我不先接受用户的输入那我又有什么办法能把行列试存储到你所说的double **中呢?而接受输入好象没有比用TEdit更方便的方法了吧。
请认真研究一下我的代码,看看有什么问题。谢谢!
hillhero789-丘 at 2007-10-22 > top of Msdn China Tech,C++ Builder,基础类...
# 10
有没有兴趣看我写的一个简例?
//-----------------------------------
// UNIT1.h
//-----------------------------------

//---------------------------------------------------------------------------

#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <Grids.hpp>
#include <ExtCtrls.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
TPanel *Panel1;
TStringGrid *StringGrid1;
TPanel *Panel2;
TLabel *Label1;
TMemo *Memo1;
TButton *Button1;
TButton *Button2;
void __fastcall Memo1Change(TObject *Sender);
void __fastcall Memo1Exit(TObject *Sender);
void __fastcall Button2Click(TObject *Sender);
void __fastcall Button1Click(TObject *Sender);
private: // User declarations
bool bRowCountChanged;
public: // User declarations
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

ALNG-? at 2007-10-22 > top of Msdn China Tech,C++ Builder,基础类...
# 11
//-----------------------------------
// Unit1.cpp
//-----------------------------------

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"

#include <vector>
#include <math.h>
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
bRowCountChanged = true;
Memo1Exit(NULL);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Memo1Change(TObject *Sender)
{
bRowCountChanged = true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Memo1Exit(TObject *Sender)
{
if(bRowCountChanged){
int cnt;
try{
cnt = Memo1->Lines->operator [](0).ToDouble();
if(cnt<1)throw Exception("");
}catch(...){
ShowMessage("Illegal row count");
Memo1->SetFocus();
return;
}
StringGrid1->RowCount = cnt+1;
StringGrid1->ColCount = cnt+1;
for(int i=1; i<=cnt; i++){
StringGrid1->Cells[i][0] = i;
StringGrid1->Cells[0][i] = i;
}
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
for(int i=1; i<StringGrid1->RowCount; i++)
for(int j=1; j<StringGrid1->ColCount; j++)
StringGrid1->Cells[i][j] = double(random(5000))/(random(300)+1);
}
//---------------------------------------------------------------------------

typedef std::vector<double> vec_dbl;
typedef std::vector<vec_dbl> matrix;

void init_matrix(matrix& m, unsigned demension)
{
m.resize(demension);
for(unsigned i=0; i<demension; i++)
m[i].resize(demension);
}

//---------------------------------------------------------------------------

// 计算矩阵的行列式,用Gussian Elimination with row pivoting
double determinant(const matrix& m)
{
matrix tmp(m); // m的本地拷贝
double det = 1;
int swap_cnt = 0; // 行交换的次数

// scaling, divide each row with the maximum of the row
for(unsigned i=0; i<m.size(); i++){ //对每一行
double max = 0; // a very small number
for(unsigned j=0; j<m.size(); j++)
if(fabsl(tmp[i][j])>max)
max = fabs(tmp[i][j]);
for(unsigned j=0; j<m.size(); j++)
tmp[i][j] /= max;
det *= max;
}

for(unsigned i=0; i<tmp.size(); i++){ //对每一行
// 把从i行起第i列最大的行换到第i行
unsigned max_row_no = i;
double max = fabs(tmp[i][i]);
for(unsigned j=i+1; j<tmp.size(); j++){
if(fabs(tmp[j][i])>max){
max_row_no = j;
max = fabs(tmp[j][i]);
}
}
if( max_row_no != i ){ //最大行不是本行,需要交换
tmp[i].swap(tmp[max_row_no]); // very efficient
swap_cnt ++;
}

if( fabs(max)< 1e-20) return 0.0; // single matrix

det *= tmp[i][i]; // 乘以对角线元素

for(unsigned j=i+1; j<m.size(); j++)
tmp[i][j] /= tmp[i][i];

// 把从i+1行开始所有第i列变为0
for(unsigned j=i+1; j<m.size(); j++){
for(unsigned col= i+1; col<m.size(); col++)
tmp[j][col] -= tmp[i][col] * tmp[j][i];
}

}
if(swap_cnt & 1) // 交换了奇数次
det = -det;
return det;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
matrix m;
init_matrix(m, StringGrid1->RowCount-1);
try{
for(int i=1; i<StringGrid1->RowCount; i++)
for(int j=1; j<StringGrid1->RowCount; j++)
m[i-1][j-1] = StringGrid1->Cells[j][i].ToDouble();
}catch(...){
ShowMessage("行列式不完整,或者有不合法的数!");
return;
}
ShowMessage(determinant(m));
}
//---------------------------------------------------------------------------
ALNG-? at 2007-10-22 > top of Msdn China Tech,C++ Builder,基础类...
# 12
// unit1.dfm

object Form1: TForm1
Left = 131
Top = 119
Width = 454
Height = 385
Caption = 'Form1'
Color = clBtnFace
Font.Charset = ANSI_CHARSET
Font.Color = clWindowText
Font.Height = -13
Font.Name = '宋体'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object Panel1: TPanel
Left = 0
Top = 41
Width = 446
Height = 317
Align = alClient
BorderWidth = 3
Caption = 'Panel1'
TabOrder = 0
object StringGrid1: TStringGrid
Left = 4
Top = 4
Width = 438
Height = 309
Align = alClient
Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect, goEditing]
TabOrder = 0
end
end
object Panel2: TPanel
Left = 0
Top = 0
Width = 446
Height = 41
Align = alTop
TabOrder = 1
object Label1: TLabel
Left = 8
Top = 8
Width = 131
Height = 13
Caption = '请输入方阵的行[列]数'
end
object Memo1: TMemo
Left = 144
Top = 5
Width = 41
Height = 21
Alignment = taRightJustify
Lines.Strings = (
'5')
TabOrder = 0
WantReturns = False
OnChange = Memo1Change
OnExit = Memo1Exit
end
object Button1: TButton
Left = 328
Top = 8
Width = 89
Height = 25
Caption = '计算行列式'
TabOrder = 1
OnClick = Button1Click
end
object Button2: TButton
Left = 224
Top = 8
Width = 75
Height = 25
Caption = '随机填数'
TabOrder = 2
OnClick = Button2Click
end
end
end
ALNG-? at 2007-10-22 > top of Msdn China Tech,C++ Builder,基础类...
# 13
非常感谢ALNG(?) 大哥
hillhero789-丘 at 2007-10-22 > top of Msdn China Tech,C++ Builder,基础类...
# 14
上面是用Gaussian Elimination with row pivoting 求方阵行列式。

有个小错误, Memo1Exit中应该把bRowCountChanged设为false.

我想你可以比较一下,如果把程序转为VC或Console Application, 我的功能代码完全不受影响。 当然,我这个也做的很粗,matrix完全够资格抽象成一个类的。

如果你能够按上面的原则重写你的程序,我想你的赢面会大一点,你说呢?

有疑问欢迎与我讨论。
ALNG-? at 2007-10-22 > top of Msdn China Tech,C++ Builder,基础类...
# 15
非常感谢ALNG(?)我很想和你交个朋友(如果你愿意的话),我的qq是48302334
hillhero789-丘 at 2007-10-22 > top of Msdn China Tech,C++ Builder,基础类...
# 16
all right.

I 'll QQ you tomorrow.
ALNG-? at 2007-10-22 > top of Msdn China Tech,C++ Builder,基础类...
# 17
我今天才发现你的方法好象要用到一个borlandmm.dll但是好像没有的啊?什么回事啊?(不是编译的问题而是运行的问题)
hillhero789-丘 at 2007-10-22 > top of Msdn China Tech,C++ Builder,基础类...
# 18
应该不会。估计是你的代码其他地方的问题。我这里可以生成独立的exe.在其他没有装bcb的机子上运行也没有问题。如果你需要,我可以发一个给你。

对了,如何产生一个standalone executable, 你不会不知道吧?

ALNG-? at 2007-10-22 > top of Msdn China Tech,C++ Builder,基础类...