求矩阵不靠边元素之和_C语言实现矩阵求秩和化约化阶梯形

d9eee519fab3667321a257c2b501fee5.png
矩阵的秩(rank)是反映矩阵固有特性的一个重要概念,在线性代数中有非常重要的地位. 在本文中,笔者将依据自己对矩阵秩定义对理解,利用C语言实现矩阵求秩,并实现矩阵化约化阶梯形.

一、理论基础

一个矩阵

中不为零的子式的最大阶数称为这个矩阵的秩;

对矩阵进行初等行变换(包括互换、倍乘和倍加)不改变矩阵的秩,初等列变换也不改变矩阵的秩;下面的实现过程中,我们仅采用初等行变换;

• 求矩阵的秩通常采用这样的方法:将矩阵通过初等行(列)变换化为阶梯形,阶梯形矩阵的秩为其不全为零的行的个数,得到阶梯形矩阵的秩和原矩阵等秩,从而求出矩阵的秩.

二、基本思路

• 获取矩阵的行规模

和列规模
,同时获取矩阵;

• 将矩阵按行依次化为阶梯形,然后转化为约化阶梯形,最后求秩;笔者的思路如下:

(1)按矩阵的行开始循环,在每一行循环开始时,找到该行第一个不为 0 的元素

,并利用
消元法将该元素所在列
上、该元素所在行
之后的元素都约为 0 ,这样在完成所有消元之后,我们可以获得一个
伪阶梯矩阵,该伪阶梯矩阵一定能通过行互换变为一个阶梯矩阵;

(2)把伪阶梯矩阵调整为阶梯矩阵,并把阶梯头化为 1 ,再把每个阶梯头上方均消为 0 ,这样便获得了约化阶梯形矩阵;

(3)统计含有不为 0 元素的行数,这个数就是矩阵的秩

.

* 对于上文中定义的伪阶梯矩阵,举一个 3 阶方阵

来体会:

(1)如果元素

便非零,则将矩阵约化为
(此时
等元素表示改变后的该位置元素,为方便计如此表示,下同);如果此时的元素
也非零,则矩阵约化为
,矩阵成为了阶梯形;

(2)如果元素

为零而
非零,则找到矩阵第一行第一个非零元素,将矩阵约化为
;如果第二行第一列元素
非零,则矩阵约化为
,此时只要调换第一、二行,就可得到
,也能化为一个阶梯矩阵;

(3)其余状况类同.

三、实现方法

  1. 编写主函数,实现用户输入矩阵的行规模、列规模和矩阵本身:
int main()
{
    float matrix[20][20];
    int i,j,r,c;
    
    printf("请输入矩阵的行规模:");
    scanf("%d",&r);
    printf("请输入矩阵的列规模:");
    scanf("%d",&c);
    printf("请输入矩阵:n");
    for(i = 0;i < r;i ++)
        for(j = 0;j < c;j ++)
            scanf("%f",&matrix[i][j]);
    
    printf("矩阵的秩r = %d.n",rank(matrix,r,c));
    printf("约化阶梯形矩阵为:n");
    show_standard_echelon(matrix,r,c);
    
    return 0;
}

将矩阵化简为约化阶梯形、输出阶梯矩阵和求矩阵的秩,我们分别用函数

float standard_echelon(float matrix[20][20],int r,int c,int x,int y);
void show_standard_echelon(float matrix[20][20],int r,int c);
int rank(float matrix[20][20],int r,int c);

来实现.

2.

消元法取得伪阶梯矩阵

说明 :接下来的过程,直到生成约化阶梯形,均应当是函数

float standard_echelon(float matrix[20][20],int r,int c,int x,int y);

中的内容. 要注意,函数中会生成约化阶梯矩阵,但是函数返回的是申请返回的行列位置上的元素(例如在调用函数时输入了 standard_echelon(matrix,r,c,2,3),则函数返回其约化阶梯矩阵的第 3 行第 4 列的值而不是整个矩阵). 之后的矩阵运算函数,均采用这种方式返回,这样可以避免采用指针来传递矩阵,便于掉用时的数据统一;

接下来的第一步,我们用消元法把矩阵转化为伪阶梯形,先来看代码;

float times;
int i,j,r,c;

for(i = 0;i < r - 1;i ++)
    for(k = i + 1;k < r;k ++)
    {
        j = 0;
        while(matrix[i][j] == 0)
            j ++;
        if(matrix[i][j] != 0)
        {
            times = matrix[k][j] / matrix[i][j];
            for(j = 0;j < c;j ++)
                matrix[k][j] -= matrix[i][j] * times;
        }
    }

按照我们之前的基本思路,在每一行的循环开始时,我们都去找该行的第一个非零元素,因此,可以通过

j = 0;
while(matrix[i][j] == 0)
    j ++;

实现非零元素的查找;

找到该行的非零元素之后,需要将该元素下方的全部元素消为0,这时候需要对元素所在行按照不同的倍率(记为 times)实行倍乘,然后减到相应的行中,实现消元. 对该元素所在行之后的行开始循环,这个倍率 times 就等于该元素所在列上其他元素 matrix[k][j] 与该元素 matrix[i][j] 的比值,则:

if(matrix[i][j] != 0)
{
    times = matrix[k][j] / matrix[i][j];
    for(j = 0;j < c;j ++)
        matrix[k][j] -= matrix[i][j] * times;
}

经过这一步,矩阵就被化为了伪阶梯矩阵.

再通过下面的过程:

for(i = 0;i < r;i ++)
{
    j = 0;
    while(matrix[i][j] == 0)
        j ++;
    if(matrix[i][j] != 0)
    {
        times = matrix[i][j];
        for(j = 0;j < c;j ++)
            matrix[i][j] /= times;
    }
}

我们就把全部的阶梯头化为了 1.

3. 调整为阶梯形:要通过行变换将矩阵化为阶梯形,我们考虑到:阶梯矩阵中随着行数增加,每一行在第一个非零元素出现之前的 0 零元素个数一定是的增加(除非已经出现了元素全为 0 的行),因此我们只要数出第一个非零元素出现之前的 0 零元素个数,把个数与行数

相对应起来,储存在数组 total 中:
int total[20] = {0};

for(i = 0;i < r;i ++)
    for(j = 0;j < c;j ++)
        if(matrix[i][j] == 0)
            total[i] ++;
        else
            break;

total 的下标与行数相同,然后利用循环右移的基本思路将矩阵按行、以每行对应的 total 值由小到大重新排列. 由于编码需要,引入一个新的量 l 来表示行和列,代码如下;

int l;
float temp;

for(l = r - 1;l > 0;l --)
    for(i = 0;i < l;i ++)
        if(total[l] < total[i])
            for(j = 0;j < c;j ++)
            {
                temp = matrix[l][j];
                matrix[l][j] = matrix[i][j];
                matrix[i][j] = temp;
            }

这样矩阵就被化成了阶梯形.

4. 化为约化阶梯形:基本思路不变,在每一行中找到第一个 1(阶梯头),然后把阶梯头上方的元素全部消为 0,就完成了约化,代码如下:

int l;

for(i = 0;i < r;i ++)
{
    j = 0;
    while(matrix[i][j] == 0)
        j ++;
    if(matrix[i][j] != 0)
        for(k = 0;k < i;k ++)
        {
            times = matrix[k][j] / matrix[i][j];
            for(l = 0;l < c;l ++)
                matrix[k][l] -= times * matrix[i][l];
        }
}

到此为止,本函数已经把矩阵化为了约化阶梯形,返回值:

return matrix[x][y];

就大功告成了.

5. 最后用 rank 函数计算矩阵的秩:

由于 standard_echelon 返回的是约化阶梯形矩阵中用户指定行列位置的元素,在计算秩时还需要先将矩阵还原出来:

float echelon_matrix[20][20];
int i,j;
    
for(i = 0;i < r;i ++)
    for(j = 0;j < c;j ++)
        echelon_matrix[i][j] = standard_echelon(matrix,r,c,i,j);

接下来,用一个量 none_zero 判断每一行元素是否含有非零元素,初始化其为 0,如果找到一个非零元素,则跳出列循环,并让秩的值 result 增加 1:

int none_zero = 0,result = 0;
    
for(i = 0;i < r;i ++)
{
    for(j = 0;j < c;j ++)
        if(echelon_matrix[i][j] != 0)
        {
            none_zero = 1;
            break;
        }
    if(none_zero == 1)
        result ++;
    none_zero = 0;
}

如此一来,便实现了利用约化阶梯形计算矩阵的秩的过程.

把上述过程全部综合起来并适当简化,得到全过程的代码如下:

#include <stdio.h>
#include <math.h>

int rank(float matrix[20][20],int r,int c);
float standard_echelon(float matrix[20][20],int r,int c,int x,int y);
void show_standard_echelon(float matrix[20][20],int r,int c);

int main()
{
    float matrix[20][20];
    int i,j,r,c;
    
    printf("请输入矩阵的行规模:");
    scanf("%d",&r);
    printf("请输入矩阵的列规模:");
    scanf("%d",&c);
    printf("请输入矩阵:n");
    for(i = 0;i < r;i ++)
        for(j = 0;j < c;j ++)
            scanf("%f",&matrix[i][j]);
    
    printf("矩阵的秩r = %d.n",rank(matrix,r,c));
    printf("约化阶梯形矩阵为:n");
    show_standard_echelon(matrix,r,c);
    
    return 0;
}
   
int rank(float matrix[20][20],int r,int c)
{
    float echelon_matrix[20][20];
    int i,j,none_zero = 0,result = 0;
    
    for(i = 0;i < r;i ++)
        for(j = 0;j < c;j ++)
            echelon_matrix[i][j] = standard_echelon(matrix,r,c,i,j);
    
    for(i = 0;i < r;i ++)
    {
        for(j = 0;j < c;j ++)
            if(echelon_matrix[i][j] != 0)
            {
                none_zero = 1;
                break;
            }
        if(none_zero == 1)
            result ++;
        none_zero = 0;
    }
    return result;
}


float standard_echelon(float matrix[20][20],int r,int c,int x,int y)
{
    int i,j,k,l,total[20] = {0};
    float times,temp;
    
    for(i = 0;i < r - 1;i ++)
        for(k = i + 1;k < r;k ++)
        {
            j = 0;
            while(matrix[i][j] == 0)
                j ++;
            if(matrix[i][j] != 0)
            {
                times = matrix[k][j] / matrix[i][j];
                for(j = 0;j < c;j ++)
                    matrix[k][j] -= matrix[i][j] * times;
            }
        }
    for(i = 0;i < r;i ++)
    {
        j = 0;
        while(matrix[i][j] == 0)
            j ++;
        if(matrix[i][j] != 0)
        {
            times = matrix[i][j];
            for(j = 0;j < c;j ++)
                matrix[i][j] /= times;
        }
    }
    for(i = 0;i < r;i ++)
        for(j = 0;j < c;j ++)
            if(matrix[i][j] == 0)
                total[i] ++;
            else
                break;
    for(l = r - 1;l > 0;l --)
        for(i = 0;i < l;i ++)
            if(total[l] < total[i])
                for(j = 0;j < c;j ++)
                {
                    temp = matrix[l][j];
                    matrix[l][j] = matrix[i][j];
                    matrix[i][j] = temp;
                }
    for(i = 0;i < r;i ++)
    {
        j = 0;
        while(matrix[i][j] == 0)
            j ++;
        if(matrix[i][j] != 0)
            for(k = 0;k < i;k ++)
            {
                times = matrix[k][j] / matrix[i][j];
                for(l = 0;l < c;l ++)
                    matrix[k][l] -= times * matrix[i][l];
            }
    }

    return matrix[x][y];
}

void show_standard_echelon(float matrix[20][20],int r,int c)
{
    int i,j;
    
    for(i = 0;i < r;i ++)
    {
        for(j = 0;j < c;j ++)
        {
            if(fabs(matrix[i][j]) < 0.0005)
                matrix[i][j] = fabs(matrix[i][j]);
            printf("%.3ft",matrix[i][j]);
        }
        printf("n");
    }
}

* 以 5 阶方阵

和 4 行 6 列矩阵
作为测试样例检验一下:

06efb08c56c3dfdfdfbb387969202ba4.png
矩阵 A 的秩与约化阶梯形

f8b6668ae29b63645bfb88004d893397.png
矩阵 B 的秩和约化阶梯形

上述实现方法并非最优,仅代表笔者个人的想法,如果发现错误,还请各位在评论区及时指正.

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值