实验一图的创建、遍历、及其MST的构建
实验目的
ö 图的创建 。
ö 基于深度优先的图的遍历算法的设计与实现 。
ö 基于广度优先的图的遍历算法的设计与实现 。
ö 基于Prim算法的最小生成树的构建。
ö 基于Kruskal算法的最小生成树的构建 。
实验过程
#include<iostream>
#include” KJL_Queue.h”
using namespace std;
//定义为prim服务的辅助结点
struct primnode
{public:
char begvex;//开始结点
char endvex;//结束结点
int lowcost;//中间权值};
class KJL_Graphmtx//图的邻接矩阵定义
{ public:
KJL_Graphmtx(int sz=DefaultVertices);//构造函数
~KJL_Graphmtx()//析构函数
{delete []VerticesList;delete []Edge;}
bool GraphEmpty()//判断图是否为空
{ if(numEdges==0)return true;
else return false; }
bool GraphFull()//判断图是否为满
{if(numVertices==maxVertices||numEdges==maxVertices*(maxVertices-1)/2)
return true;
else
return false; }
int NumberOfVertices()//返回当前顶点数
{ return numVertices; }
int NumberOfEdges()//返回当前边数
{ return numEdges; }
char getValue(int i)//取顶点i的值,i不合理返回0
{ return i>=0&&i<=numVertices ? VerticesList[i] : NULL; }
int getWeight(int v1,int v2)//取边(v1,v2)上的权值
{ return v1!=-1&&v2!=-1 ? Edge[v1][v2] : 0; }
int getFirstNeighbor(int v);//取顶点v的第一个邻接顶点
int getNextNeighbor(int v,int w);//取v的邻接顶点w的下一邻接顶点
bool insertVertex(char vertex);//插入顶点vertex
bool insertEdge(int v1,int v2,int weight);//插入边(v1,v2),权为weight
bool removeVertex(int v);//删去顶点v和所有与它相关联的边
bool removeEdge(int v1,int v2);//在图中删去边(v1,v2)
int getVertexPos(char vertex)//给出顶点vertex的位置,如果该顶点不在图内则返回-1
{ for(int i=0;i<numVertices;i++)
if(VerticesList[i]==vertex) return i;
return -1; }
int mini();//求图中所有边的最小权值
bool input();//输入函数
bool output();//输出函数
void kruskal();//kruskal算法
void prim();//prim算法
protected:
int maxVertices;//图中最大顶点数
int numEdges;//图中当前边数
int numVertices;//图中当前顶点数
private:
char *VerticesList;//顶点表
int * *Edge;//邻接矩阵
int visit[50];//便利时的辅助工具
primnode closeedge[50];//为实现prim 函数的辅助结点};
KJL_Graphmtx::KJL_Graphmtx(int sz)//构造函数
{ maxVertices=sz;
numVertices=0;
numEdges=0;
int i,j;
VerticesList=new char[maxVertices];//创建顶点表数组
Edge=(int * *)new int *[maxVertices];//创建邻接矩阵数组
for(i=0;i<maxVertices;i++)
Edge[i]=new int[maxVertices];
for(i=0;i<maxVertices;i++)//邻接矩阵初始化
for(j=0;j<maxVertices;j++)
Edge[i][j]=(i==j)? 0 : maxWeight;}
int KJL_Graphmtx::getFirstNeighbor(int v)//给出顶点位置v的第一个邻接顶点的位置,如果找不到,则函数返回-1
{ if(v!=-1)
{ for(int i=0;i<numVertices;i++)
if(Edge[v][i]>0&&Edge[v][i]<maxWeight)return i; }
return -1;}
int KJL_Graphmtx::getNextNeighbor(int v,int w)//给出顶点v的某邻接顶点w的下一个邻接顶点的位置,如果找不到,则函数返回-1
{ if(v!=-1&&w!=-1)
{for(int i=w+1;i<numVertices;i++)
if(Edge[v][i]>0&&Edge[v][i]<maxWeight) return i; }
return -1;}
bool KJL_Graphmtx::insertVertex(char vertex)//插入顶点vertex
{ if(numVertices==maxVertices) return false;//顶点表满,不插入
VerticesList[numVertices++]=vertex;
return true;}
bool KJL_Graphmtx::insertEdge(int v1,int v2,int weight)//插入边(v1,v2),权为weight
{if(v1!=-1&&v1<numVertices&&v2!=-1&&v2<numVertices&&Edge[v1][v2]==maxWeight)////插入条件(???)
{ Edge[v1][v2]=Edge[v2][v1]=weight;
numEdges++;
return true; }
else
return false;}
bool KJL_Graphmtx::removeVertex(int v)//删去顶点v和所有与它相关联的边
{ if(v<0&&v>=numVertices)return false;//v不在图中,不删除
int i,j;
VerticesList[v]=VerticesList[numVertices-1];//顶点表中删除该结点
for(i=0;i<numVertices;i++)//减去与v相关联的边数
if(Edge[i][v]>0&&Edge[i][v]<maxWeight) numEdges--;
for(i=0;i<numVertices;i++)//用最后一列填补第v列
Edge[i][v]=Edge[i][numVertices-1];
numVertices--;//顶点个数减1
for(j=0;j<numVertices;j++)//用最后一行填补第v行
Edge[v][j]=Edge[numVertices-1][j];
return true;}
bool KJL_Graphmtx::removeEdge(int v1,int v2)//在图中删去边(v1,v2)
{if(v1>-1&&v1<numVertices&&v2>-1&&v2<numVertices&&Edge[v1][v2]>0&&Edge[v1][v2]<maxWeight)
{Edge[v1][v2]=Edge[v2][v1]=maxWeight;//删除边(v1,v2)
numEdges--;
return true; }
else
return false;}
bool KJL_Graphmtx::input()
{ int i,j,k,n,m;
char e1,e2;
int weight;
cout<<"请输入顶点数和边数:"<<endl;
cin>>n>>m;//输入顶点数n和边数m
cout<<"请输入顶点的值:"<<endl;
for(i=0;i<n;i++)//依次输入顶点的值
{ cin>>e1;
this->insertVertex(e1); }
i=0;
while(i<m)
{ cout<<"请输入端点信息:"<<endl;
cin>>e1>>e2>>weight;//输入端点信息
j=this->getVertexPos(e1);//查顶点号
k=this->getVertexPos(e2);
if(j==-1||k==-1)
cout<<"边两端点信息输入有误,请重新输入!"<<endl;
else
{ this->insertEdge(j,k,weight);
i++; }}
return true;}
bool KJL_Graphmtx::output()//输出函数
{ int i,j,n,m;
char e1,e2;
int w;
n=this->NumberOfVertices();
m=this->NumberOfEdges();
cout<<"顶点的个数为:"<<n<<endl;
cout<<"边的条数为:"<<m<<endl;
cout<<"所有边的信息为:"<<endl;
for(i=0;i<n;i++)
for(j=i+1;j<n;j++)
{ w=this->getWeight(i,j);
if(w>0&&w<maxWeight)
{ e1=this->getValue(i);
e2=this->getValue(j); cout<<"("<<e1<<","<<e2<<","<<w<<")"<<endl;}}
return true;}
int KJL_Graphmtx::mini()//求图中所有边的最小权值,并返回
{ static int i;
int min=0;
for (int j=0;j<numVertices;j++)
{ if(!visit[j])
{if(closeedge[min].lowcost>closeedge[j].lowcost)
{ min=j; } } }
i=min;
cout<<"包括边("<<closeedge[i].begvex<<","<<closeedge[i].endvex<<")";
return i;}
//图的深度优先搜索函数////////
void DFS(KJL_Graphmtx & G,int v,bool visited[]);//先声明函数,后使用
void DFS(KJL_Graphmtx & G,char & v)//从顶点v出发,对图G进行深度优先遍历的主要过程
{ int i,loc,n=G.NumberOfVertices();//取图中顶点的个数
bool * visited=new bool[n];//创建辅助数组
for(i=0;i<n;i++)//初始化辅助数组visited
{ visited[i]=0; }
loc=G.getVertexPos(v);//取得v结点在图中的位置
DFS(G,loc,visited);//从顶点0开始深度优先搜索
delete []visited;}
void DFS(KJL_Graphmtx & G,int v,bool visited[])//从顶点v出发,对图G进行深度优先遍历的子过程
//从顶点位置v出发,以深度优先的次序访问所有可读入的尚未访问过的顶点。
//算法中用到一个vistied,对已访问过的顶点做访问标记。
{ cout<<G.getValue(v)<<endl;//访问顶点v
visited[v]=1;//顶点v作访问标记
int w=G.getFirstNeighbor(v);//找v的第一个邻接顶点w
while(w!=-1)//若邻接顶点w存在
{ if(visited[w]==0)
DFS(G,w,visited);//若w未被访问,递归访问顶点w
w=G.getNextNeighbor(v,w);//取v排在w后的下一个邻接顶点 }}
//图的广度优先搜索函数////////
void BFS(KJL_Graphmtx G,char v)//从顶点v出发,以广度优先的次序横向搜索图,算法中使用了一个队列。
{ int i,w,n=G.NumberOfVertices();//去图中的定点个数
bool *visited=new bool[n];//用来记录顶点是否被访问过,被访问值为1,为被访问值为0
for(i=0;i<n;i++)//初始化
visited[i]=0;
int loc=G.getVertexPos(v);//取顶点v的位置号
cout<<G.getValue(loc)<<endl;//访问顶点v
visited[loc]=1;//做已访问标记
KJL_Queue Q;//定义一个辅助队列
Q.EnQueue(loc);//顶点进队,实现分层访问
while(!Q.IsEmpty())//循环访问所有结点,判断队列是否为空
{Q.DeQueue(loc);//从队列中退出顶点loc
w=G.getFirstNeighbor(loc);//找顶点loc的第一个邻接点w
while(w!=-1)//若邻接点w存在
{if(visited[w]==false)//若未被访问
{cout<<G.getValue(w)<<endl;//访问顶点w
visited[w]=1;//标记w已经被访问
Q.EnQueue(w);//顶点w进队列w=G.getNextNeighbor(loc,w);//找顶点loc的下一个邻接顶点,重复检测v的所有邻接顶点 }}
delete [] visited;}
//////kruskal函数的实现//////
void KJL_Graphmtx::kruskal()
{ int a,b,k=0;
int min=maxWeight;
int Edge1[20][20];
for (int m=0;m<numVertices;m++)
visit[m]=m;//每一个顶点属于一颗树
for (int i=0;i<numVertices;i++)
for(int j=0;j<numVertices;j++)
Edge1[i][j]=Edge[i][j];
while (k<numVertices-1)
{ min=maxWeight;
for (int i=0;i<numVertices;i++)
{ for (int j=0;j<numVertices;j++)
{ if (Edge1[i][j]<min)
{ a=i; b=j; min=Edge1[i][j]; }}}
if (visit[a]!=visit[b])
{ cout<<"包括边("<<VerticesList[a]<<","<<VerticesList[b]<<")";
k++;
for (int n=0;n<numVertices;n++)
{ if (visit[n]==visit[b]) visit[n]=visit[a]; } }
else Edge1[a][b]=Edge[b][a]=maxWeight; }
cout<<endl;}
////////////Prim函数的实现////
void KJL_Graphmtx::prim()
{ char u;
cout<<"请输入起始顶点:"<<endl; cin>>u;
int i=this->getVertexPos(u); visit[i]=1;
for(int j=0;j<numVertices;j++)
{closeedge[j].begvex=u;
closeedge[j].endvex=VerticesList[j];
closeedge[j].lowcost=Edge[i][j]; }
for (int m=1;m<numVertices;m++)
{ int n=mini(); visit[n]=1; closeedge[n].lowcost=maxWeight;
for (int p=0;p<numVertices;p++)
{ if(!visit[p])
{ if(Edge[p][n]<closeedge[p].lowcost)
{ closeedge[p].lowcost=Edge[p][n];
closeedge[p].begvex=VerticesList[n];} } } }}
实验结果
实验体会
经过这次实验让我更深刻的理解了C++类的的结构,能够对二维数组的动态开辟空间和释放空间有了更深刻的理解,对图的遍历及构建最小生成树也有了深刻的体会。
总之,在这次试验中,学到了许多,也提高了自己的编程能力。
实验二、快速排序算法的实现
实验目的
ö 选取表中一个元素r[k](一般选第一个元素),令x=r[k]称为控制关键字,用控制关键字和无序区中其余元素关键字进行比较
ö 设置两个指示器i,j,分别表示线性表第一个和最后一个元素位置
ö 将j逐渐减小,逐次比较r[j]与x,直到出现一个r[j]<x,然后将r[j]移动到r[i]位置。将i逐渐增大,并逐次比较r[i]与x,直到发现一个r[i]>x,然后将r[i]移动到r[j]位置
ö 重复上述过程,知道i=j位置,并将x移动到r[j]位置,此时线性表以x为界分割成两个子区间
ö 实现快速排序功能
实验过程
#include<iostream>
using namespace std;
const maxSize=100;
int partition(int data[],int first,int end)//在实现快速排序函数时要用,这是快速排序的一趟算法
{
int i=first;
int j=end;
int temp;
while(i<j)
{
while(i<j&&data[i]<=data[j]) //向右扫描
j--;
if(i<j)
{
temp=data[i];
data[i]=data[j];
data[j]=temp;
i++;
}
while(i<j&&data[i]<=data[j]) //向左扫描
i++;
if(i<j)
{
temp=data[i];
data[i]=data[j];
data[j]=temp;
j--;
}
}
return i;
}
class KJL_CSort
{
public:
KJL_CSort();
~KJL_CSort();
public: // 排序算法的具体实现
void QuickSort();
void input();
void output();
private: // 成员变量
int *data;
int first,end;
int size;//当前数组大小
};
KJL_CSort::KJL_CSort()
{
first =0;
end=0;
size=0;
data=new int [maxSize];
for(int j=0;j<maxSize;j++)
data[j]=0;
}
KJL_CSort::~KJL_CSort()
{
delete []data;
}
void KJL_CSort::input()
{
int i;
cout<<"请输入数组大小:"<<endl;
cin>>size;
end=size-1;
cout<<"输入数组的值:"<<endl;
int m;
for(i=0;i<size;i++)
{
cin>>data[i];
}
}
void KJL_CSort::output()
{
int i;
for(i=0;i<size;i++)
cout<<data[i]<<" ";
cout<<endl;
}
void KJL_CSort::QuickSort()
{
int pivot;
if(first<end)
{
pivot=partition(data,first,end);
end=pivot-1;
QuickSort();
first=pivot+1;
QuickSort();
}
first=0;
end=size-1;
}
void main()
{
KJL_CSort biao;
biao.input();
cout<<"快速排序前的顺序:"<<endl;
biao.output();
biao.QuickSort();
cout<<"快速排序后的顺序:"<<endl;
biao.output();
}
实验结果
实验体会
快速排序法,是众多排序方法中的一种,这种方法的优点在于它的比较次数少,每经过一趟比较,都可以把一个无序的数组分成两个部分,左边的部分全部小于(大于)右边的部分。
在实现这个算法过程中,采用的时递归调用的方式。这让我对递归又有了更深层次的理解,对数组的排序,也不仅仅局限于冒泡,选择排序,在快速排序的基础上设计了以个快速排序类。
实验三、矩阵类的设计与实现
实验目的
ö 按照上述矩阵类的设计,完成相应函数的编码
ö 对于矩阵数据的存储,可以选用如下两种方式来实现
ö 使用double** _A来存储矩阵;
实验过程
#include<iostream>
#include<cmath>
using namespace std;
const maxSize=100;
#define maxnum 50
class KJL_CMatrix
{
public:
KJL_CMatrix(); // 默认构造函数
KJL_CMatrix(int row, int column); // 构造函数一
KJL_CMatrix(const KJL_CMatrix& m); // 复制构造函数
~KJL_CMatrix(); // 默认析构函数
KJL_CMatrix& operator=(const KJL_CMatrix& m); // 赋值运算符
bool operator==(const KJL_CMatrix& m); // 比括较运算符
bool operator!=(const KJL_CMatrix& m); // 比括较运算符
KJL_CMatrix operator+(const KJL_CMatrix& m); // 加运算符
KJL_CMatrix operator-(const KJL_CMatrix& m); // 减运算符
KJL_CMatrix& operator+=(const KJL_CMatrix& m); //+=运算符
KJL_CMatrix& operator-=(const KJL_CMatrix& m); // -=运算符
KJL_CMatrix operator-();// 取负数
KJL_CMatrix operator*(const KJL_CMatrix& m); // 乘法运算符
void input();//矩阵输入
void output(); // 输出该矩阵
KJL_CMatrix transpose(); // 矩阵转置
////////////////////////////////////////////////////////////
KJL_CMatrix yuzishi(int i,int j);//求矩阵的第(i,j)的余子式
double hanglieshi();//求矩阵的行列式
KJL_CMatrix bansui();//求矩阵的伴随矩阵
KJL_CMatrix inverse(); // 矩阵求逆(伴随矩阵除以行列式)
//////////////////////////////////////////////////////////////
KJL_CMatrix inv();//矩阵求逆(用高斯约当法)
KJL_CMatrix & change(int k,int l);//交换矩阵的第k行和第l行
int max_cloumn(int k);//求矩阵第k列的最大行数
//////////////////////////////////////////////////////////////
// 设置(i,j)的值
void setValue(int row, int column, double value) { _A[row][column] = value; }
double getValue(int row, int column) const { return _A[row][column]; }
// 设置行、列的值
void setRow(const int row) { _row = row; }
int getRow() const { return _row; }
void setColunm(const int column) { _column = column; }
int getColumn() const { return _column; }
public:// 成员变量
double** _A; // 或用这个定义vector<vector<double> > _A;
int _row, /*行*/ _column; // 列
};
KJL_CMatrix::KJL_CMatrix()//矩阵默认构造函数
{
_row=0;
_column=0;
_A=(double * *) new double [maxSize];
int i;
for(i=0;i<maxSize;i++)
_A[i]=new double[maxSize];
int j;
for(i=0;i<maxSize;i++)
for(j=0;j<maxSize;j++)
_A[i][j]=0;
}
KJL_CMatrix::KJL_CMatrix(int row, int column)//构造函数重载
{
_row=row;
_column=column;
_A=(double * *) new double [maxSize];
int i;
for(i=0;i<maxSize;i++)
_A[i]=new double[maxSize];
int j;
for(i=0;i<maxSize;i++)
for(j=0;j<maxSize;j++)
_A[i][j]=0;
}
KJL_CMatrix::KJL_CMatrix(const KJL_CMatrix& m)//复制构造函数
{
_row=m._row;
_column=m._column;
int i,j;
_A=(double * *) new double [maxSize];
for(i=0;i<maxSize;i++)
_A[i]=new double[maxSize];
for(i=0;i<maxSize;i++)//初始化
for(j=0;j<maxSize;j++)
_A[i][j]=0;
for(i=0;i<_row;i++)
for(j=0;j<_column;j++)
{
_A[i][j]=m._A[i][j];
}
}
KJL_CMatrix::~KJL_CMatrix()//析构函数
{
delete []_A;
}
void KJL_CMatrix::input()//输入函数
{
int i,j;
cout<<"请输入矩阵的行数:"<<endl;
cin>>_row;
cout<<"请输入矩阵的列数:"<<endl;
cin>>_column;
cout<<"请输入矩阵:"<<endl;
for(i=0;i<_row;i++)
for(j=0;j<_column;j++)
{
cin>>_A[i][j];
}
}
void KJL_CMatrix::output()//输出函数
{
int i,j;
for(i=0;i<_row;i++)
{ for(j=0;j<_column;j++)
{
cout<<_A[i][j]<<" ";
}
cout<<endl;
}
}
KJL_CMatrix & KJL_CMatrix::operator=(const KJL_CMatrix & m)//=函数重载
{
_row=m._row;
_column=m._column;
int i,j;
for(i=0;i<_row;i++)
for(j=0;j<_column;j++)
{
_A[i][j]=m._A[i][j];
}
return *this;
}
KJL_CMatrix KJL_CMatrix::operator-()//取负号负号重载
{
int i,j;
for(i=0;i<_row;i++)
for(j=0;j<_column;j++)
{
_A[i][j]=-_A[i][j];
}
return *this;
}
KJL_CMatrix KJL_CMatrix::operator+(const KJL_CMatrix& m)//加号函数重载
{
if(_row!=m._row||_column!=m._column)
{
cerr<<"矩阵不能相加!"<<endl;
}
int i,j;
for(i=0;i<_row;i++)
for(j=0;j<_column;j++)
{
_A[i][j]=_A[i][j]+m._A[i][j];
}
return *this;
}
KJL_CMatrix& KJL_CMatrix::operator+=(const KJL_CMatrix& m)//+=符号函数重载
{
if(_row!=m._row||_column!=m._column)
{
cerr<<"矩阵不能+=!"<<endl;
}
int i,j;
for(i=0;i<_row;i++)
for(j=0;j<_column;j++)
{
_A[i][j]+=m._A[i][j];
}
return *this;
}
KJL_CMatrix& KJL_CMatrix::operator-=(const KJL_CMatrix& m)//-=符号函数重载
{
if(_row!=m._row||_column!=m._column)
{
cerr<<"矩阵不能-=!"<<endl;
}
int i,j;
for(i=0;i<_row;i++)
for(j=0;j<_column;j++)
{
_A[i][j]-=m._A[i][j];
}
return *this;
}
KJL_CMatrix KJL_CMatrix::operator-(const KJL_CMatrix& m)//减号函数重载
{
if(_row!=m._row||_column!=m._column)
{
cerr<<"矩阵不能相减!"<<endl;
}
int i,j;
for(i=0;i<_row;i++)
for(j=0;j<_column;j++)
{
_A[i][j]=_A[i][j]-m._A[i][j];
}
return *this;
}
KJL_CMatrix KJL_CMatrix::operator*(const KJL_CMatrix& m)//乘号符号函数重载
{
KJL_CMatrix temp(_row,m._column);
if(_column!=m._row)
{
cerr<<"矩阵不能相乘!"<<endl;
}
int i,j,n;
for(i=0;i<_row;i++)
for(j=0;j<_row;j++)
{
for(n=0;n<_column;n++)
temp._A[i][j]+=_A[i][n]*m._A[n][j];
}
return temp;
}
bool KJL_CMatrix::operator ==(const KJL_CMatrix& m)//==函数重载
{
if(_row!=m._row||_column!=m._column)
return false;
int i,j;
for(i=0;i<_row;i++)
for(j=0;j<_column;j++)
{
if(_A[i][j]!=m._A[i][j])
return false;
}
return true;
}
bool KJL_CMatrix::operator !=(const KJL_CMatrix& m)//!=函数重载
{
if(_row!=m._row||_column!=m._column)
return true;
int i,j;
for(i=0;i<_row;i++)
for(j=0;j<_column;j++)
{
if(_A[i][j]!=m._A[i][j])
return true;
}
return false;
}
KJL_CMatrix KJL_CMatrix::transpose()//转置函数
{
KJL_CMatrix tem;
tem._row=this->_column;
tem._column=this->_row;
int i,j;
for(i=0;i<_row;i++)
for(j=0;j<_column;j++)
{
tem._A[j][i]=_A[i][j];
}
return tem;
}
KJL_CMatrix KJL_CMatrix::yuzishi(int i,int j)//求矩阵的余子式
{
KJL_CMatrix temp;
temp._row=this->_row-1;
temp._column=this->_column-1;
int m,n,k=0,l;
for(m=0;m<_row;m++)
{
l=0;
for(n=0;n<_column;n++)
{
if(m!=i&&n!=j)
{
temp._A[k][l]=_A[m][n];
}
if(n!=j) l++;
}
if(m!=i) k++;
}
return temp;
}
double KJL_CMatrix::hanglieshi()//求矩阵的行列式
{
if(_row!=_column)
{cerr<<"此矩阵无行列式"<<endl; }
if(_row==1&&_column==1)
return _A[0][0];
else
{
int i;
double sum=0;
for(i=0;i<_column;i++)
{ sum+=pow(-1,i)*_A[0][i]*this->yuzishi(0,i).hanglieshi();
}
return sum;
}
}
KJL_CMatrix KJL_CMatrix::bansui()//求伴随矩阵
{
KJL_CMatrix temp;
temp._column=this->_column;
temp._row=this->_row;
int i,j;
for(i=0;i<_row;i++)
for(j=0;j<_column;j++)
{
temp._A[i][j]=pow(-1,i+j)*this->yuzishi(i,j).hanglieshi(); }
return temp;
}
KJL_CMatrix KJL_CMatrix::inverse()//矩阵求逆
{
KJL_CMatrix temp;
int n;
n=this->hanglieshi();
temp=this->bansui();
int i,j;
for(i=0;i<_row;i++)
for(j=0;j<_column;j++)
{
temp._A[i][j]/=n;
}
return temp;
}
KJL_CMatrix & KJL_CMatrix::change(int k,int l)//交换矩阵的第k行和第l行
{
int i;
double j;
for(i=0;i<_column;i++)
{ j=_A[k][i];
_A[k][i]=_A[l][i];
_A[l][i]=j;
}
return *this;
}
int KJL_CMatrix::max_cloumn(int k)//求矩阵第k列中从第k个元素之后绝对值最大的行数
{ int m=k;
double max=fabs(_A[k][k]);
for(int i=k+1;i<_column;i++)
{ if(fabs(_A[i][k])>max)
{ max=fabs(_A[i][k]);
m=i; }
}
return m;
}
KJL_CMatrix KJL_CMatrix::inv()//矩阵求逆,通过行列变换
{
int i,j,m;
KJL_CMatrix E1;
E1=*this;
if(this->_row!=this->_column)
{
cerr<<"该矩阵不能求逆"<<endl;
}
else
{ if(E1.hanglieshi()==0)
{cerr<<"该矩阵不可逆:"<<endl; }
else
{/////////把矩阵E赋值成单位阵
KJL_CMatrix E;//创建一个和当前方阵阶数相同的单位矩阵
E._row=E1._row;
E._column=E1._column;
for(i=0;i<E1._row;i++)
for(j=0;j<E1._row;j++)
{E._A[i][j]=0;}
for(i=0;i<E1._row;i++)
E._A[i][i]=1;
//化上三角阵
int i,j,hang;
for(i=0;i<E1._column-1;i++)//
{ hang=E1.max_cloumn(i);
if(hang!=i)
{ E1.change(i,hang);
E.change(i,hang); }
double xishu; for(m=i+1;m<E1._row;m++)//第m行
{
xishu=E1._A[m][i]/E1._A[i][i]; for(j=0;j<E1._column;j++)
{ E1._A[m][j]=E1._A[m][j]-xishu*E1._A[i][j]; E._A[m][j]=E._A[m][j]-xishu*E._A[i][j];}} ////上面为求上三角阵 }
///////////////////////////化对角阵
for(i=this->_column-1;i>0;i--)//
{ double xishu1;
for(m=0;m<i;m++)
{ xishu1=E1._A[m][i]/E1._A[i][i];
for(j=0;j<this->_column;j++)
{ E1._A[m][j]=E1._A[m][j]-xishu1*E1._A[i][j]; E._A[m][j]=E._A[m][j]-xishu1*E._A[i][j];
}}}
///////////////////////////////////矩阵单位化
double xishu3;
for(i=0;i<E1._column;i++)
{ xishu3=1/E1._A[i][i];
for(j=0;j<E1._column;j++)
{ E1._A[i][j]*=xishu3;
E._A[i][j]*=xishu3;}} return E; }}}
void main()
{ KJL_CMatrix array1,array2,array3;
array1.input();
array2=array1.inv();
array3=array2*array1;
array1.output();
array2.output();
array3.output();}
实验结果
实验体会
这个实验,是真正考验我们对所学知识的掌握,这里综合了我们所学的C++面向对象类的设计,以及我们如何利用自己所学的知识,把它转换为代码C++程序。
比如在实现矩阵的转置和矩阵的求逆这方面。根据我们以前所学的线性代数的知识,我们知道,要求一个矩阵的逆,可以求它的伴随矩阵除以该矩阵的行列式。这里就涉及到怎么求矩阵的行列式的问题,这是一个递归调用的问题。
然而,老师又给我们提供了几种推荐的方法,列主元素法法,高斯约当消去法等等。通过构造一个跟需求矩阵同阶的单位矩阵,然后通过行变换把该矩阵变成单位阵,原来的单位阵也做相应变化,便得到所求的逆矩阵。这知识一些思想,有了这些思想,我们就可以写出程序得到我们想要的结果了。
这个实验还让我们复习了以前所学的函数重载,比如矩阵的运算,运算符重载等等。经过这次实验真是获益匪浅。大大提高了我得编程能力。
实验四、基于直接法(列主元素法)与迭代法
(Jacobi迭代与Gauss-Seidel迭代法)的线性方程组求解
实验目的
基于直接法(列主元素法)与迭代法(Jacobi迭代与Gauss-Seidel迭代法)的线性方程组求解.对各种迭代的收敛条件,和收敛速度做个比较。掌握这些函数的实现。
实验过程
主要的几个函数:
KJL_CMatrix & KJL_CMatrix::change(int k,int l)//交换矩阵的第k行和第l行
{ int i;
double j;
for(i=0;i<_column;i++)
{
j=_A[k][i];
_A[k][i]=_A[l][i];
_A[l][i]=j;
}
return *this;
}
int KJL_CMatrix::max_cloumn(int k)//求矩阵第k列中从第k个元素之后绝对值最大的行数
{ int m=k;
double max=fabs(_A[k][k]);
for(int i=k+1;i<_column;i++)
{ if(fabs(_A[i][k])>max)
{ max=fabs(_A[i][k]);
m=i; }}
return m;
}
KJL_CMatrix KJL_CMatrix::inv()//矩阵求逆,通过行列变换
{
int i,j,m;
KJL_CMatrix E1;
E1=*this;
if(this->_row!=this->_column)
{cerr<<"该矩阵不能求逆"<<endl; }
else
{
if(E1.hanglieshi()==0)
{cerr<<"该矩阵不可逆:"<<endl; }
else
{///////把矩阵E赋值成单位阵
KJL_CMatrix E;//创建一个和当前方阵阶数相同的单位矩阵
E._row=E1._row;
E._column=E1._column;
for(i=0;i<E1._row;i++)
for(j=0;j<E1._row;j++)
{E._A[i][j]=0;}
for(i=0;i<E1._row;i++)
E._A[i][i]=1;
//化上三角阵
int i,j,hang;
for(i=0;i<E1._column-1;i++)//
{ hang=E1.max_cloumn(i);
if(hang!=i)
{ E1.change(i,hang);
E.change(i,hang);}
double xishu; for(m=i+1;m<E1._row;m++)//第m行
{
xishu=E1._A[m][i]/E1._A[i][i]; for(j=0;j<E1._column;j++)
{ E1._A[m][j]=E1._A[m][j]-xishu*E1._A[i][j]; E._A[m][j]=E._A[m][j]-xishu*E._A[i][j];}} ////上面为求上三角阵 }
///////////////////////////化对角阵
for(i=this->_column-1;i>0;i--)//
{ double xishu1;
for(m=0;m<i;m++)
{ xishu1=E1._A[m][i]/E1._A[i][i];
for(j=0;j<this->_column;j++)
{ E1._A[m][j]=E1._A[m][j]-xishu1*E1._A[i][j]; E._A[m][j]=E._A[m][j]-xishu1*E._A[i][j];
}}}
///////////////////////////////////矩阵单位化
double xishu3;
for(i=0;i<E1._column;i++)
{
xishu3=1/E1._A[i][i];
for(j=0;j<E1._column;j++)
{ E1._A[i][j]*=xishu3;
E._A[i][j]*=xishu3;}} return E; }}}
void KJL_CMatrix::find(int& f)const
{ int i;
for(i=0;i<this->_row;i++)
if(this->_A[i][i]!=0) f=1;
else f=0;
};
void jacobi(const KJL_CMatrix& a)
{ int f=1;
a.find(f);
if(f==0) {cerr<<"该矩阵不满足迭代求解条件!"<<endl; exit(1); }
else
{
KJL_CMatrix x,w;
x.setColunm(1);
x.setRow(a.getColumn());
w.setColunm(1);
w.setRow(a.getColumn());
int i;
double z;
for(i=1;i<=x._row;i++)
{ cout<<"请输入等式右侧的第"<<i<<"个值:";
cin>>z;
w._A[i-1][0]=z;
}
for(i=1;i<=x._row;i++)
{ cout<<"请输入X"<<i<<"的近似值:";
cin>>z;
x.setValue(i, 1, z);
}
i=1;
while(i<=20)
{ int j, k;
for(j=1;j<=x._row;j++)
{ double sum=0.0;
for(k=1;k<j;k++)
{sum=sum-(a._A[j-1][k-1])*(x._A[k-1][0]);}
for(k=j+1;k<=x._row;k++) {sum=sum-(a._A[j-1][k-1])*(x._A[k-1][0]);}
sum+=w._A[j-1][0];
x._A[j-1][0]=sum/a._A[j-1][j-1];
}
i++;
}
for(i=1;i<=x._row;i++)
cout<<"X"<<i<<" = "<<x._A[i-1][0]<<endl;
}}
实验结果
1、 解方程如下(列主元素法)
jacobi迭代矩阵D.inv()*(L+U)矩阵结果:
Gauss-Seidel矩阵(D-L).inv()*U矩阵结果:
实验体会
通过实验结果,和我们所学的知识知道,只要迭代矩阵的谱半径小于1,迭代就是收敛的,与右边所取得的近似值无关。这个实验是基于矩阵类的实现,进一步加深对矩阵操作的理解。右端对迭代收敛是无影响。
实验五Windows绘图
实验目的
通过在C++ MFC中绘制各种图形,能够定义各种画刷、线条、颜色。能够绘制出Windows基本图形。
实验过程
#include "stdafx.h"
#include "cbs.h"
#include "cbsDoc.h"
#include "cbsView.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// CCbsView
IMPLEMENT_DYNCREATE(CCbsView, CView)
BEGIN_MESSAGE_MAP(CCbsView, CView)
//{{AFX_MSG_MAP(CCbsView)
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
//}}AFX_MSG_MAP
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
END_MESSAGE_MAP()
// CCbsView construction/destruction
CCbsView::CCbsView()
{
// TODO: add construction code here
this->m_bDragging=false;
}
CCbsView::~CCbsView()
{
}
BOOL CCbsView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return CView::PreCreateWindow(cs);
}
// CCbsView drawing
void CCbsView::OnDraw(CDC* pDC)
{ CCbsDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
pDC->SetViewportOrg(150,150); // 当前原点位置移动到(50, 50)的位置
COLORREF rgbBkClr = RGB(192,192,192); // 定义灰色
pDC->SetBkColor(rgbBkClr); // 背景色为灰色
pDC->SetTextColor(RGB(0,0,128));// 文本颜色为兰色
pDC->TextOut(250,10,"我*****的*****绘*****图*****板!");
CPen *pPenOld, PenNew;
int nPenStyle[]= {
PS_SOLID, // 实线
PS_DOT, // 点线
PS_DASH, // 虚线
PS_DASHDOT, // 点划线
PS_DASHDOTDOT, // 双点划线
PS_NULL, // 空的边框
PS_INSIDEFRAME, // 边框实线
};
char *strStyle[]={"Solid", "Dot", "Dash", "DashDot",
"DashDotDot", "Null", "InsideFrame"};
pDC->TextOut(50, 65, "用不同样式的画笔绘图");
pDC->TextOut(400, 40, ");
for(int i=0; i<7; i++)
{ // 用不同样式的画笔绘图
if(PenNew.CreatePen(nPenStyle[i],1,RGB(0,0,0)))
{ //创建画笔 pPenOld=pDC->SelectObject(&PenNew); // 选择画笔 pDC->TextOut(45,90+20*i,strStyle[i]);
pDC->MoveTo(150,100+20*i);
pDC->LineTo(200,100+20*i);
pDC->SelectObject(pPenOld); // 恢复原来的画笔
PenNew.DeleteObject(); // 删除底层的GDI对象
}
else {MessageBox("不能创建画笔!"); }
}
char *strWidth[]={"1", "2", "3", "4", "5", "6", "7"};
pDC->TextOut(260, 65, "用不同宽度的画笔绘图");
for(i=0; i<7; i++)
{ // 用不同宽度的画笔绘图
if(PenNew.CreatePen(PS_SOLID,i+1,RGB(0,0,0)))
{ // 创建画笔
pPenOld=pDC->SelectObject(&PenNew); // 选择画笔
pDC->TextOut(260, 90+20*i,strWidth[i]);
pDC->MoveTo(300, 100+20*i);
pDC->LineTo(400, 100+20*i);
pDC->SelectObject(pPenOld); // 恢复原来的画笔
PenNew.DeleteObject(); // 删除底层的GDI对象
}
else { MessageBox("不能创建画笔!"); }
}
char *strColor[]={"红","绿","蓝","黄","紫","青","灰"};
COLORREF rgbPenClr[]={RGB(255,0,0), RGB(0,255,0),
RGB(0,0,255), RGB(255,255,0), RGB(255,0,255),
RGB(0,255,255), RGB(192,192,192)};
pDC->TextOut(460,65,"用不同颜色的画笔绘图");
for(i=0; i<7; i++)
{ // 用不同颜色的画笔绘图
CPen *pPenNew=new CPen(PS_INSIDEFRAME,10,rgbPenClr[i]);
// 创建画笔的另一种方法 pPenOld=pDC->SelectObject(pPenNew); // 选择创建的画笔
pDC->TextOut(460,90+20*i, strColor[i]);
pDC->MoveTo(500,100+20*i);
pDC->LineTo(600,100+20*i);
pDC->SelectObject(pPenOld); // 恢复原来的画笔
delete pPenNew; // 自动删除底层的GDI对象
}
}
// CCbsView printing
BOOL CCbsView::OnPreparePrinting(CPrintInfo* pInfo)
{ // default preparation
return DoPreparePrinting(pInfo);}
void CCbsView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add extra initialization before printing
}
void CCbsView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add cleanup after printing
}
// CCbsView diagnostics
#ifdef _DEBUG
void CCbsView::AssertValid() const
{
CView::AssertValid();
}
void CCbsView::Dump(CDumpContext& dc) const
{ CView::Dump(dc);}
CCbsDoc* CCbsView::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CCbsDoc)));
return (CCbsDoc*)m_pDocument;
}
#endif //_DEBUG
// CCbsView message handlers
void CCbsView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
if(m_bDragging)
{
CClientDC dc(this);
OnPrepareDC(&dc);
dc.DPtoLP(&point);
dc.MoveTo(this->m_ptOrigin);
dc.LineTo(point);
m_ptOrigin = point;
}
CView::OnMouseMove(nFlags, point);
}
void CCbsView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CClientDC dc(this);
OnPrepareDC(&dc); // 调整设备环境的属性
dc.DPtoLP(&point); // 将设备坐标转换为逻辑坐标
SetCapture(); // 捕捉鼠标
//::SetCursor(m_hCross); // 设置十字光标
m_ptOrigin=point;
m_bDragging=TRUE; // 设置拖拽标记
CView::OnLButtonDown(nFlags, point);
}
void CCbsView::OnLButtonUp(UINT nFlags, CPoint point)
{ // TODO: Add your message handler code here and/or call default
m_bDragging = false;
实验结果
实验结果运行不成功。
实验体会
由于这次实验是基于MFC的第一次操作,老师讲解的时候,我没有认真听讲。所以只能看别人的代码,通过学习别人的程序来加深自己的理解。上面都是看了别人的代码,进行了适当的修改而得来,让自己有点偷窃的感觉,没有真正领悟到实验中得精华。让我深表遗憾,当然在以后的学习中,我会加强对这方面的练习。
实验六、面向对象的高程网平差程序设计与实现
实验目的
在矩阵实现的基础上,通过对水准网平差。了解和掌握平差原理,在C++面向对象程序设计中,实现平差,要求得出平差值和平差精度,可能的话能画出误差椭圆。
实验过程
#include<iostream>
#include<cmath>
using namespace std;
const maxSize=100;
#define maxnum 50
class KJL_CMatrix
{
public:
KJL_CMatrix(); // 默认构造函数
KJL_CMatrix(int row, int column); // 构造函数一
KJL_CMatrix(const KJL_CMatrix& m); // 复制构造函数
~KJL_CMatrix(); // 默认析构函数
KJL_CMatrix& operator=(const KJL_CMatrix& m); // 赋值运算符
bool operator==(const KJL_CMatrix& m); // 比括较运算符
bool operator!=(const KJL_CMatrix& m); // 比括较运算符
KJL_CMatrix operator+(const KJL_CMatrix& m); // 加运算符
KJL_CMatrix operator-(const KJL_CMatrix& m); // 减运算符
KJL_CMatrix& operator+=(const KJL_CMatrix& m); //+=运算符
KJL_CMatrix& operator-=(const KJL_CMatrix& m); // -=运算符
KJL_CMatrix operator-();// 取负数
KJL_CMatrix operator*(const KJL_CMatrix& m); // 乘法运算符
void input();//矩阵输入
void output(); // 输出该矩阵
KJL_CMatrix transpose(); // 矩阵转置
////////////////////////////////////////////////////////////
KJL_CMatrix yuzishi(int i,int j);//求矩阵的第(i,j)的余子式
double hanglieshi();//求矩阵的行列式
KJL_CMatrix bansui();//求矩阵的伴随矩阵
KJL_CMatrix inverse(); // 矩阵求逆(伴随矩阵除以行列式)
//////////////////////////////////////////////////////////////
KJL_CMatrix inv();//矩阵求逆(用高斯约当法)
KJL_CMatrix & change(int k,int l);//交换矩阵的第k行和第l行
int max_cloumn(int k);//求矩阵第k列的最大行数
//////////////////////////////////////////////////////////////
// 设置(i,j)的值
void setValue(int row, int column, double value) { _A[row][column] = value; }
double getValue(int row, int column) const { return _A[row][column]; }
// 设置行、列的值
void setRow(const int row) { _row = row; }
int getRow() const { return _row; }
void setColunm(const int column) { _column = column; }
int getColumn() const { return _column; }
public:// 成员变量
double** _A; // 或用这个定义vector<vector<double> > _A;
int _row, /*行*/ _column; // 列
};
KJL_CMatrix::KJL_CMatrix()//矩阵默认构造函数
{
_row=0;
_column=0;
_A=(double * *) new double [maxSize];
int i;
for(i=0;i<maxSize;i++)
_A[i]=new double[maxSize];
int j;
for(i=0;i<maxSize;i++)
for(j=0;j<maxSize;j++)
_A[i][j]=0;
}
KJL_CMatrix::KJL_CMatrix(int row, int column)//构造函数重载
{
_row=row;
_column=column;
_A=(double * *) new double [maxSize];
int i;
for(i=0;i<maxSize;i++)
_A[i]=new double[maxSize];
int j;
for(i=0;i<maxSize;i++)
for(j=0;j<maxSize;j++)
_A[i][j]=0;
}
KJL_CMatrix::KJL_CMatrix(const KJL_CMatrix& m)//复制构造函数
{
_row=m._row;
_column=m._column;
int i,j;
_A=(double * *) new double [maxSize];
for(i=0;i<maxSize;i++)
_A[i]=new double[maxSize];
for(i=0;i<maxSize;i++)//初始化
for(j=0;j<maxSize;j++)
_A[i][j]=0;
for(i=0;i<_row;i++)
for(j=0;j<_column;j++)
{
_A[i][j]=m._A[i][j];
}
}
KJL_CMatrix::~KJL_CMatrix()//析构函数
{
delete []_A;
}
void KJL_CMatrix::input()//输入函数
{
int i,j;
cout<<"请输入矩阵的行数:"<<endl;
cin>>_row;
cout<<"请输入矩阵的列数:"<<endl;
cin>>_column;
cout<<"请输入矩阵:"<<endl;
for(i=0;i<_row;i++)
for(j=0;j<_column;j++)
{
cin>>_A[i][j];
}
}
void KJL_CMatrix::output()//输出函数
{
int i,j;
for(i=0;i<_row;i++)
{ for(j=0;j<_column;j++)
{
cout<<_A[i][j]<<" ";
}
cout<<endl;
}
}
KJL_CMatrix & KJL_CMatrix::operator=(const KJL_CMatrix & m)//=函数重载
{
_row=m._row;
_column=m._column;
int i,j;
for(i=0;i<_row;i++)
for(j=0;j<_column;j++)
{
_A[i][j]=m._A[i][j];
}
return *this;
}
KJL_CMatrix KJL_CMatrix::operator-()//取负号负号重载
{
int i,j;
for(i=0;i<_row;i++)
for(j=0;j<_column;j++)
{
_A[i][j]=-_A[i][j];
}
return *this;
}
KJL_CMatrix KJL_CMatrix::operator+(const KJL_CMatrix& m)//加号函数重载
{
if(_row!=m._row||_column!=m._column)
{
cerr<<"矩阵不能相加!"<<endl;
}
int i,j;
for(i=0;i<_row;i++)
for(j=0;j<_column;j++)
{
_A[i][j]=_A[i][j]+m._A[i][j];
}
return *this;
}
KJL_CMatrix& KJL_CMatrix::operator+=(const KJL_CMatrix& m)//+=符号函数重载
{
if(_row!=m._row||_column!=m._column)
{
cerr<<"矩阵不能+=!"<<endl;
}
int i,j;
for(i=0;i<_row;i++)
for(j=0;j<_column;j++)
{
_A[i][j]+=m._A[i][j];
}
return *this;
}
KJL_CMatrix& KJL_CMatrix::operator-=(const KJL_CMatrix& m)//-=符号函数重载
{
if(_row!=m._row||_column!=m._column)
{
cerr<<"矩阵不能-=!"<<endl;
}
int i,j;
for(i=0;i<_row;i++)
for(j=0;j<_column;j++)
{
_A[i][j]-=m._A[i][j];
}
return *this;
}
KJL_CMatrix KJL_CMatrix::operator-(const KJL_CMatrix& m)//减号函数重载
{
if(_row!=m._row||_column!=m._column)
{
cerr<<"矩阵不能相减!"<<endl;
}
int i,j;
for(i=0;i<_row;i++)
for(j=0;j<_column;j++)
{
_A[i][j]=_A[i][j]-m._A[i][j];
}
return *this;
}
KJL_CMatrix KJL_CMatrix::operator*(const KJL_CMatrix& m)//乘号符号函数重载
{
KJL_CMatrix temp(_row,m._column);
if(_column!=m._row)
{
cerr<<"矩阵不能相乘!"<<endl;
}
int i,j,n;
for(i=0;i<_row;i++)
for(j=0;j<_row;j++)
{
for(n=0;n<_column;n++)
temp._A[i][j]+=_A[i][n]*m._A[n][j];
}
return temp;
}
bool KJL_CMatrix::operator ==(const KJL_CMatrix& m)//==函数重载
{
if(_row!=m._row||_column!=m._column)
return false;
int i,j;
for(i=0;i<_row;i++)
for(j=0;j<_column;j++)
{
if(_A[i][j]!=m._A[i][j])
return false;
}
return true;
}
bool KJL_CMatrix::operator !=(const KJL_CMatrix& m)//!=函数重载
{
if(_row!=m._row||_column!=m._column)
return true;
int i,j;
for(i=0;i<_row;i++)
for(j=0;j<_column;j++)
{
if(_A[i][j]!=m._A[i][j])
return true;
}
return false;
}
KJL_CMatrix KJL_CMatrix::transpose()//转置函数
{
KJL_CMatrix tem;
tem._row=this->_column;
tem._column=this->_row;
int i,j;
for(i=0;i<_row;i++)
for(j=0;j<_column;j++)
{
tem._A[j][i]=_A[i][j];
}
return tem;
}
KJL_CMatrix KJL_CMatrix::yuzishi(int i,int j)//求矩阵的余子式
{
KJL_CMatrix temp;
temp._row=this->_row-1;
temp._column=this->_column-1;
int m,n,k=0,l;
for(m=0;m<_row;m++)
{
l=0;
for(n=0;n<_column;n++)
{
if(m!=i&&n!=j)
{
temp._A[k][l]=_A[m][n];
}
if(n!=j) l++;
}
if(m!=i) k++;
}
return temp;
}
double KJL_CMatrix::hanglieshi()//求矩阵的行列式
{
if(_row!=_column)
{
cerr<<"此矩阵无行列式"<<endl;
}
if(_row==1&&_column==1)
return _A[0][0];
else
{
int i;
double sum=0;
for(i=0;i<_column;i++)
{ sum+=pow(-1,i)*_A[0][i]*this->yuzishi(0,i).hanglieshi();
}
return sum;
}
}
KJL_CMatrix KJL_CMatrix::bansui()//求伴随矩阵
{
KJL_CMatrix temp;
temp._column=this->_column;
temp._row=this->_row;
int i,j;
for(i=0;i<_row;i++)
for(j=0;j<_column;j++)
{ temp._A[i][j]=pow(-1,i+j)*this->yuzishi(i,j).hanglieshi();
}
return temp;
}
KJL_CMatrix KJL_CMatrix::inverse()//矩阵求逆
{
KJL_CMatrix temp;
int n;
n=this->hanglieshi();
temp=this->bansui();
int i,j;
for(i=0;i<_row;i++)
for(j=0;j<_column;j++)
{
temp._A[i][j]/=n;
}
return temp;
}
KJL_CMatrix & KJL_CMatrix::change(int k,int l)//交换矩阵的第k行和第l行
{
int i;
double j;
for(i=0;i<_column;i++)
{
j=_A[k][i];
_A[k][i]=_A[l][i];
_A[l][i]=j;
}
return *this;
}
int KJL_CMatrix::max_cloumn(int k)//求矩阵第k列中从第k个元素之后绝对值最大的行数
{
int m=k;
double max=fabs(_A[k][k]);
for(int i=k+1;i<_column;i++)
{
if(fabs(_A[i][k])>max)
{
max=fabs(_A[i][k]);
m=i;
}
}
return m;
}
KJL_CMatrix KJL_CMatrix::inv()//矩阵求逆,通过行列变换
{
int i,j,m;
KJL_CMatrix E1;
E1=*this;
if(this->_row!=this->_column)
{
cerr<<"该矩阵不能求逆"<<endl;
}
else
{
if(E1.hanglieshi()==0)
{
cerr<<"该矩阵不可逆:"<<endl;
}
else
{
/////////////把矩阵E赋值成单位阵
KJL_CMatrix E;//创建一个和当前方阵阶数相同的单位矩阵
E._row=E1._row;
E._column=E1._column;
for(i=0;i<E1._row;i++)
for(j=0;j<E1._row;j++)
{
E._A[i][j]=0;
}
for(i=0;i<E1._row;i++)
E._A[i][i]=1;
//化上三角阵
int i,j,hang;
for(i=0;i<E1._column-1;i++)//
{
hang=E1.max_cloumn(i);
if(hang!=i)
{
E1.change(i,hang);
E.change(i,hang);
}
double xishu;
for(m=i+1;m<E1._row;m++)//第m行
{
xishu=E1._A[m][i]/E1._A[i][i];
for(j=0;j<E1._column;j++)
{ E1._A[m][j]=E1._A[m][j]-xishu*E1._A[i][j];
E._A[m][j]=E._A[m][j]-xishu*E._A[i][j];
}
}
///////////////////////////////////////////////上面为求上三角阵
}
///////////////////////////化对角阵
for(i=this->_column-1;i>0;i--)//
{
double xishu1;
for(m=0;m<i;m++)
{
xishu1=E1._A[m][i]/E1._A[i][i];
for(j=0;j<this->_column;j++)
{ E1._A[m][j]=E1._A[m][j]-xishu1*E1._A[i][j]; E._A[m][j]=E._A[m][j]-xishu1*E._A[i][j];
}
}
}
///////////////////////////////////矩阵单位化
double xishu3;
for(i=0;i<E1._column;i++)
{
xishu3=1/E1._A[i][i];
for(j=0;j<E1._column;j++)
{
E1._A[i][j]*=xishu3;
E._A[i][j]*=xishu3;
}
}
return E;
}
}
}
struct KJL_gaocha//高差信息
{
double value; // 观测值
double weight; // 权重
long startPoint; // 起始点编号
long endPoint; // 终点编号
};
//水准点类的设计
struct KJL_shzpoint
{ // 高程平差值=高程值+高程值改正数
long bh; // 水准点编号
double eleValue; // 高程值
double dv; // 高程值改正数(初始化为0)
bool isKnown; // 是否为已知点
};
//水准网设计
class KJL_shzwNet
{
public: // 成员函数
KJL_shzwNet(){numgaocha=0;numPoints=0;numKnPoint=0;}; // 构造函数
~KJL_shzwNet(){}; // 析构函数
void input();//水准网输入函数
void output();//水准网输出函数
void jsgc();////求每个点得近似高程
int getgczs(){return numgaocha;} //返回观测值数目
int getzds(){return numPoints;} //返回总点数
int getyzds(){return numKnPoint;} //返回已知点数
int getwzds(){return numPoints-numKnPoint;} //返回未知点数
double getgcValue(int i){return this->gczhi[i-1].eleValue;} //获得高程值
long getgcbh(int i){return gczhi[i-1].bh;} //返回高程点编号
void setgczhi(int i, double dv){gczhi[i-1].eleValue+=dv;} //改正高程值
void setdv(int i,double dv){this->gczhi[i-1].dv=dv;} //修改改正数
double getdv(int i){return gczhi[i-1].dv;} //返回改正数
friend void xishu(KJL_CMatrix& B, KJL_CMatrix& X,KJL_shzwNet A); //求取系数矩阵和未知点高程矩阵
friend void quanzhen(KJL_CMatrix& Q, KJL_shzwNet A); //求取权阵
friend void l_zhen( KJL_CMatrix& l ,KJL_CMatrix& L, KJL_shzwNet A); //求取观测值L矩阵和l阵
public: // 成员变量
int numgaocha; // 高差总数
int numPoints; // 水准网中点的总数目
int numKnPoint; //水准网中已知点的数目
KJL_gaocha edVec[maxnum]; // 观测值数组
KJL_shzpoint gczhi[maxnum]; // 水准点数组
};
void KJL_shzwNet::input()
{
int a,b,c,i;
double m,n,k;
cout<<"请输入水准网中水准点总数和已知点数:"<<endl;
cin>>a>>b;
this->numPoints=a;
this->numKnPoint=b;
for(i=0;i<a;i++)//对水准网中的点进行编号,并对水准点进行初始化
{
gczhi[i].bh=i+1;
gczhi[i].dv=0;
gczhi[i].eleValue=0;
gczhi[i].isKnown=0;
}
for(i=0;i<b;i++)//为水准网中的已知点输入高程
{
cout<<"请输入第"<<i+1<<"个已知点的高程值:"<<endl;
cin>>m;
gczhi[i].eleValue=m;
gczhi[i].isKnown=1;
}
cout<<"请输入观测值的个数:"<<endl;
cin>>c;
this->numgaocha=c;
for(i=0;i<this->numgaocha;i++)//输入观测值信息
{
cout<<"请输入第"<<i+1<<"段观测段的高差值(m)、长度(km)、起始编号和终点编号"<<endl;
cin>>k>>n>>a>>b;
this->edVec[i].value=k;
this->edVec[i].weight=n;
this->edVec[i].startPoint=a;
this->edVec[i].endPoint=b;
}
}
void KJL_shzwNet::output()
{
int i;
for(i=0;i<this->numPoints;i++)//输出水准点的信息
cout<<"编号为"<<this->gczhi[i].bh<<"的高程值为:"<<this->gczhi[i].eleValue<<endl;
for(i=0;i<this->numgaocha;i++)//输出高差的信息
cout<<"观测段"<<i+1<<"平差后的值为:"<<this->edVec[i].value<<endl;
}
void KJL_shzwNet::jsgc()//求每个点得近似高程
{
int i,j;
for(i=0;i<this->numgaocha;i++)
{//如果高差观测段的起始点高程值不为0,结束点高程为0 则:结束点高程=等于起始点高程+该测段的高差值 (0是默认值,代表还没参与计算)
//如果高差观测段的起始点高程值为0,结束点高程为不0 则:起始点高程=等于结束点高程-该测段的高差值 if(this->gczhi[this->edVec[i].startPoint-1].eleValue!=0&&this->gczhi[this->edVec[i].endPoint-1].eleValue==0)
{ this->gczhi[this->edVec[i].endPoint-1].eleValue=this->gczhi[this->edVec[i].startPoint-1].eleValue+this->edVec[i].value;
}else if(this->gczhi[this->edVec[i].startPoint-1].eleValue==0&&this->gczhi[this->edVec[i].endPoint-1].eleValue!=0)
{ this->gczhi[this->edVec[i].startPoint-1].eleValue=this->gczhi[this->edVec[i].endPoint-1].eleValue-this->edVec[i].value;
}
}
for(j=this->numKnPoint;j<this->numPoints;j++)
{//如果水准点的高程等于0则执行下面语句
if(this->gczhi[j].eleValue==0)
{
for(i=0;i<this->numgaocha;i++)
{//如果观测段的起始点等于水准点的编号 并且结束点得高程不为0则该该起始点的高程等于结束点高程减去高差值(观测值) if(this->edVec[i].startPoint==this->gczhi[i].bh&&this->gczhi[this->edVec[i].endPoint-1].eleValue!=0)
{ this->gczhi[i].eleValue=this->gczhi[this->edVec[i].endPoint-1].eleValue-this->edVec[i].value;
}//如果观测段的结束点等于水准点的编号 并且起始点点得高程不为0则该该结束点的高程等于起始点高程加上高差值(观测值)
else if(this->edVec[i].endPoint==this->gczhi[i].bh&&this->gczhi[this->edVec[i].startPoint-1].eleValue!=0)
{ this->gczhi[i].eleValue=this->gczhi[this->edVec[i].startPoint-1].eleValue+this->edVec[i].value;
}
}
}
}
}
void xishu(KJL_CMatrix & B, KJL_CMatrix & X,KJL_shzwNet A)//友元函数,求误差方程得系数矩阵
{
int i,j;
for(i=0;i<B.getRow();i++)
for(j=0;j<B.getColumn();j++)
{
B._A[i][j]=0;
}
for(i=0;i<A.getgczs();i++)
{//如果起始点为已知点并且结束点为未知点 则系数设置如下 if(A.gczhi[A.edVec[i].startPoint-1].isKnown==1&&A.gczhi[A.edVec[i].endPoint-1].isKnown==0)
{
B._A[i][A.edVec[i].endPoint-A.getyzds()-1]=1;
}//如果起始点为未知点并且结束点为已知点 则系数设置如下
else if(A.gczhi[A.edVec[i].startPoint-1].isKnown==0&&A.gczhi[A.edVec[i].endPoint-1].isKnown==1)
{ B._A[i][A.edVec[i].startPoint-A.getyzds()-1]=-1;
}//如果起始点和结束点均为未知点 则系数设置如下
else if(A.gczhi[A.edVec[i].startPoint-1].isKnown==0&&A.gczhi[A.edVec[i].endPoint-1].isKnown==0)
{ B._A[i][A.edVec[i].endPoint-A.numKnPoint-1]=1;
B._A[i][A.edVec[i].startPoint-A.numKnPoint-1]=-1;
}
}
for(i=0;i<X._row;i++)
{//未知点的近似高程矩阵
X._A[i][0]=A.gczhi[A.numKnPoint+i].eleValue;
}
}
void quanzhen(KJL_CMatrix & P,KJL_shzwNet A)//求权阵,与距离(单位km)的长度成反比
{ int i,j;
double sum=0;
double avg;
for(i=0;i<A.numgaocha;i++)
sum+=A.edVec[i].weight;//水准路线的总长度
avg=sum/A.numgaocha;//水准路线平均长度
for(i=0;i<P._row;i++)
{
for(j=0;j<P._column;j++)
P._A[i][j]=0;
}
for(i=0;i<P._row;i++)
P._A[i][i]=avg/A.edVec[i].weight;
}
void l_zhen(KJL_CMatrix & l,KJL_CMatrix &L,KJL_shzwNet A)//求取观测值L矩阵和l阵
{
int i;
double m;
for(i=0;i<A.getgczs();i++)
{
L._A[i][0]=A.edVec[i].value;
}
for(i=0;i<l._row;i++)
{//(起始点高程+高差-结束点高程)*1000作为l阵 m=(A.gczhi[A.edVec[i].startPoint-1].eleValue+A.edVec[i].value-A.gczhi[A.edVec[i].endPoint-1].eleValue)*1000;
l._A[i][0]=m;
}
}
void main()
{
KJL_shzwNet A;
A.input();
A.jsgc();//V=BX-l =>x=NBB.inv()*B.transpose()*P*l
KJL_CMatrix B(A.getgczs(),A.getwzds());
KJL_CMatrix P(A.getgczs(),A.getgczs());
KJL_CMatrix X(A.getwzds(),1);
KJL_CMatrix l(A.getgczs(),1);
KJL_CMatrix V(A.getgczs(),1);
KJL_CMatrix NBB(A.getwzds(),A.getwzds());
KJL_CMatrix x(A.getwzds(),1);
KJL_CMatrix L(A.getgczs(),1);
KJL_CMatrix VtpV(1,1);
xishu(B,X,A);
quanzhen(P,A);
l_zhen(l,L,A);
NBB=B.transpose()*P*B;
x=NBB.inv()*B.transpose()*P*L;
int i,j;
for(i=A.getyzds()+1;i<=A.getzds();i++)
{
A.setdv(i,(x._A[i-A.numKnPoint-1][0]/1000));
A.setgczhi(i,A.getdv(i));
cout<<"平差后编号为"<<A.getgcbh(i)<<"的点高程值:"<<A.getgcValue(i)<<"米"<<endl;
}
V=B*x-l;
for(j=0;j<V._row;j++)
cout<<"第"<<j+1<<"段观测高差平差值为:"<<(L._A[j][0]+V._A[j][0]/1000)<<"米"<<endl;
VtpV=V.transpose()*P*V;
cout<<"平差后单位权中误差为:"<<"+(-)"<<sqrt(VtpV._A[0][0]/A.getwzds())<<"毫米"<<endl;
}
实验结果
实验体会
通过这次实验,让我不仅对以前所学的测量平差有所复习,也对最小二乘原理有了深刻了解。
在这个实验中,最关键的问题,当然是矩阵的实现,由于在实验三中我们对矩阵类已经实现了,所以当下需要解决的问题就是理解水准网平差的原理,水准网平差的过程。有了这些知识,我们需要解决的就是,如何构建一个水准网,在构建水准网的过程中,我们需要建立一个水准点类,和观测边类。有了这些先验的知识,对平差过程中,才会有所眉目。
在所有的结构和类都已经定义好了,剩下的就是逻辑思想了。
我们知道对于水准网平差过程中,我们所使用的是间接平差原理。V=BX-L;
VTPV=min的原理,在如何求B阵是解决问题的关键,因为水准网的方程式都是线性的,所以构建系数阵很方便。如果观测段是从已知点到未知点则系数阵为0,-1.如果观测段是从未知点到已知点则系数阵为1,0.如果观测段是冲未知点到未知点则系数阵是1,-1.利用这种思想很快就可以建立系数阵。对权阵P的构建也比较简单,因为P与距离成反比。用平均距离除以该距离作为权。L阵就是观测阵。有了这些基本矩阵,就很容易求出V,和L的平差值。
再利用sqrt(VTPV/(n-t))便求出了整个单位权中误差。
通过这次实验,把自己所学的知识真正利用到实际中了,这是一次体验,也是一次飞跃,有了这次实验的历练,对理解和学习C++也不再像以前那样盲目和不知所措,知道了如何学以致用。