数据结构(3)数组和矩阵

发布于 2021-08-30  855 次阅读


传统二维数组是个标准的矩阵,每行的元素数量相同

int a[3][5];

使用指针数组可以创建一个不规则二维数组

#include <iostream>
using namespace std;

#include <iostream>
using namespace std;
 
int main()
{
    int numberOfRows = 5;//行数
    int length[] = { 5,3,4,5,7 };//每一行的长度
    int** irregularArray = new int* [numberOfRows];//定义一个指针数组,数组中的指针还没分配
	  //int* irregularArray[] = new int* [numberOfRows];也是一样的
    for (int i = 0; i < numberOfRows; i++) {//给数组里的指针分配指定长度的数组
        irregularArray[i] = new int[length[i]];
    }
    irregularArray[1][2] = 2;
  	//记得delete所有new出来的东西
    for (int i = 0; i < numberOfRows; i++) {
       	 delete []irregularArray[i];
    }
  	delete []irregularArray;
}

下面定义一个矩阵类matrix

#pragma once
#include <iostream>;
using namespace std;
template<class T>
class matrix
{
	friend ostream& operator<<(ostream& out, const matrix<T>& x) {x.output(out); return out;}//重载<<
public:
	matrix(int theRows = 0, int theColumns = 0);//构造函数
	matrix(T **a,int theRows = 0, int theColumns = 0);//构造函数(使用数组赋值)
	matrix(const matrix<T>&);//构造函数(复制)
	~matrix() { delete []element; };//析构函数,删除存放元素的数组
	int rows() const { return theRows; }//返回行数
	int columns() const { return theColumns; }//返回列数
	matrix<T> transposition();//转置
	T& operator()(int i, int j)const;//重载(),通过此函数使用二维索引访问矩阵元素
	matrix<T>& operator=(const matrix<T>&);//重载=,复制每个元素
	matrix<T> operator+(const matrix<T>&) const;//重载+
	matrix<T> operator-(const matrix<T>&) const;//重载-
	matrix<T> operator*(const matrix<T>&) const;//重载*
	void output(ostream& out) const;//逐个输出元素值,提供给<<重载用
private:
	int theRows, theColumns;//行数和列数
	T* element;//用来存储数据的数组
};

三种重载函数,注意动态二维数组的创建与调用方法

//matrix.cpp
#include <iostream>;
#include "matrix.h";


/*-------------构造函数--------------------------*/
template<class T>
matrix<T>::matrix(int theRows, int theColumns) {
	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];
	copy(m.element, m.element + theRows * theColumns, element);//使用copy函数获得被复制矩阵数组的值
}

/*-------------构造函数(并赋值)---------------*/
template<class T>
matrix<T>::matrix(T **a, int theRows, int theColumns) {
	this->theRows = theRows;
	this->theColumns = theColumns;
	element = new T[theRows * theColumns];
	for (int i = 0; i < theRows; i++)
		for (int j = 0; j < theColumns; j++)
			element[i * theColumns + j] = a[i][j];
}

//main.cpp
int main()
{
	int **a = new int*[5];//创建二维动态数组

        //分配每一行的数组
 	a[0] = new int[5]{ 1,2,3,4,5 };
	a[1] = new int[5]{ 1,2,3,4,5 };
	a[2] = new int[5]{ 1,2,3,4,5 };
	matrix<int>* m = new matrix<int>(a,3,5);//创建matrix并通过数组赋值

        delete []a[0];
        delete []a[1];
        delete []a[2];
	delete []a;//记得删除动态数组
        delete m;
	return 0;
}

之后是各种运算符重载,要特别注意哪些函数返回的是引用

以重载()为例, 重载后()返回矩阵二维索引的值,这里我们设置矩阵的索引从1开始而不是数组的0开始,符合日常生活习惯。函数很简单,换算一下二维索引和一维数组的映射关系就行

template<class T>
T& matrix<T>::operator()(int i, int j) const{
	return element[(i - 1) * theColumns + j - 1];//矩阵的索引从1开始
}

重点是函数返回的是引用,这就代表我们不仅可以通过这个函数访问对应的元素值,还可以直接改变这个值,请看下面的示例 注:调用()函数时记得给前面 *m 打上括号,要不然会报错

int main()
{
	int **a = new int*[3];
	a[0] = new int[5]{ 1,2,3,4,5 };
	a[1] = new int[5]{ 1,2,3,4,5 };
	a[2] = new int[5]{ 1,2,3,4,5 };
	matrix<int>* m = new matrix<int>(a,3,5);
	cout << (*m)(1, 1) << endl;//获得矩阵(1,1)处的值
	(*m)(1, 1) = 0;
	cout << (*m)(1, 1) << endl;//改写矩阵(1,1)处的值
        delete []a[0];
        delete []a[1];
        delete []a[2];
	delete[]a;
        delete m;
	return 0;
}
可以看到数值被成功改写

加法和减法符号的重载

/*-------------加法(+)重载--------------------------*/
template<class T>
matrix<T> matrix<T>::operator+(const matrix<T>& m) const {//函数调用时使用引用符&避免复制浪费效率,使用const防止更改
	matrix<T> w(theRows, theColumns);
	for (int i = 0; i < theRows * theColumns; i++)
		w.element[i] = element[i] + m.element[i];//对应位置的值相加
	return w;
}

/*-------------劵大小是否匹配
	matrix<T> w(theRows, m.theColumns);//定义结果矩阵
	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++;
				cm += m.theColumns;//向下一行在一维数组映射就是加一行的元素个数
				sum += element[ct] * m.element[cm];
			}
			w.element[cw++] = sum;//先把结果存入数组指定位置,cw游标再加1
			ct -= theColumns - 1;//第一个矩阵游标向下一行
			cm = j;//第二个矩阵的游标回到第一行并向右移动一位
		}
		ct += theColumns;//第一个矩阵游标向下一行
		cm = 0;//第二个矩阵游标归零
	}
	return w;
}
#include <iostream>;
#include "matrix.h";
#include "matrix.cpp";
using namespace std;
int main()
{
	int **a = new int*[5];
	a[0] = new int[5]{ 1,2,3,4,5 };
	a[1] = new int[5]{ 1,2,3,4,5 };
	a[2] = new int& class="wp-block-code">friend ostream& operator<<(ostream& out, const matrix<T>& x) {x.output(out); return out;}//重载<<

这样使用c<<输出就可以逐个打印矩阵中元素的值

之后是矩阵的转置,新建一个矩阵,形状从(rows,columns)变成 (columns,rows),相应的元素映射也很明显

template<class T>
matrix<T> matrix<T>::transposition() {
	matrix<T> w(theColumns, theRows);//形状变换
	for (int i = 0; i < w.theRows; i++)
		for (int j = 0; j < w.theColumns; j++) {
			w.element[i * w.theColumns + j] = element[i+j*theColumns];
		}
	return w;
}

剩下还有一个矩阵的乘法,二维矩阵的乘法规则还是相对简单的

二维矩阵乘法
template<class T>
matrix<T> matrix<T>::operator*(const matrix<T>& m)const {
	if (theColumns != m.theRows) { abort(); };//检查矩阵大小是否匹配
	matrix<T> w(theRows, m.theColumns);//定义结果矩阵
	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++;
				cm += m.theColumns;//向下一行在一维数组映射就是加一行的元素个数
				sum += element[ct] * m.element[cm];
			}
			w.element[cw++] = sum;//先把结果存入数组指定位置,cw游标再加1
			ct -= theColumns - 1;//第一个矩阵游标向下一行
			cm = j;//第二个矩阵的游标回到第一行并向右移动一位
		}
		ct += theColumns;//第一个矩阵游标向下一行
		cm = 0;//第二个矩阵游标归零
	}
	return w;
}
#include <iostream>;
#include "matrix.h";
#include "matrix.cpp";
using namespace std;

int main()
{
	int **a = new int*[5];
	a[0] = new int[5]{ 1,2,3,4,5 };
	a[1] = new int[5]{ 1,2,3,4,5 };
	a[2] = new int[5]{ 1,2,3,4,5 };
	matrix<int>* m1 = new matrix<int>(a,3,5);
	matrix<int> m2 = *m1;
	m2 = m2.transposition();//转置
	cout<<m2 * (*m1)<<endl;//输出相乘结果
        delete []a[0];
        delete []a[1];
        delete []a[2];
	delete[]a;
        delete m1;
	return 0;
}
矩阵相乘结果
届ける言葉を今は育ててる
最后更新于 2023-09-26