数据结构:对角矩阵(Diagonal Matrix)

发布于:2025-07-26 ⋅ 阅读:(17) ⋅ 点赞:(0)

目录

矩阵的传统表示:二维数组

🔍 真正有用的数据是哪些?

从二维数组转为一维数组

用 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

➡️ 实质是一个表格,每个位置用两个索引 ij 访问: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];
    else
        return 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];
        else
            return 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] << " ";
            else
                cout << "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():显示整个矩阵

网站公告

今日签到

点亮在社区的每一天
去签到