数组和矩阵
在实际应用中,数据通常以表的形式出现。尽管用数组来描述表是最自然的方式,但为了减少程序所需的时间和空间,经常采用自定义的描述方式。例如,当表中大部分元素都为0的时候,就会采用自定义的描述方式。
一个数组的每一个实例都是形如**(索引,值)**的数对集合,其中任意两个数对的值都不相同。有关数组的操作如下:
- 取值——给定一个索引,取对应数对中的值
- 存值——把一个新数对加到数对集合中。如果已经存在一个索引相同的数对,就用新数对覆盖。
数组的存取分为行主映射和列主映射。
值得注意的是,二维数组int x[3][5]和int x[15]占用空间是不一样的,x[3][5]占用的空间是sizeof(int)*(3*5+3)=72,x[15]占用的空间是sizeof(int)*(15)=60,因为二维数组x[3][5]实际上是创建了一个长度为3的一维数组x,x的每一个元素是一个长度为5的一维数组。长度为3的一维数组存储的是第二维的指针。所以要多出来一些存储空间。
不规则二维数组
#include <iostream>
using namespace std;
int main(void)
{
int numberOfRows = 5;
//定义每一行的长度
int length[5]={6,3,4,2,7};
//声明一个二维数组变量
//且分配所需要的行数
int **irregularArray = new int* [numberOfRows];
//分配每一行空间
for(int i = 0; i < numberOfRows;i++)
irregularArray[i] = new int [length[i]];
irregularArray[2][3] = 5;
irregularArray[4][6] = irregularArray[2][3] + 2;
irregularArray[1][1] = 3;
cout << irregularArray[2][3] << endl;
cout << irregularArray[4][6] << endl;
cout << irregularArray[1][1] << endl;
return 0;
}
矩阵
矩阵需要注意的就是矩阵乘法,其中m×n的矩阵A和q×p的矩阵B相乘,只有在n=q时才能进行乘法运算,结果是一个m×p的矩阵。
注意的是,因为是一维数组方式存储的,所以在矩阵(i,j)位置的元素实际上再数组的(i-1)*theRows+j的位置上,所以在矩阵乘法时要注意相乘位的表示。
#ifndef MATRIX_H_INCLUDED
#define MATRIX_H_INCLUDED
#include<iostream>
#include"myException.h"
using namespace std;
template<class T>
class matrix
{
friend ostream& operator<<(ostream&, const matrix<T>&);
public:
matrix(int theRows = 0,int theColumns = 0);
matrix(const matrix<T>&);
~matrix()
{
delete [] element;
}
int rows()const
{
return theRows;
}
int columns() const
{
return theColumns;
}
T& operator()(int i,int j)const;
matrix<T>& operator=(const matrix<T>&);
matrix<T> operator+()const;
matrix<T> operator+(const matrix<T>&)const;
matrix<T> operator-() const;
matrix<T> operator-(const matrix<T>&)const;
matrix<T> operator*(const matrix<T>&) const;
matrix<T>& operator+=(const T&);
private:
int theRows, //矩阵的行数
theColumns; //矩阵的列数
T *element; //数组element
};
template<class T>
matrix<T>::matrix(int theRows, int theColumns)
{
//矩阵构造函数
//检查行数和列数的有效性
if(theRows < 0 || theColumns < 0)
throw illegalParameterValue("Rows and columns must be >= 0");
if((theRows == 0 || theColumns == 0)&&(theRows != 0 || theColumns != 0))
throw illegalParameterValue("Either both or neither rows and columns should be zero");
//创建矩阵
this->theRows = theRows;
this->theColumns = theColumns;
element = new T [theRows * theColumns];
}
template<class T>
matrix<T>::matrix(const matrix<T>& m)
{
//矩阵的复制构造函数
theRows = m.theRows;
theColumns = m.theColumns;
element = new T[theRows * theColumns];
//复制m的每一个元素
copy(m.element,
m.element + theRows * theColumns,
element);
}
template<class T>
matrix<T>& matrix<T>::operator=(const matrix<T>& m)
{
//赋值.(*this)=m
if(this != &m)
{
//不能复制自己
delete[] element;
theRows = m.theRows;
theColumns = m.theColumns;
element = new T[theRows * theColumns];
copy(m.element,
m.element + theRows + theColumns,
element);
}
return *this;
}
template<class T>
T& matrix<T>::operator()(int i,int j)const
{
//返回对元素element(i,j)的引用
if(i < 1 || i > theRows
|| j < 1 || j >theColumns)
throw matrixIndexOutOfBounds();
return element[(i-1)*theColumns + j - 1];
}
template<class T>
matrix<T> matrix<T>::operator+(const matrix<T>& m)const
{
//返回矩阵w = (*this)+m
if(theRows != m.theRows
|| theColumns != m.theColumns)
throw matrixSizeMismatch();
//生成结果矩阵
matrix<T> w(theRows, theColumns);
for(int i = 0; i < theRows * theColumns; i++)
w.element[i] = element[i] + m.element[i];
return w;
}
template<class T>
matrix<T> matrix<T>::
operator-(const matrix<T>& m) const
{// Return (*this) - m.
if (theRows != m.theRows
|| theColumns != m.theColumns)
throw matrixSizeMismatch();
// create result matrix w
matrix<T> w(theRows, theColumns);
for (int i = 0; i < theRows * theColumns; i++)
w.element[i] = element[i] - m.element[i];
return w;
}
template<class T>
matrix<T> matrix<T>::operator-() const
{// Return w = -(*this).
// create result matrix w
matrix<T> w(theRows, theColumns);
for (int i = 0; i < theRows * theColumns; i++)
w.element[i] = -element[i];
return w;
}
template<class T>
matrix<T> matrix<T>::operator*(const matrix<T>& m)const
{
//矩阵乘法.返回结果矩阵w=(*this) * m;
if(theColumns != m.theRows)
throw matrixSizeMismatch();
matrix<T> w(theRows,m.theColumns);
//定义矩阵*this,m和w的游标且初始化以为(1,1)元素定位
int ct = 0, cm = 0, cw = 0;
//对所有i和j计算w(i,j)
for(int i = 1; i <= theRows; i++)
{
//计算结果矩阵的第i行
//ct在行方向移动,所以是++,而cm在列方向移动,所以是+m.theColumns
for(int j = 1; j <= m.theColumns; j++)
{
//计算w(i,j)第一项
T sum = element[ct] * m.element[cm];
//累加其余所有项
for(int k = 2; k <= theColumns; k++)
{
ct++;
cm += m.theColumns;
sum += element[ct] * m.element[cm];
}
w.element[cw++] = sum;
//从行的起点和下一列重新开始
ct -= theColumns - 1;
cm = j;
}
//从下一行和第一列重新开始
ct += theColumns;
cm = 0;
}
return w;
}
template<class T>
matrix<T>& matrix<T>::operator+=(const T& x)
{// Increment all elements of *this by x.
for (int i = 0; i < theRows * theColumns; i++)
element[i] += x;
return *this;
}
template<class T>
ostream& operator<<(ostream& out, const matrix<T>& m)
{// Put matrix m into the stream out.
// One row per line.
int k = 0; // index into element array
for (int i = 0; i < m.theRows; i++)
{// do row i
for (int j = 0; j < m.theColumns; j++)
out << m.element[k++] << " ";
// row i finished
out << endl;
}
return out;
}
// for some reason compiler can't create this on its own
ostream& operator<<(ostream& out, const matrix<int>& m)
{// Put matrix m into the stream out.
// One row per line.
int k = 0; // index into element array
for (int i = 0; i < m.theRows; i++)
{// do row i
for (int j = 0; j < m.theColumns; j++)
out << m.element[k++] << " ";
// row i finished
out << endl;
}
return out;
}
#endif // MATRIX_H_INCLUDED
特殊矩阵
方阵是行数和列数相同的矩阵。一些常用的特殊方阵如下:
对角矩阵:当且仅当i≠j时,M(i,j) = 0;
三对角矩阵:当且仅当|i-j|>1时,M(i,j) = 0;
下三角矩阵:当且仅当i<j时,M(i,j)=0;,三角矩阵共有n(n+1)/2个元素。
上三角矩阵:当且仅当i>j时,M(i,j)=0;
对称矩阵:当且仅当对于所有的i和j,M(i,j)=M(j,i)。
注意各个对应元素与element一维数组的对应关系即可。
稀疏矩阵
一个m×n的矩阵,如果大多数元素都是0,则称为稀疏矩阵,一个矩阵如果不是稀疏的,就称为稠密矩阵,在稀疏矩阵和稠密矩阵之间没有明确界限。
稀疏矩阵可以考虑用单个线性表来描述,
稀疏矩阵比较重要的是转置的实现,
实现如下:创建两个数组colSize和rowNext,colSize[i]是输入矩阵*this在第i列的非0元素个数,rowNext[i]是转置矩阵第i行首个非0元素在b中的索引。例如,对于上图的稀疏矩阵,colSize[1:8]=[0,2,1,2,1,1,1,1]。rowNext=[0,0,2,3,5,6,7,8]。
流程为计算colSize[1:8]->计算rowNext[1:8],
rowNext[1] = 0;
rowNext[i] = rowNext[i-1]+colSize[i-1];
稀疏矩阵的每个元素是terms的结构数组。
// a term in sparseMatrix
#ifndef matrixTerm_
#define matrixTerm_
using namespace std;
template <class T>
struct matrixTerm
{
int row,
col;
T value;
operator T() const {return value;}
// type conversion from matrixTerm to T
};
#endif
稀疏矩阵类如下
// sparse matrix using an extended array list
#ifndef sparseMatrix_
#define sparseMatrix_
#include <iostream>
#include "matrixTerm.h"
#include "extendedArrayList.h"
#include "myException.h"
template<class T>
class sparseMatrix
{
friend ostream& operator<<
(ostream&, sparseMatrix<T>&);
friend istream& operator>>
(istream&, sparseMatrix<T>&);
public:
void transpose(sparseMatrix<T> &b);
void add(sparseMatrix<T> &b, sparseMatrix<T> &c);
private:
int rows, // number of rows in matrix
cols; // number of columns in matrix
arrayList<matrixTerm<T> > terms;
// list of nonzero terms
};
// overload <<
//template <typename T>
template <class T>
ostream& operator<<(ostream& out, sparseMatrix<T>& x)
{// Put x in output stream.
// put matrix characteristics
out << "rows = " << x.rows << " columns = "
<< x.cols << endl;
out << "nonzero terms = " << x.terms.size() << endl;
// put terms, one per line
for (typename arrayList<matrixTerm<T> >::iterator i = x.terms.begin();i != x.terms.end(); i++)
out << "a(" << (*i).row << ',' << (*i).col
<< ") = " << (*i).value << endl;
return out;
}
// overload >>
template<class T>
istream& operator>>(istream& in, sparseMatrix<T>& x)
{// Input a sparse matrix.
// input matrix characteristics
int numberOfTerms;
cout << "Enter number of rows, columns, and #terms"
<< endl;
in >> x.rows >> x.cols >> numberOfTerms;
// set size of x.terms and ensure enough capacity
x.terms.reSet(numberOfTerms);
// input terms
matrixTerm<T> mTerm;
for (int i = 0; i < numberOfTerms; i++)
{
cout << "Enter row, column, and value of term "
<< (i + 1) << endl;
in >> mTerm.row >> mTerm.col >> mTerm.value;
x.terms.set(i, mTerm);
}
return in;
}
/****************************************************************/
// explict code tooverload with T = int for test as compiler
// unable to generate
// overload <<
ostream& operator<<(ostream& out, sparseMatrix<int>& x)
{// Put x in output stream.
// put matrix characteristics
out << "rows = " << x.rows << " columns = "
<< x.cols << endl;
out << "nonzero terms = " << x.terms.size() << endl;
// put terms, one per line
for (arrayList<matrixTerm<int> >::iterator i = x.terms.begin();
i != x.terms.end(); i++)
out << "a(" << (*i).row << ',' << (*i).col
<< ") = " << (*i).value << endl;
return out;
}
// overload >>
istream& operator>>(istream& in, sparseMatrix<int>& x)
{// Input a sparse matrix.
// input matrix characteristics
int numberOfTerms;
cout << "Enter number of rows, columns, and #terms"
<< endl;
in >> x.rows >> x.cols >> numberOfTerms;
// set size of x.terms and ensure enough capacity
x.terms.reSet(numberOfTerms);
// input terms
matrixTerm<int> mTerm;
for (int i = 0; i < numberOfTerms; i++)
{
cout << "Enter row, column, and value of term "
<< (i + 1) << endl;
in >> mTerm.row >> mTerm.col >> mTerm.value;
x.terms.set(i, mTerm);
}
return in;
}
/****************************************************************/
template<class T>
void sparseMatrix<T>::transpose(sparseMatrix<T> &b)
{// Return transpose of *this in b.
// set transpose characteristics
b.cols = rows;
b.rows = cols;
b.terms.reSet(terms.size());
// initialize to compute transpose
int* colSize = new int[cols + 1];
int* rowNext = new int[cols + 1];
// find number of entries in each column of *this
for (int i = 1; i <= cols; i++) // initialize
colSize[i] = 0;
for (typename arrayList<matrixTerm<T> >::iterator i = terms.begin();
i != terms.end(); i++)
colSize[(*i).col]++;
// find the starting point of each row of b
rowNext[1] = 0;
for (int i = 2; i <= cols; i++)
rowNext[i] = rowNext[i - 1] + colSize[i - 1];
// perform the transpose copying from *this to b
matrixTerm<T> mTerm;
for (typename arrayList<matrixTerm<T> >::iterator i = terms.begin();
i != terms.end(); i++)
{
int j = rowNext[(*i).col]++; // position in b
mTerm.row = (*i).col;
mTerm.col = (*i).row;
mTerm.value = (*i).value;
b.terms.set(j, mTerm);
}
}
template<class T>
void sparseMatrix<T>::add(sparseMatrix<T> &b, sparseMatrix<T> &c)
{// Compute c = (*this) + b.
// verify compatibility
if (rows != b.rows || cols != b.cols)
throw matrixSizeMismatch(); // incompatible matrices
// set characteristics of result c
c.rows = rows;
c.cols = cols;
c.terms.clear();
int cSize = 0;
// define iterators for *this and b
typename arrayList<matrixTerm<T> >::iterator it = terms.begin();
typename arrayList<matrixTerm<T> >::iterator ib = b.terms.begin();
typename arrayList<matrixTerm<T> >::iterator itEnd = terms.end();
typename arrayList<matrixTerm<T> >::iterator ibEnd = b.terms.end();
// move through *this and b adding like terms
while (it != itEnd && ib != ibEnd)
{
// row-major index plus cols of each term
int tIndex = (*it).row * cols + (*it).col;
int bIndex = (*ib).row * cols + (*ib).col;
if (tIndex < bIndex)
{// b term comes later
c.terms.insert(cSize++, *it);
it++;
}
else {if (tIndex == bIndex)
{// both in same position
// append to c only if sum not zero
if ((*it).value + (*ib).value != 0)
{
matrixTerm<T> mTerm;
mTerm.row = (*it).row;
mTerm.col = (*it).col;
mTerm.value = (*it).value + (*ib).value;
c.terms.insert(cSize++, mTerm);
}
it++;
ib++;
}
else
{// a term comes later
c.terms.insert(cSize++, *ib);
ib++;
}
}
}
// copy over remaining terms
for (; it != itEnd; it++)
c.terms.insert(cSize++, *it);
for (; ib != ibEnd; ib++)
c.terms.insert(cSize++, *ib);
}
#endif
刚开一直没运行成功,一直出现这个错误
need typename before because is a dependent scope,通过百度搜索,在每个iterator前加了typename关键字,问题得到解决,首先看一下template<class T>和template<typename T>的区别
总而言之:typename的作用就是告诉c++编译器,typename后面的字符串为一个类型名称,而不是成员函数或者成员变量,这个时候如果前面没有typename,编译器没有任何办法知道arrayList<matrixTerm<T>>::iterator是一个类型还是一个成员名称(静态数据成员或者静态函数),所以编译不能够通过。