C++(数据结构与算法):16---特殊矩阵的实现(对角矩阵、三对角矩阵、下三角矩阵、上三角矩阵、对称矩阵)

一、特殊矩阵(方阵)

  • 方阵:是指行数与列数相同的矩阵
  • 一些常用的特殊方阵如下:
    • 对角矩阵:M是一个对角矩阵,当且仅当i!=l时,M(i,j)=0
    • 三对角矩阵:M是一个三对角矩阵,当且仅当|i-j|>1时,M(i,j)=0
    • 下三角矩阵:M是一个下三角矩阵,当且仅当i<j时,M(i,j)=0
    • 上三角矩阵:M是一个上三角矩阵,当且仅当i>j时,M(i,j)=0
    • 对称矩阵:M是一个对称矩阵,当且仅当对于所有的j和j,M(i,j)=M(j,i)

二、特殊矩阵(方阵)在实际中的应用

应用①

  • 佛罗里达州的6个城市Gainsville、Jacksonville、Miami、Orlando、Tallaha-ssee和Tampa
  • 按照这个顺序,依次从1~6编号。任意两个城市之间的距离用一个6*6的矩阵distance表示。矩阵的第i行和第i列代表第i个城市。distance(i,j)代表城市i和城市j之间的距离
  • 下图给出了相应的矩阵,因为对于所有的i和j有distance(i,j)=distance(j,i),所以这是一个对称矩阵

应用②

三、对角矩阵

  • 对角矩阵:M是一个对角矩阵,当且仅当i!=l时,M(i,j)=0

编码实现:

  • 一个rows*rows的对角矩阵D可以表示为一个二维数组element[rows][rows],其中element[i-1][j-1]=D(i,i)。这种表示法需要rows*rows个类型为T的数据空间
  • 然后对角矩阵最多只有rows个非0元素,因此可以用一位数组element[rows]来表示,其中element[i-1]=D(i,i),所有未在一维数组中出现的矩阵元素均为0

异常类定义

class illegalParameterValue
{
	string message;
public:
	illegalParameterValue(const char *theMessage ="Illegal Parameter Value"):message(theMessage) {}
	const char *what() {
		return message.c_str();
	}
};

class matrixIndexOutOfBounds
{
public:
	matrixIndexOutOfBounds(string theMessage = "Matrix index out of bounds") :message(theMessage){}
	const char *what() {
		return message.c_str();
	}
private:
	string message;
};

类定义

template<typename T>
class diagonalMatrix
{
public:
	diagonalMatrix(int theN = 10);
	~diagonalMatrix();
	void set(int i, int j, T value);
	T get(int i, int j)const;
	void output(ostream& out) const;
private:
	T *element;  //存放矩阵的数组
	int n;  //矩阵维度
};

类成员实现

  • 构造函数时间复杂度:当T时内部数据类型时为O(1),当T为用户定义类型时为O(rows)
  • get、set的时间复杂度:Θ(1)
template<typename T>
diagonalMatrix<T>::diagonalMatrix(int theN = 10)
{
	if (theN < 1) {
		throw illegalParameterValue("Parameter mu be >=1");
	}

	element = new T[theN];
	n = theN;
}

template<typename T>
diagonalMatrix<T>::~diagonalMatrix()
{
	if (element) {
		delete[] element;
		element = nullptr;
	}
}

template<typename T>
void diagonalMatrix<T>::set(int i, int j, T value)
{
	if ((i<1) || (j<1) || (i>n) || (j>n)) {
		throw matrixIndexOutOfBounds();
	}

	if (i == j) {
		element[i] = value;
	}
	else {
		if (value != 0) {
			throw illegalParameterValue("nondiagonal elements must be zero");
		}
	}
}

template<typename T>
T diagonalMatrix<T>::get(int i, int j)const
{
	if ((i<1) || (j<1) || (i>n) || (j>n)) {
		throw matrixIndexOutOfBounds();
	}

	if (i == j)
		return element[i];
	else
		return 0;
}

template<typename T>
void diagonalMatrix<T>::output(ostream& out) const
{
	for (int i = 1; i <= n; ++i) {
		for (int j = 1; j <= n; j++) {
			if (i == j) {
				out << element[i]<<" ";
				continue;
			}
			out << "0 ";
		}
		out << endl;
	}
}

演示案例

int main()
{
	diagonalMatrix<int> *matrix = new diagonalMatrix<int>(3);

	matrix->set(1,1,1);
	matrix->set(2, 2, 2);
	matrix->set(3, 3, 3);

	cout << "matrix[1,1]="<< matrix->get(1, 1) <<endl;
	cout << "matrix[2,2]=" << matrix->get(2, 2) << endl;
	cout << "matrix[3,3]=" << matrix->get(3, 3) << endl;

	matrix->output(cout);

	return 0;
}

四、三对角矩阵

  • 三对角矩阵:M是一个三对角矩阵,当且仅当|i-j|>1时,M(i,j)=0

  • 非0元素排列在如下三条对角线上:
    • ①主对角线:i=j
    • ②主对角线之下的对角线(称为低对角线):i=j+1
    • ③主对角线之上的对角线(称为高对角线):i=j-1

编码实现:

  • 三条对角线上的元素总数为3*rows-2。可以用一个容量3*rows-2的一维数组element来描述三对角矩阵
  • 以下图这个三对角矩阵为例:
    • 如果逐行映射:则element[0-9]={2,1,3,1,3,5,7,9,0}
    • 如果逐列映射:则element[0-9]={2,3,1,1,5,3,2,9,7,0}
    • 如果从低对角线开始逐条对角线映射:则element[0-9]={3,5,9,2,1,2,0,1,3,7}

  • 每一种映射方式,get和set方法的代码都不同,下面我们假设为逐条对角线映射

异常类定义

class illegalParameterValue
{
	string message;
public:
	illegalParameterValue(const char *theMessage ="Illegal Parameter Value"):message(theMessage) {}
	const char *what() {
		return message.c_str();
	}
};

class matrixIndexOutOfBounds
{
public:
	matrixIndexOutOfBounds(string theMessage = "Matrix index out of bounds") :message(theMessage){}
	const char *what() {
		return message.c_str();
	}
private:
	string message;
};

类定义 

template<typename T>
class tridiagonalMatrix
{
public:
	tridiagonalMatrix(int theN = 10);
	~tridiagonalMatrix();
	T get(int i,int j)const;
	void set(int i, int j, T value);
	void output(ostream& out) const;
private:
	T *element;  //存放矩阵的数组
	int n; //矩阵维数
};

类成员实现

template<typename T>
tridiagonalMatrix<T>::tridiagonalMatrix(int theN = 10)
{
	if (theN < 1) {
		throw illegalParameterValue("Parameter mu be >=1");
	}

	element = new T[3*theN-2];
	n = theN;
}

template<typename T>
tridiagonalMatrix<T>::~tridiagonalMatrix()
{
	if (element) {
		delete[] element;
		element = nullptr;
	}
}

template<typename T>
 T tridiagonalMatrix<T>::get(int i, int j)const
{
	if ((i<1) || (j<1) || (i>n) || (j>n)) {
		throw matrixIndexOutOfBounds();
	}

	switch (i-j)
	{
	case 1: //下对角线
		return element[i - 2];
	case 0: //主对角线
		return element[n + i - 2];
	case -1: //上对角线
		return element[2 * n + i - 2];
	default:
		return 0;
	}
}

template<typename T>
void tridiagonalMatrix<T>::set(int i, int j, T value)
{
	if ((i<1) || (j<1) || (i>n) || (j>n)) {
		throw matrixIndexOutOfBounds();
	}

	switch(i - j)
	{
	case 1: //下对角线
		element[i - 2] = value;
		break;
	case 0: //主对角线
		element[n + i - 2] = value;
		break;
	case -1: //上对角线
		element[2 * n + i - 2] = value;
		break;
	default:
		if (value != 0) {
			throw illegalParameterValue("nondiagonal elements must be zero");
		}
		break;
	}
}

template<typename T>
void tridiagonalMatrix<T>::output(ostream& out) const
{
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			switch (i - j)
			{
			case 1: //下对角线
				out << element[i - 2] << " ";
				continue;
			case 0: //主对角线
				out << element[n + i - 2] << " ";
				continue;
			case -1: //上对角线
				out << element[2 * n + i - 2]<<" ";
				continue;
			default:
				out << "0 ";
				continue;
			}
		}
		out << endl;
	}
}

演示效果

int main()
{
	tridiagonalMatrix<int> *matrix = new tridiagonalMatrix<int>(4);
	matrix->set(1, 1, 2);
	matrix->set(1, 2, 1);
	matrix->set(2, 1, 3);
	matrix->set(2, 2, 1);
	matrix->set(2, 3, 3);
	matrix->set(3, 2, 5);
	matrix->set(3, 3, 2);
	matrix->set(3, 4, 7);
	matrix->set(4, 3, 9);
	matrix->set(4, 4, 0);

	matrix->output(cout);
	return 0;
}

五、三角矩阵

  • 下三角矩阵:M是一个下三角矩阵,当且仅当i<j时,M(i,j)=0
  • 上三角矩阵:M是一个上三角矩阵,当且仅当i>j时,M(i,j)=0

编码实现:

  • 在一个n行的下三角矩阵中(见下图),非0区域的第一行有1个元素,第二行有2个元素,......,第n行有n个元素
  • 在一个n行的上三角矩阵中(见下图),非0区域的第一行有n个元素,第二行有n-1个元素,......,第n行有1个元素

  • 总结:下三角矩阵或上三角矩阵中非0区域共有非0元素:n(n+1)/2。一个三角矩阵可以用一个大小为n(n+1)/2的一维数组来表示
  • 以下面的下三角矩阵为例:
    • 按行映射:element[0-9]={2,5,1,0,3,1,4,2,7,0}
    • 按列映射:element[0-9]={2,5,0,4,1,3,2,1,7,0}

  • 下三角矩阵的元素L(i,j):
    • 如果i<j,则L(i,j)=0
    • 如果i>=j,则L(i,j)位于非0区域。如果按行映射,在元素L(i,j)(i>=j)之前分别有个元素位于第1行至第i-1行的非0区域和j-1个元素位于第i行的非0区域拒,共有

异常类定义

class illegalParameterValue
{
	string message;
public:
	illegalParameterValue(const char *theMessage ="Illegal Parameter Value"):message(theMessage) {}
	const char *what() {
		return message.c_str();
	}
};

class matrixIndexOutOfBounds
{
public:
	matrixIndexOutOfBounds(string theMessage = "Matrix index out of bounds") :message(theMessage){}
	const char *what() {
		return message.c_str();
	}
private:
	string message;
};

类定义 

template<typename T>
class lowerTriangularMatrix
{
public:
	lowerTriangularMatrix(int theN = 10);
	~lowerTriangularMatrix();
	void set(int i, int j, T value);
	T get(int i, int j)const;
	void output(ostream& out) const;
private:
	T *element;  //存放矩阵的数组
	int n;  //矩阵维度
};

类成员实现

template<typename T>
lowerTriangularMatrix<T>::lowerTriangularMatrix(int theN = 10)
{
	if (theN < 1) {
		throw illegalParameterValue("Parameter mu be >=1");
	}

	element = new T[theN*(theN + 1) / 2];
	n = theN;
}

template<typename T>
lowerTriangularMatrix<T>::~lowerTriangularMatrix()
{
	if (element) {
		delete[] element;
		element = nullptr;
	}
}

template<typename T>
void lowerTriangularMatrix<T>::set(int i, int j, T value)
{
	if ((i<1) || (j<1) || (i>n) || (j>n)) {
		throw matrixIndexOutOfBounds();
	}

	if (i >= j) {
		element[i*(i - 1) / 2 + j - 1] = value;
	}
	else {
		if (value != 0) {
			throw illegalParameterValue("nondiagonal elements must be zero");
		}
	}
}

template<typename T>
T lowerTriangularMatrix<T>::get(int i, int j)const
{
	if ((i<1) || (j<1) || (i>n) || (j>n)) {
		throw matrixIndexOutOfBounds();
	}

	if (i >= j)
		return element[i*(i - 1) / 2 + j - 1];
	else
		return 0;
}

template<typename T>
void lowerTriangularMatrix<T>::output(ostream& out) const
{
	for (int i = 1; i <= n; ++i) {
		for (int j = 1; j <= n; j++) {
			if (i >= j) {
				out << element[i*(i - 1) / 2 + j - 1] << " ";
				continue;
			}
			out << "0 ";
		}
		out << endl;
	}
}

演示效果

int main()
{
	lowerTriangularMatrix<int> *matrix = new lowerTriangularMatrix<int>(4);
	matrix->set(1, 1, 2);
	matrix->set(2, 1, 5);
	matrix->set(2, 2, 1);
	matrix->set(3, 1, 0);
	matrix->set(3, 2, 3);
	matrix->set(3, 3, 1);
	matrix->set(4, 1, 4);
	matrix->set(4, 2, 2);
	matrix->set(4, 3, 7);
	matrix->set(4, 4, 0);

	matrix->output(cout);

	return 0;
}

六、对称矩阵

  • 对称矩阵:M是一个对称矩阵,当且仅当对于所有的j和j,M(i,j)=M(j,i)

  • 编码实现:一个n*n的对称矩阵,可以视为下三角或上三角矩阵,用三角矩阵的表示方法,用一个大小为n(n+1)/2的一维数组来表示。未存储的元素可以用存储的元素来计算

七、总结

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

董哥的黑板报

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值