7.1 数组
7.1.1 抽象数据类型
抽象数据类型 Array
{
实例
形如(index,value)的数对集合,其中任意两个数对的index值都各不相同. 操作
get(index):返回索引为index的数对中的值
set(index,value):加入一个新数对(index,value)
(如果索引index值相同的数对已存在,则用新数对覆盖)
}
7.1.2 C++数组的索引
- K维数组的索引(或下标)
- [ i 1 ] [ i 2 ] [ i 3 ] . . . [ i k ] [i_1][i_2][i_3]...[i_k] [i1][i2][i3]...[ik]
- k维数组创建:
- int score [ u 1 ] [ u 2 ] [ u 3 ] . . . [ u k ] [u_1][u_2][u_3]...[u_k] [u1][u2][u3]...[uk]( u i u_i ui—正的常量或有常量表示的表达式)
- 数组元素的个数:
- n = u 1 u 2 u 3 . . . u k n=u_1u_2u_3...u_k n=u1u2u3...uk
- 内存空间:
- n x sizeof(int)字节.
- c++ 编译器为数组预留空间:
- start -----start + sizeof(score)-1
7.1.3 行主映射和列主映射
行主映射(按行的顺序对元素一一映射)和列主映射(按列的顺序对元素一一映射)
以二维数组举例
int s[ u 1 u_1 u1] [ u 2 u_2 u2] (令s[2] [3])
行主映射下: | 列主映射下: |
---|---|
map( i 1 i_1 i1, i 2 i_2 i2) = u 2 u_2 u2 * i 1 i_1 i1 + i 2 i_2 i2 | map( i 1 i_1 i1, i 2 i_2 i2) = u 1 u_1 u1 * i 2 i_2 i2 + i 1 i_1 i1 |
s[0] [0] | s[0] [0] |
s[0] [1] | s[1] [0] |
s[0] [2] | s[0] [1] |
s[1] [0] | s[1] [1] |
s[1] [1] | s[0] [2] |
s[1] [2] | s[1] [2] |
思考:
-
在C++使用的是行主映射
-
M 行 M_行 M行= M 列 T M_列^T M列T
-
k维数组行主映射:
m a p ( i 1 , i 2 , . . . , i k ) = ( i 1 ∗ u 2 ∗ u 3 . . . u k ) + ( i 2 ∗ u 3 . . . u k ) + . . . + ( i k − 1 ∗ u k ) + ( i k ) map(i_1, i_2, ..., i_k) = (i_1*u_2*u_3 ... u_k)+(i_2*u_3 ... u_k)+...+(i_{k-1}*u_k)+(i_k) map(i1,i2,...,ik)=(i1∗u2∗u3...uk)+(i2∗u3...uk)+...+(ik−1∗uk)+(ik)
-
k维数组列主映射:
m a p ( j 1 , j 2 , . . . j k ) = ( j 1 ∗ u 2 ∗ u 3 . . . u k ) + ( j 2 ∗ u 3 . . . u k ) + . . . + ( j k − 1 ∗ u k ) + ( j k ) map(j_1,j_2,...j_k)= (j_1*u_2*u_3 ... u_k)+(j_2*u_3 ... u_k)+...+(j_{k-1}*u_k)+(j_k) map(j1,j2,...jk)=(j1∗u2∗u3...uk)+(j2∗u3...uk)+...+(jk−1∗uk)+(jk)
注意,超过两维就没有列的概念了,因此高维的行、列主映射公式通用。
7.1.4 用数组的数组来描述
多维数组可以用数组的数组描述
-
占用空间:4×3×1 + 4×5×3
-
C++定位x[i] [j]的过程:
-
利用一维数组的映射函数找到指针x[i]
-
利用一维数组的映射函数找到指针x[i]所指的第i行中索引为j的元素
-
7.1.5 行主描述和列主描述
数组y | 以下就是int s[3] [5]的行主描述 | 以下就是int s[3] [5]的列主描述 |
---|---|---|
y[0] | s[0] [0] | s[0] [0] |
y[1] | s[0] [1] | s[1] [0] |
y[2] | s[0] [2] | s[2] [0] |
y[3] | s[0] [3] | s[0] [1] |
y[4] | s[0] [4] | s[1] [1] |
y[5] | s[1] [0] | s[2] [1] |
y[6] | s[1] [1] | s[0] [2] |
y[7] | s[1] [2] | s[1] [2] |
y[8] | s[1] [3] | s[2] [2] |
y[9] | s[1] [4] | s[0] [3] |
y[10] | s[2] [0] | s[1] [3] |
y[11] | s[2] [1] | s[2] [3] |
y[12] | s[2] [2] | s[0] [4] |
y[13] | s[2] [3] | s[1] [4] |
y[14] | s[2] [4] | s[2] [4] |
- 占用空间:3×5×4
- 定位x[i] [j]的过程(以行主列为例):
- 利用二维数组的映射函数(map( i 1 i_1 i1, i 2 i_2 i2) = u 2 u_2 u2 * i 1 i_1 i1 + i 2 i_2 i2)计算x[i] [j]在一维数组y中的位置u
- 利用一维数组的映射函数(map( i 1 i_1 i1)= i 1 i_1 i1)访问元素y[u]
7.2 矩阵
7.2.1 定义和操作
m×n矩阵:m行和n列的表
M(i,j):矩阵M中第i行、第j列的元素
矩阵相乘直观表示(* ^ ▽ ^ *)
7.2.2 类matrix
数据描述:用于一个一维数组element,按行主次序存储
M:m×n matrix
- 矩阵元素M(i,j)在数组element中的位置
- map(i,j) = (i-1)*n+j-1
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*(constmatrix<T>&)const;
matrix<T>&operator+=(const T&x);
private:
int theRows,theColumns;//矩阵行数和列数
T*element;//元素数组
};
matrix类的构造函数
template<class T>
matrix<T>::matrix(int theRows,int theColumns)
{
//检验行数和列数的有效性
if(theRows <0 || theColumns <0)
throw illegalParameterValue("行列数必须大于等于0");
if(theRows ==0 || theColumns == 0 && (theRows !=0|| theColumns !=0))
throw illegalParameterValue("要么都大于0,要么都等于0");
//创建矩阵
this-> theRows = theRows;
this-> theColumns = theColumns;
element=new T [theRows* theColumns];
}
matrix类的复制构造函数
template<class T>
matrix<T>::matrix(const matrix<T>& m)
{
//创建矩阵
theRows = m.rows;
theColumns = m.theColumns;
element= new T [theRows* theColumns];
//复制m的每一个元素
copy (m.element,m.element + theRows* theColumns, element);
}
matrix类对()
的重载
矩阵元素M(i,j)在数组element中的位置
map(i,j) = (i-1)*n+j-1
template<class T>
T& matrix<T>::operator()(int i,int j)const
{
//返回一个指向元素(i,j)的引用
if(i<1||i>theRows||j<1|j>theColumns)
throw matrixIndexOutOfBounds();
return element[(i-1)*theColumns +j-1];
}
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];
//复制m的每一个元素
copy (m.element,m.element + theRows* theColumns, element);
}
return *this;
}
matrix类对+
的重载
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();
//生成结果矩阵w
matrix<T> w(theRows, theColumns);
for(int i = 0;i < theRows * theColumns;i++)
w.element[i] = element[i] + m.element[i];
return w;
}
matrix类对*
的重载
template<class T>
matrix<T>matrix<T>::operator * (const matrix<T>& m)const
{
//返回矩阵w=(*this)*m
if(theColumns != m.theRows)
throw matrixSizeMismatch();
//生成结果矩阵w
matrix<T> w(theRows, m.theColumns);
//为*this,m和w定义游标,并设定初始位置为(1,1)
int ct = 0,cm = 0,cw = 0;
/*最外层的循环对应不同行和不同列的计算,一行的所有列都好了就换一行*/
for (int i = 1;i <= theRows;i++)
{
/*第二层的循环对应一行和不同列的计算,一列完了换一列*/
for (int j = 1;j <= m.theColumns; j++)
{
T sum = element[ct] * m.element[cm];
/*最内层的循环实现一行对应一列的计算*/
for(int k=2;k<=theColumns;k++)
{
//累加其余项
ct++;//指向*this第i行的下一项
/*在行主次序中同一列的两个相同元素在位置上相差m.theColumns*/
cm += m.theColumns;//指向m的第j列的下一项
sum += element[ct] * m.element[cm];
}
w.element[cw++] = sum;//保存w(i,j)
ct -= theColumns-1;//第i行行首
cm = j;//第j+1列起始
}
ct += theColumns;//重新调整至下一行的行首
cm = 0;//重新调整至第一列起始
}
return w;
}
7.3 特殊矩阵
7.3.1 定义和应用
方阵是指具有相同行数和列数的矩阵
特殊矩阵
7.3.2 对角矩阵
对角矩阵:D
矩阵描述:T element[n]
类diagonalmatrix声明
template<class T>
class diagonalMatrix
{
public:
diagonalMatrix(int theN=10);//构造函数
~diagonalMatrix(){delete []element;} //析构函数
T get(int,int)const;
void set(int,int,const T&);
private:
int n;//矩阵维数
T*element; //存储对角元素的一维数组
};
diagonalMatrix::get
template <class T>
T diagonalMatrix<T>::get(int i,int j)const
{
//返回矩阵中(i,j)位置上的元素.
//检验i和j是否有效
if (i<1 || j<1 || i>n || j>n) throw matrixIndexOutOfBounds();
if(i==j)
return element[i-1];//对角线上的元素
else return 0;//非对角线上的元素
}
diagonalMatrix:: set
template<class T>
void diagonalMatrix<T>:: set(int i, int j, const T& newValue)
{
//存储矩阵中位置(i,j)上元素的新值.
//检验i和j是否有效
if(i<1 || j<1 || i>n || j>n) throw matrixIndexOutOfBounds();
if(i==j)
element[i-1] = newValue;//存储对角元素的值
else
if(newValue!= 0)
throw illegalParameterValue("非对角线上的元素必须是0");
}
7.3.3 三对角矩阵
三对角矩阵:T
三条对角线:
主对角线:i = j
低对角线(主对角线之下的对角线):i = j + 1
高对角线(主对角线之上的对角线):i = j - 1
补充:按对角线映射
tridiagonalMatrix::get
template <class T>
T tridiagonalMatrix<T>::get(int i,int j)const
{
//返回矩阵中(i,j)位置上的元素.
//检验i和j是否有效
if(i <1 || j<1 || i>n || j>n) throw matrixIndexOutOfBounds();
//确定要返回的元素
switch (i-j)
{
case 1://低对角线
return elelment[i-2];
case 0://主对角线
return elelment[n+i-2];
case -1://高对角线
return elelment[2*n+i-2];
default: return 0;
}
}
7.3.4 三角矩阵
非0区域的元素总数:n(n+1)/2
7.3.5 对称矩阵
一个n×n对称矩阵,可以视为下三角或上三角矩阵,用三角矩阵的表示方法,用一个大小为n(n+1)/2的一维数组来表示。未存储的元素可以由存储的元素来计算。
7.4 稀疏矩阵
7.4.1 基本概念
-
如果一个m×n矩阵中有“许多”元素为0,则称该矩阵为稀疏矩阵(sparse)。
-
不是稀疏的矩阵被称为稠密矩阵(dense)。
-
稀疏矩阵和稠密矩阵之间没有一个精确的界限:
- 我们规定若一个矩阵是稀疏矩阵,则其非0元素的数目应小于 n 2 / 3 n^2/3 n2/3,在有些情况下应小于 n 2 / 5 n^2/5 n2/5
- 对角矩阵,三对角矩阵(n×n):稀疏矩阵
- 三角矩阵:稠密矩阵
7.4.2 用单个线性表描述
线性表terms采用数组描述(terms是arrayList的实例)
类sparseMatrix声明
template <class T>
struct matrixTerm
{
int row;
int col;
T value;
operator T() const { return value;}
};
template<class T>
class sparseMatrix
{
public:
void transpose(SparseMatrix<T> &b);//矩阵转置
void add(sparseMatrix<T> &b, sparseMatrix<T> &c);//两个稀疏矩阵相加
private:
int rows;//矩阵行数
int cols;//矩阵列数
arrayList<matrixTerm<T>>terms;//矩阵非0元素表
};
类sparseMatrix中的矩阵转置
关键点
矩阵*this的转置矩阵→b
矩阵*this中的元素在b中的位置?
- colSize[i]:*this第i列的非0元素数
- rowNext[i]:*this第i列(b中第i行)下一个元素在b中的位置
- 初始:b中第i行的起始位置
rowNext[1] = 0;
rowNext[i] = rowNext[i - 1]+colSize[i - 1];
算法思路
计算*this每列中的非0元素数
求出b中每一行的起始点
实施从*this到b的转置复制
定义i为* this迭代器
依次扫描* this各元素( *i)
template<class T>
void sparseMatrix<T>::transpose(sparseMatrix<T>&b)
{//把*this转置结果送入b
//设置转置矩阵特征
b.cols = rows;
b.rows = cols;
b.terms.reSet(terms.size());
//初始化以实现转置
int* colSize = new int[cols + 1];
int* rowNext = new int[cols + 1];
//计算*this每一列的非0元素数
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).col]++;//在b中的位置
mTerm.row = (*i).col;
mTerm.col = (*i).row;
mTerm.value = (*i).value;
b.terms.set(j,mTerm);
}
}
类sparseMatrix中的两个稀疏矩阵相加
两个稀疏矩阵(*this和b)相加,所得结果放入c中。
实现思想:文章来源:https://www.toymoban.com/news/detail-793898.html
- 定义矩阵*this的迭代器:it,和矩阵b的的迭代器ib
- 使用it和ib,从左至右依次扫描两个矩阵中的元素。
- 当it和ib都未扫描完成时,循环:
- 计算it所指的元素和ib所指的元素按行主次序的索引。
- tIndex=*this中的it所指的元素索引
- 元素索引——(元素的行下标-1)* 列数+元素的列下标
- bIndex =b中ib所指的元素索引
- 判断tIndex>bIndex 还是tIndex=bIndex,确定it所指的元素是在ib所指的元素之前,之后还是进行相加运算,并只在和不为0时才加入c。
- 复制剩余元素
template<class T>
void sparseMatrix<T>::Add(sparseMatrix<T>&b,sparseMatrix<T>&c)
{//计算c=(*this)+b.
//检验相容性
if (rows != b.rows || cols != b.cols)
throw matrixSizeMismatch();//不能相加
//设置结果矩阵c的特征
c.rows = rows;
c.cols = cols;
c.terms.clear() = 0;//初值
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的元素在后
{
//*this的下一个元素
c.terms.insert(cSize++,*it);
it++;
}
else
{
if (tIndex == bIndex)//位置相同
{
//仅当和不为0时才添加到c中
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);
}
//*this和b的下一个元素
it++;
ib++;
}
else
{//b的下一个元素
c.terms.insert(cSize++,*ib);
ib++;
}
}
}
//复制剩余元素
for(;it != itEnd; it++)
c.terms.insert(cSize++,*it);
for(;ib != ibEnd; ib++)
c.terms.insert(cSize++,*ib);
}
7.4.3 用多个线性表描述
文章来源地址https://www.toymoban.com/news/detail-793898.html
到了这里,关于数据结构 | 第七章:数组和矩阵 | 行主映射和列主映射 | 稀疏矩阵的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!