数据结构:对角矩阵(Diagonal Matrix)
目录
矩阵的传统表示:二维数组
🔍 真正有用的数据是哪些?
从二维数组转为一维数组
用 C++ 类实现对角矩阵
1. 对角矩阵真正需要存什么?
2. 对角矩阵允许哪些行为?
3. 为什么要动态分配数组?
接下来推导每个函数如何实现
什么是对角矩阵?
在一个正方形矩阵中:只有主对角线(左上到右下)上的元素可能非零,其余全为零。
举个例子:3x3 对角矩阵
A = | 1 0 0 || 0 2 0 || 0 0 3 |
只有 A[0][0]
, A[1][1]
, A[2][2]
非零,其余全是 0
➡️ 实质是一个表格,每个位置用两个索引 i
和 j
访问:A[i][j]
矩阵的传统表示:二维数组
在 C++ 里我们通常用二维数组来表示矩阵:
int A[3][3]; // 表示一个 3×3 的矩阵
例如:
A[0][0] A[0][1] A[0][2]
A[1][0] A[1][1] A[1][2]
A[2][0] A[2][1] A[2][2]
总共有 n^2 个元素,每个都有自己的位置。
❗问题来了:如果矩阵是稀疏的或有结构的,这个方式会浪费空间。
对角矩阵是一个非常特殊的矩阵:
-
只有对角线(
i == j
)上的元素可能非 0 -
其他所有元素(
i ≠ j
)都为 0
🔍 真正有用的数据是哪些?
观察这个对角矩阵:
我们可以问自己两个问题:
哪些元素值我们真正关心?
哪些元素值是注定为 0、不需要存?
答案很明显:
条件 | 是否有用 | 存储与否 |
---|---|---|
i == j | 是对角线 → 非零元素 → 必须存 | ✔ 存 |
i ≠ j | 一定是 0,无需存储 | ✘ 不存 |
所以,对角矩阵只需要存储 n 个元素!
我们就可以只用一个 一维数组 存这些元素:
//只存储对角线上的元素
int D[n]; // D[0] 存 A[0][0], D[1] 存 A[1][1], ..., D[n-1] 存 A[n-1][n-1]
从二维数组转为一维数组
我们的问题是:
给定任意 (i, j)
,如何通过简单规则判断:
-
要不要存储?
-
如果要 → 存在 D[] 中哪一项?
观察这个矩阵:
A[0][0] A[0][1] A[0][2]
A[1][0] A[1][1] A[1][2]
A[2][0] A[2][1] A[2][2]
我们对每一个 (i, j)
做判断:
-
如果
i != j
:一定是 0,不存 -
如果
i == j
:对角线 → 存在D[i]
中
访问时:如何从 (i,j)
得到实际值?
-
如果
i == j
:返回 D[i] -
如果
i != j
:说明是非对角元素 ⇒ 返回 0
int get(int D[], int i, int j) {if (i == j)return D[i];elsereturn 0;
}
插入时:如何通过 (i, j) 更新值?
-
如果
i == j
:表示是在对角线上,我们需要更新存储数组D[i] = value
-
如果
i != j
:不允许存储,非对角线值必须为 0 ⇒ 忽略或报错
void set(int D[], int i, int j, int value) {if (i == j)D[i] = value;else if (value != 0)cout << "Error: Only diagonal elements can be non-zero.\n";
}
用 C++ 类实现对角矩阵
第一性思考:我们要封装什么?
我们希望把对角矩阵的数据 + 行为都封装起来,变成一个可用的抽象对象。
所以我们问自己三个关键问题:
1. 对角矩阵真正需要存什么?
-
只需要存对角线上的元素:
D[0]~D[n-1]
-
也就是一个一维数组 + 大小信息
→ 数据成员:
int* D; // 存储数据(动态分配)
int n; // 矩阵大小 n × n
2. 对角矩阵允许哪些行为?
行为也就是 成员函数(methods),我们一一推导:
功能 | 描述 |
---|---|
set(i, j, x) | 如果 i==j ,设置 D[i]=x,否则忽略或报错 |
get(i, j) | 如果 i==j 返回 D[i],否则返回 0 |
display() | 打印整个 n×n 矩阵 |
构造函数 | 初始化数组大小和空间 |
析构函数 | 释放分配的堆内存 |
3. 为什么要动态分配数组?
-
因为用户可以创建任意大小的矩阵
n×n
-
所以不能用静态数组,必须用
new int[n]
动态分配
抽象转为结构:类的原型
class DiagonalMatrix {
private:int* D; // 一维数组int n; // 阶数public:DiagonalMatrix(int size); // 构造函数~DiagonalMatrix(); // 析构函数void set(int i, int j, int value); // 设置元素int get(int i, int j); // 获取元素void display(); // 打印矩阵
};
接下来推导每个函数如何实现
1. 构造函数
目标:接受一个 size,创建一个对角矩阵
DiagonalMatrix::DiagonalMatrix(int size) {n = size;D = new int[n]; // 创建对角线存储for (int i = 0; i < n; i++) D[i] = 0; // 初始化为 0
}
2. 析构函数
释放堆空间,防止内存泄露:
DiagonalMatrix::~DiagonalMatrix() {delete[] D;
}
3. set(i, j, value)
void DiagonalMatrix::set(int i, int j, int value) {if (i >= 0 && i < n && j >= 0 && j < n) {if (i == j)D[i] = value;else if (value != 0)cout << "Error: only diagonal elements can be non-zero.\n";} else {cout << "Error: index out of bounds.\n";}
}
4. get(i, j)
int DiagonalMatrix::get(int i, int j) {if (i >= 0 && i < n && j >= 0 && j < n) {if (i == j)return D[i];elsereturn 0;} else {cout << "Error: index out of bounds.\n";return -1;}
}
5. display()
void DiagonalMatrix::display() {for (int i = 0; i < n; i++) {for (int j = 0; j < n; j++) {if (i == j)cout << D[i] << " ";elsecout << "0 ";}cout << endl;}
}
最终完整使用示例(main)
int main() {DiagonalMatrix dm(4); // 创建一个 4×4 的对角矩阵dm.set(0, 0, 5);dm.set(1, 1, 9);dm.set(2, 2, 3);dm.set(3, 3, 7);dm.set(0, 1, 99); // 应报错:非对角元素dm.display();cout << "dm[2][2] = " << dm.get(2, 2) << endl;return 0;
}
总结(类设计第一性路径图)
对角矩阵↓
只需保存 D[0..n-1]↓
封装成类 DiagonalMatrix↓
数据成员:- int* D // 动态存储对角线- int n // 阶数↓
方法设计:- 构造函数:new 分配- 析构函数:delete 释放- set(i,j,x):仅 i==j 时设置- get(i,j):i==j 返回 D[i],否则 0- display():显示整个矩阵