• 三对角矩阵原理及C++实现


    一、三对角矩阵

    1.三对角矩阵概念

    在这里插入图片描述

    2.三对角矩阵元素数量

    对于给定n阶方阵M,若其为三对角矩阵,则元素个数N为:

    • n=1,此时方阵只有一个元素M[0][0],由定义知该元素也在三对角线上。故N=1
    • n>1,由三对角矩阵特点知,矩阵的第一行和最后一行(第n行)分别有两个非零元素,其余行每行各有三个非零元素。故N = 3*(n-2)+2*2 = 3n-2

    综上,
    N = { 1 , n=1 3 n − 2 , n>1 N=\left\{

    1,n=13n2,n>1" role="presentation">1,n=13n2,n>1
    \right. N={1,3n2,n=1n>1

    3.三对角矩阵下标变换推导(行优先和列优先)

    对于给定n阶三对角方阵M和存放该方阵的数组A,非零元素M_ij1≤i,j≤n|i-j|≤1)同数组元素A[k]0≤k)存在一一对应的关系。下面分别推导从下标i,jkki,j的关系。

    3.1行优先

    1. M_ijA[k]:即已知i,j要找出对应的k,需要知道,在数组A中,元素M_ij之前存放的元素个数num,则M_ij存放在A的第num+1个位置,对应数组A的下标正好为num(假设数组下标从0开始)。
    • 先考虑i>1的情况,即寻找第一行以下的非零元素M_ij
      • 第一行有2个非零元素;之后的2~i-1行,每行有三个非零元素。

      • i行,在M_ij之前的非零元素有j-(i-1)个。

    k = num = 2+3*(i-1-1)+j-(i-1)=2i+j-3

    • 而当i=1时,有j=1或2。且A[0]=M_11,A[1]=M_12。代入发现也符合上述公式。
      在这里插入图片描述
    1. A[k]M_ij

    首先求出A[k]位于M的第几行:由于M的第一行有两个元素,2~i-1行有三个元素,由此可以得到i关于k的表达式:i = ⌊(k+1)/3+1⌋(下取整)。(i+1为第一行“补”一个元素,加一是因为i从1开始)。
    然后可以根据上面得到的ki,j的关系得到:j = k-2i+3

    3.列优先

    由于三对角矩阵具有良好的对称性,所以只需要对行优先推导得到的关系中i,j互换即可。
    即:

    • k=2j+i-3
    • j=⌊(k+1)/3+1⌋(下取整)i=k-2j+3

    二、C++实现三对角矩阵代码

    //diagonalMatrix.hpp
    #pragma once
    #include "assert.h"
    #include 
    template <typename E>
    // 检查下标越界
    #define CHECK(i, j) \
        assert(i >= 1 && j >= 1 && i <= m_dimension && j <= m_dimension);
    
    // 检查是否是对角阵中的非零元素
    #define IS_ZERO(i, j) abs(i - j) > 1
    
    // 根据行/列优先原则获取数组对应下标
    #define GET_IDX(i, j) m_priority ? (2 * i + j - 3) : (2 * j + i - 3)
    
    class DiagonalMatrix
    {
    private:
        int m_dimension; // 方阵阶数
        int m_capacity;  // 数组容量,即方阵中非零元素数量
        E *m_array;      // 存储方阵的数组
        bool m_priority; // 0: 行优先 1:列优先
    public:
        DiagonalMatrix(int dimension, bool priority = false) : m_dimension(dimension), m_priority(priority)
        {
            assert(dimension >= 1);
            if (dimension == 1)
    
                m_capacity = 1;
    
            else
                m_capacity = 3 * dimension - 2; // capacity = (d - 2)*3 + 2*2 = 3d -2
            m_array = new E[m_capacity];
        }
        ~DiagonalMatrix()
        {
            delete m_array;
            m_array = nullptr;
        }
        // 设置元素M_ij
        void set(const E &element, int i, int j)
        {
            CHECK(i, j);
            if (IS_ZERO(i, j))
                return;
            m_array[GET_IDX(i, j)] = element;
        }
        // 获取元素M_ij
        E get(int i, int j)
        {
            CHECK(i, j);
            if (IS_ZERO(i, j))
                return 0;
            return m_array[GET_IDX(i, j)];
        }
    
        // 获取数组元素A[k]对应方阵的下标i和j
        void getKIdx(int k, int &i, int &j)
        {
            assert(k >= 0 && k < m_capacity);
            if (!m_priority)
            {
                i = (k + 1) / 3 + 1;
                j = k - 2 * i + 3;
            }
            else
            {
                j = (k + 1) / 3 + 1;
                i = k - 2 * j + 3;
            }
        }
        // 打印方阵
        void printMatrix()
        {
            for (int i = 1; i <= m_dimension; i++)
            {
                for (int j = 1; j <= m_dimension; j++)
                    std::cout << get(i, j) << ' ';
                std::cout << '\n';
            }
        }
    
        int getCapacity()
        {
            return m_capacity;
        }
    
        int getDimension()
        {
            return m_dimension;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92

    使用:

    #include "diagonalMatrix.hpp"
    int main()
    {
        using namespace std;
        DiagonalMatrix<int> d(6);
        int matrix[6][6] =
            {
                {1, 1, 0, 0, 0, 0},
                {1, 1, 1, 0, 0, 0},
                {0, 1, 1, 1, 0, 0},
                {0, 0, 1, 1, 1, 0},
                {0, 0, 0, 1, 1, 1},
                {0, 0, 0, 0, 1, 1}};
    
        // set value
        int i, j, k;
        for (i = 0; i < 6; i++)
            for (j = 0; j < 6; j++)
                if (matrix[i][j] != 0)
                    d.set(matrix[i][j], i + 1, j + 1);
    
        // get idx and value
        for (k = 0; k < d.getCapacity(); k++)
        {
            d.getKIdx(k, i, j);
            printf("k = %d , i = %d, j = %d , matrix[%d][%d] = %d\n", k, i, j, i, j, d.get(i, j));
        }
        d.printMatrix();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    结果:

    k = 0 , i = 1, j = 1 , matrix[1][1] = 1
    k = 1 , i = 1, j = 2 , matrix[1][2] = 1
    k = 2 , i = 2, j = 1 , matrix[2][1] = 1
    k = 3 , i = 2, j = 2 , matrix[2][2] = 1
    k = 4 , i = 2, j = 3 , matrix[2][3] = 1
    k = 5 , i = 3, j = 2 , matrix[3][2] = 1
    k = 6 , i = 3, j = 3 , matrix[3][3] = 1
    k = 7 , i = 3, j = 4 , matrix[3][4] = 1
    k = 8 , i = 4, j = 3 , matrix[4][3] = 1
    k = 9 , i = 4, j = 4 , matrix[4][4] = 1
    k = 10 , i = 4, j = 5 , matrix[4][5] = 1
    k = 11 , i = 5, j = 4 , matrix[5][4] = 1
    k = 12 , i = 5, j = 5 , matrix[5][5] = 1
    k = 13 , i = 5, j = 6 , matrix[5][6] = 1
    k = 14 , i = 6, j = 5 , matrix[6][5] = 1
    k = 15 , i = 6, j = 6 , matrix[6][6] = 1
    1 1 0 0 0 0
    1 1 1 0 0 0
    0 1 1 1 0 0
    0 0 1 1 1 0
    0 0 0 1 1 1
    0 0 0 0 1 1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
  • 相关阅读:
    网易数帆 Envoy Gateway 实践之旅:坚守 6 年,峥嵘渐显
    前端导出Excel并下载到本地
    2000-2020年上市公司制造业数据/制造业上市公司数据
    GoogLeNet网络
    举报即有机会解锁CSDN限定勋章|2022上半年CSDN社区治理数据公布
    数据结构学习笔记 - 带权并查集(食物链题解)
    常用的git指令
    Code For Better 谷歌开发者之声——开发者必备神器
    FPGA 按键控制串口发送
    【历史上的今天】11 月 7 日:图灵奖女性得主诞生;Twitter 告别 140 字符时代;首位中国 AI 主播
  • 原文地址:https://blog.csdn.net/m0_56745306/article/details/130895550