当前位置: 首页 > news >正文

矩阵扩展-算卷积算法介绍及C语言代码实现

目录

矩阵扩展算法——简单的算卷积

杂谈

矩阵

矩阵的幂

矩阵转置 


矩阵扩展算法——简单的算卷积

接着上文,矩阵进行更深入的学习就需要学习更多的处理了,矩阵被运用在很多的领域,这里简单以计算机图形处理的重要概念——卷积,为例进行说明:

卷积。用一个模板去和另一个图片对比,进行卷积运算。目的是使目标与目标之间的差距变得更大。卷积在数字图像处理中最常见的应用为锐化和边缘提取,此外,在人工智能中的图像处理也极为常见,这里的运算介绍不提供繁杂的公式(相信短时间内也看不懂)使用Zero padding,unit strides(零填充,单位滑动)的计算方式进行举例。

(图片来自外国的学术论坛datascience)

对于此类计算,有两个矩阵a和b,矩阵a是原矩阵,b是卷积核,他们的运算过程是,首先对b矩阵进行倒置,如:

 接着,再将待处理矩阵的部分与卷积核进行逐个进行相对应的运算,本例子由于按照边缘’零’处理的方式,因此边缘全部按照0进行运算,如图运算的过程为:0*1+0*2+0*3+0*2+1*1+2*2+0*1+1*2+2*1=9,这样的一个值计算完成后,对每一个值再度进行运算即可。

以卷积核为3*3为例,代码样例为: 

#include <stdio.h>#define MAXN 105int n, m;
int org[MAXN][MAXN] = {0};
int ker[3][3] = {0};
int ans[MAXN][MAXN] = {0};int main() {scanf("%d %d", &n, &m);// 输入待处理的矩阵for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) {scanf("%d", &org[i][j]);}}// 以倒置的方式输入卷积核for (int i = 2; i >= 0; i--) {scanf("%d %d %d", &ker[i][2], &ker[i][1], &ker[i][0]);}// 卷积运算    for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) {int tmp = 0;for (int a = 0; a < 3; a++) {for (int b = 0; b < 3; b++) {tmp += (ker[a][b] * org[i - 1 + a][j - 1 + b]);}}ans[i][j] = tmp;}}// 结果输出for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) {printf("%d ", ans[i][j]);}printf("\n");}return 0;
}

杂谈

从前文的代码实现可以看出,矩阵在整个计算机中使用非常广泛,而其实现方式又无不与二维数组这个概念相对应,二维数组是最简单的矩阵表示方式,其便利性可以让我们设计出相当多的矩阵相关的算法,与一维的运算不同,二维的运算无论从理解出发还是计算乃至代码设计出发,都复杂了许多,这就需要充分的数学知识做铺垫,也希望读者能够细细理解代数这一门学科的奥妙。

矩阵

 

代码示例:

#include<stdlib.h>
#include<stdio.h>
#include<stdbool.h>
// 对于该题也可以把数组设为arr[7][7],count[7],设为全局变量更好,方便函数传参
int SumMax(int** arr, int n)// 计算矩阵中列的最大值
{int max = -1000;for (int i = 0; i < n; i++){int sum = 0;for (int j = 0; j < n; j++){sum += arr[j][i];}max = sum > max ? sum : max;}return max;
}
void RightRotate(int** arr, int n, int i)// 实现右移一次
{int temp = arr[i][n - 1];for (int k = n - 2; k >= 0; k--){arr[i][k + 1] = arr[i][k];}arr[i][0] = temp;
}
int main()
{int n;while (scanf("%d", &n) != EOF && n != -1)// -1结束{// 定义一个二维数组,为n*n的矩阵int** arr = (int**)malloc(n * sizeof(int*));for (int i = 0; i < n; i++){arr[i] = (int*)malloc(n * sizeof(int));}// 定义一个一维数组,用来储存每一行需移动的次数int* count = (int*)malloc(n * sizeof(int));    // 初始化数据for (int i = 0; i < n; i++){count[i] = 0;for (int j = 0; j < n; j++){scanf("%d", &arr[i][j]);}}int min = 100000;if (n == 1){min = arr[0][0];}else{bool flag = true;while (flag){flag = false;// 用于终止循环,当第二行右移完之后for (int i = n - 1; i >= 1; i--)// 实现第i行的右移,一直到第二行即可{RightRotate(arr, n, i);if (count[i] < n)// 每一行最多移动n次{count[i]++;min = SumMax(arr, n) < min ? SumMax(arr, n) : min;for (int j = i + 1; j < n; j++)count[j] = 0;// 将i行后面移动的次数重置为0,再重新进行每行的右移flag = true;break;}}}}// 或者像下面这样一次循环,注意一下不同之处while (flag){flag = false;// 用于终止循环,当第一行右移完之后for (int i = n - 1; i >= 0; i--)// 实现第i行的右移,一直到第一行即可{RightRotate(arr, n, i);if (count[i] < n)// 每一行最多移动n次{count[i]++;min = SumMax(arr, n) < min ? SumMax(arr, n) : min;for (int j = i + 1; j < n; j++)count[j] = 0;// 将i行后面移动的次数重置为0,再重新进行每行的右移flag = true;break;}}}printf("%d\n", min);// 动态申请内存后释放,养成一个好习惯free(arr);free(count);arr = NULL;count = NULL;}return 0;
}

矩阵的幂

 代码示例:

#include<iostream>
#include<cstring>
using namespace std;
typedef long long LL;
class M
{public:LL data[101][101];M(){memset(data,0,sizeof(data));}
};
M *Mul(M *m1,M *m2)
{M *ans=new M();for(int i=0;i<2;i++)for(int j=0;j<2;j++)for(int k=0;k<2;k++)ans->data[i][j]+=m1->data[i][k]*m2->data[k][j];return ans;
}
M *mPow(M *m,int p)
{M *E=new M();for(int i=0;i<2;i++)for(int j=0;j<2;j++)if(i==j)E->data[i][j]=1;while(p!=0){if((p&1))E=Mul(E,m);m=Mul(m,m);p>>=1;}return E;
}
int main()
{int n;M *res=new M(),*a=new M();a->data[0][0]=0;a->data[0][1]=1;a->data[1][0]=2;a->data[1][1]=3;while(cin>>n){res=mPow(a,n);for(int i=0;i<2;i++)for(int j=0;j<2;j++)cout<<res->data[i][j]<<" ";cout<<endl;memset(res,0,sizeof(res));}return 0;
}

矩阵转置 

代码示例:

#include<stdio.h>int main(){int a[100][100];int n,i,j;scanf("%d",&n);for(i=0;i<n;i++){for(j=0;j<n;j++){scanf("%d",&a[i][j]);}}for(i=0;i<n;i++){for(j=0;j<n;j++){printf("%d ",a[j][i]);}printf("\n");}return 0;}

http://www.xdnf.cn/news/314497.html

相关文章:

  • Node.js vs 浏览器中的JavaScript:区别全解析
  • QT —— QWidget(2)
  • 【Science Advances】普林斯顿大学利用非相干光打造可重构纳米光子神经网络
  • 全文索引数据库Elasticsearch底层Lucene
  • SafeDrive:大语言模型实现自动驾驶汽车知识驱动和数据驱动的风险-敏感决策——论文阅读
  • 【Pandas】pandas DataFrame expanding
  • 常用设计模式在 Spring Boot 项目中的实战案例
  • 【LLM+Code】Devin PromptTools详细解读
  • 【spring】Spring、Spring MVC、Spring Boot、Spring Cloud?
  • 【Bootstrap V4系列】学习入门教程之 组件-折叠(Collapse)
  • Python爬虫(20)Python爬虫数据存储技巧:二进制格式(Pickle/Parquet)性能优化实战
  • 802.11s Mesh 组网框架流程
  • 【Hive入门】Hive数据导入与导出:批量操作与HDFS数据迁移完全指南
  • Windows环境下maven的安装与配置
  • 前端取经路——工程化渡劫:八戒的构建之道
  • 在Python和C/C++之间共享std::vector<std::vector<int>>数据
  • Linux复习笔记(一)基础命令和操作
  • 信创生态核心技术栈:国产芯片架构适配详解
  • Kafka生产者send方法详解
  • spark基本介绍
  • 当当狸智能天文望远镜 TW2 | 用科技触摸星辰,让探索触手可及
  • 如何使用极狐GitLab 软件包仓库功能托管 maven?
  • Spark 处理过程转换:算子与行动算子详解
  • 团队协作的润滑剂——GitHub与协作流程
  • P1782 旅行商的背包 Solution
  • Dagger中编译import报找不到ProvideClientFactory,initialize中ProvideClientFactory爆红
  • 笔记本外接显示器检测不到hdmi信号
  • 动态规划背包问题
  • AI健康小屋:开启智能健康管理新时代
  • 以生成性学习消除AI焦虑