数组
- 在图7-1中,从第一行开始,依次对每一行的索引从左至右连续编号,得到图7-2a所示的映射结果。它把二维数组的索引映射为[0,n-1]中的数,这种映射方式称为行主映射( row major mapping)。索引对应的数称为行主次序( row-major order)。
- 图7-2b是另一种映射模式,称为列主映射图7-1 整型数组score [3] [6]的索引排列表( column major mapping)。
- 在列主映射中,对索引的编号从最左列开始,依次对每一列的索引从上到下连续编号。
- 在行主次序中,映射函数为: map(i1,i2)= i1*U2+ i2,其中u2是数组的列数。
- 将多维数组映射为一维数的时候,采用行主映射公式。
- 三维数组的行主映射函数为: map(i1,i2,i3) = i1u2u3 + i2*u3 + i3
- C++用所谓数组的数组来表示一个多维数组。一个二维数组被表示为一个一维数组,这个一维数组的每一个元素还是一个一维数组。
- 一个三维数组被表示为一个一维数组,这个一维数组的每一个元素是一个二维数组。
一个不规则二维数组的创建和使用
int main (void)
{
int numberOfRows = 5;
//1定义每一行的长度
int length[5] = (6,3,4, 2,7};
//声明一个二维数组变量
//且分配所需要的行数
int **irregularArray = new int* [numberOfRows] ;
//分配每一行的空间
for (int i = 0; i < numberOfRows; i++)
{
irregularArray[i] = new int [1ength[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;
}
矩阵
- 计算过程中,将二维数组转换为一维数组,利用行主映射公式。
矩阵类matrix的声明
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
};
矩阵类 matrix的构造函数和复制构造函数
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 * theCol umns] ;
//复制m的每一个元素
copy (m.element, m.element + theRows * theColumns, element) ;
}
矩阵类matrix对赋值操作符=的重载
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;
}
矩阵类 matrix对()操作符的重载
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
{
//矩阵乘法.返回结果矩阵 w = (*this) * m
if (theColumns != m. theRows)
throw matrixSi zeMismatch() ;
matrix<T> w (theRows,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行
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;
}
特殊矩阵
对角矩阵( diagonal)。M是一个对角矩阵,当且仅当 i≠j 时,M(i,j)=0。
- element [i-1] [j-1] 表示D(i,j)。这种表示法需要rows^2 个类型为T的数据空间。然而,对角矩阵最多只有rows个非0元素,因此可以用一维数组clement[rows]来表示对角矩阵,其中element[i-1]表示D(i,i)。所有未在一维数组中出现的矩阵元素均为0。
三对角矩阵( tridiagonal)。M是一个三对角矩阵,当且仅当|i-j| >1 时,M(i,j) =0。
- 在一个rows * rows的三对角矩阵中,非0元素排列在如下三条对角线上:
1)主对角线: i=j。
2)主对角线之下的对角线( 称低对角线):i=j+1。
3)主对角线之上的对角线(称高对角线):i=j-1。 - 这三条对角线上的元素总数为3 * rows-2。可以用一个容量为3*rows-2的一维数组element来描述三对角矩阵,因为只有三条对角线上的元素需要真正地存储。
- 逐行映射。
- 如果逐列映射。
- 逐条对角线映射。
下三角矩阵( lower triangular )。M是个下三角矩阵,当且仅当i<j时,M(i,j)=0。上三角矩阵( upper triangular)。M是一个上三角矩阵,当且仅当j时,M(i,j)=0。
- 这两种三角矩阵都可以用一个大小为 n(n+1)/2 的一维数组来表示。
- 元素L(i, j)在数组element中的位置:i(i-1)/2+j-1。
对称矩阵(symmetric)。M是一个对称矩阵,当且仅当对于所有的i和j,M(i,j)=M(j,i)。
- 由于对称性,只需存储一半的数据即可,用一个大小为n(n+1)/2的一维数组来表示。
稀疏矩阵
类spareMatrix的头
template<class T>
class sparseMatrix
{
public:
void transpose(sparseMatrix<T> &b) ;//转置矩阵
void add(sparseMatrix<T> &b, sparseMatrix<T> &C) ;
private :
int rows, //矩阵行数
cols; //矩阵列数
arrayList<matrixTerm<T> > terms; //非0项表
};
稀疏矩阵的转置
template<class T>
void sparseMatrix<T>::transpose(sparseMatrix<T> &b)//b为传出参数
{
//返回b中*this的转置
//设置转置矩阵特征
b.cols = rows;
b.rows = cols;
b.terms.reSet(terms.size()) ;
//先将矩阵中的非0元素按行主映射到arrayLIst中
//初始化以实现转置
int* colSize = new int[cols + 1] ;
int* rowNext = new int[cols + 1] ;
//寻找*this 中每一列的项的数目
for(int i=.1;i<=cols;i++) //初始化
colSize[i] = 0;
for (arrayList<matrixTerm<T> >:: iterator i = terms.begin() ;i != terms.end() ; i++)
colSize[(*i).col]++;
//寻找b中每一行的起始点
rowNext[1] = 0;
for(int i=2;i<=cols;i++)
rowNext[i] = rowNext[i - 1] + colSize[i-1];
//实施从*this到b的转置复制
matrixTerm<T> mTerm;
for (arrayList <matrixTerm<T> >:: iterator i = terms.begin() ;i != terms.end() ; i++)
{
int j = rowNext[ (*i) .co1]++; //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)
{
//b为传入参数,c为传出参数
//计算c=(*this)+b.
//检验相容性
if (rows != b.rows || cols != b.cols)
throw matrixSizeMismatch() ;
//矩阵不相容
//设置结果矩阵c的特征
c.rows = rows;
c.cols = cols;
c.terms.clear() ;
int cSize = 0;
//定义*this和b的迭代器
arrayList<matrixTerm<T> >::iterator it = terms.begin() ;
arrayList<matrixTerm<T> >::iterator ib = b.terms.begin() ;
arrayList<matrixTerm<T> >::iterator itEnd = terms.end() ;
arrayList<matrixTerm<T> >::iterator ibEnd = b.terms.end() ;
//遍历*this和b,把相关的项相加
while (it != itEnd && ib != ibEnd)
{
//行主索引加上每一项的列数
//行*列数+列,先将矩阵转为一维矩阵
int tIndex = (*it) .row * cols + (*it) .col;
int bIndex = (*ib) .row * cols + (*ib) .col;
if (tIndex < bIndex)
{//b项在后
//再插入一维矩阵中
c. terms. insert (cSize++, *it) ;
it++;
else {if (tIndex == bIndex)
{//两项同在一个位置
//仅当相加后不为0时加入c
if ((*it) .value + (*ib) .value != 0)
{
matrixTerm<T> mTe rm;
mTerm. row = (*it) . row;
mTerm.col = (*it) .col;
mTerm.value = (*it) .value + (*ib) . value;
c. terms.insert(cSize++,mTerm) ;
}
it++;
ib++;
}
else
{//一项在后
c.terms.insert(cSize++,*ib) ;
ib++; .
}
}
}
//复制剩余项,有一个到达end,而另一个没有到达end时
for (; it != itEnd; it++)
c. terms. insert(cSize++,*it) ;
for (; ib != ibEnd; ib++)
c. terms. insert(cSize++, *ib) ;
}
用多个线性表描述矩阵
- 把每行的非0元素串接在一起,构成一个链表,称作行链表(row chain )。
- 关于转置操作,我们使用箱子从输入矩阵*this中收集那些在结果矩阵中位于同一行的非0元素。bin[i] 是与结果矩阵b的第i行非0元素所对应的链表。
稀疏矩阵的转置
template<class T>
void linkedMatrix<T>:: transpose(linkedMatrix<T> &b)
{
//将*this 的转置在矩阵b中返回
b.headerChain.clear() ; //从b中删除所有节点
//创建bins作为每行的头节点链表,以收集b的行
extendedChain<rowElement<T> > *bin;
bin = new extendedChain<rowElement<T> > [cols + 1];
//头节点迭代器
extendedChain<headerElement<T> >::iterator ih = headerChain.begin(),ihEnd = headerChain.end() ;
//把*this 的项复制到bins
while (ih != ihEnd)
{//检查所有行
int r = ih->row;
//行链表的行数
//行链表迭代器
extendedChain<rowEl ement<T> > :: iterator ir = ih->rowChain.begin(),irEnd = ih->rowChain.end() ;
//定义每行中元素的节点
rowElement<T> x;
//将*this 中行r中的项复制到b中的列r
x.col = r;
while (ir != irEnd)
{//把行链表的一项复制到bin
x.value = ir->value; .
//x最终在转置矩阵的行ir->col 中.
bin[ir->co1] .push_back(x) ;
ir++; //行中的下一项
}
ih++; //进入下一行
}
//设置转置矩阵的维数
b.rows = cols;
b.cols = rows;
//收集转置矩阵的头链表
headerElement<T> h;
//扫描bins
for(inti=1;i<=cols;i++)
if (!bin[i] . empty())
{//转置矩阵的行i
h.row = i;
h. rowChain = bin[i] ;
b.headerChain.push back(h) ;
bin[i] .zero(); // 免于析构
}
h.rowChain. zero() ;
//免于析构
delete [] bin;
}