MATLAB 学习笔记——3. 元胞数组和结构体数组
在编程实践中,仅仅只靠浮点数数组还是不够的,我们还需要其他更灵活的数据结构(运行效率也会更慢),最常见的数据结构是元胞数组和结构体数组。
元胞数组
元胞数组是一种包含名为cell的索引数据容器的数据类型,其中的每个cell都可以包含任意类型的数据。
元胞数组可以包含文本列表、文本和数字的组合或者不同大小的矩阵等,通常用于打包一组矩阵或多组矩阵。
通过将索引括在圆括号()中可以引用cell,使用花括号{}进行索引来直接访问cell的内容,两者区别见下文。
元胞数组的创建方式如下,元胞数组通常使用二维的结构,m行n列,每一个元素是一个矩阵或其他对象,元胞数组也支持多维的定义和操作。
123C1 = {}; % 空的元胞数组C2 = {1,2,3; 'text',rand(5,10,2),{11; 22; 33}} % 2*3的元胞数组
还可以定义指定尺寸的,每一个元素均为空矩阵的元胞数组:
C = cell(n),返回由空矩阵构成的\(n\times n\)元胞数组。
C = ce ...
MATLAB 学习笔记——2. 矩阵
概述
MATLAB 对于矩阵的支持非常好,以矩阵运算为代表的基本运算功能一直是
MATLAB
引以为自豪的核心与基础。我们可以把向量和矩阵都视作矩阵进行统一的操作。在下文中我们默认讨论二维矩阵,但
MATLAB 支持多维矩阵。行向量即行数为 1 的矩阵,列向量即列数为 1
的矩阵。
在内存中,MATLAB 使用列主序进行连续存储,与 Fortran 相同,与 C
语言是反的。在下标的使用中,MATLAB 默认下标从 1 开始,与 Fortran
相同,与 C 语言等绝大部分编程语言都不同。
矩阵的尺寸信息可以通过下面的语句获取:
size(A) 行数和列数,返回一个1x2的行向量;
size(A,1) 行数;
size(A,2) 列数。
下面我们默认矩阵是由浮点数组成的二维数组,但是MATLAB也支持更高维度的数组,而且元素类型除了浮点数,还可以是字符、布尔值、结构体数组、元胞数组等。
矩阵的创建
矩阵的字面值输入:
空格或者逗号视作单行元素的分隔;
分号视作不同行元素的分隔,也可以输入回车进行换行。(输入分号+回车也只是一次换行效果,并不会叠加)
例如
123456789 ...
MATLAB 学习笔记——1. 基础
之前对 MATLAB 的使用都是轻量级的,因此总是不太熟,趁着必须要用 MATLAB
的机会,小结一下 MATLAB 的基本语法,便于查阅。(2022年9月)
之前的MATLAB笔记还是太简陋了,必须加上面向对象等部分组成更完整的系列笔记。因为现在手上的代码还是太乱了,必须彻底重构一下,先把笔记补上。(2024年6月)
基本语法
注释:MATLAB
使用百分号%进行单行注释,使用%{...%}进行多行注释。
分号:; MATLAB
并不需要强制使用分号作为语句的结尾,以空格或回车结尾即可。不使用分号结尾时会把计算结果显示出来,使用分号结尾则会抑制计算结果的显示。
续行符:在第一行的结尾使用...可以把命令接续到第二行。(如果直接把...接在数字后面会报错,可以加空格)
命令补全:Tab 键。
对命令行窗口清屏:clc
MATLAB 的一切数据都是矩阵:行向量是行数为 1 的矩阵,数是行数列数均为
1 的矩阵,甚至一个无效命令,它的返回值[]都是一个 0 行 0
列的空矩阵。
和其他现代编程语言类似:
MATLAB 对大小写敏感,这与它所参考的 FORTRAN ...
UML类图速成
类的表示
一个类在类图中用矩形框表示,矩形框分为三层:
类名
类的成员变量:名称和类型
类的方法:名称,参数类型和名称,返回值类型(也就是完整的函数签名)
对于成员变量和方法,使用不同的前缀代表访问修饰符:
缺省代表default
+代表public
-代表private
#代表protected
对于一个抽象类或接口,它的类名以及抽象方法(留给子类实现的方法)名称使用斜体表示,以示区别。
类的关系
下面的几种关系讨论的都是两个类之间的关系,也可以理解为两个类的实例之间的关系。
对于满足后四种关系的两个类,如果屏蔽了其中一个类的定义,另一个类是无法通过编译的。
有的教程将后四种关系统称为关联关系,将聚合/组合/依赖关系视作特殊的关联关系。
继承与实现
继承和实现是类之间非常强的关系,在代码中的特征非常明显:
继承关系(泛化关系)
子类和父类之间的继承关系。
在记号上使用带空心三角箭头的实线相连,空心三角箭头指向父类。
实现关系
类和接口之间的实现关系。
在记号上使用带空心三角箭头的虚线相连,空心三角箭头指向接口。
这里的接口主要是针对Java的,Java虽然不 ...
Cpp Pimpl 模式
Pimpl(Pointer to
Implementation)是一种常用的C++设计模式,用于隐藏类的实现细节、减少编译依赖性和提高封装性。
概述
Pimpl模式主要的思路就是:在实现类的外层套上一层简单的接口类,接口类只含有一个指向实现类的指针,并暴露必要的接口。
注意接口类包含的不是实现类对象,而是实现类指针,否则修改实现类无法做到二进制的稳定性。
Pimpl模式可以达到如下的效果:
隐藏实现细节:实现细节被封装在实现类中,提供给用户的接口类只暴露必要的接口,提高代码的封装性
维护接口稳定性:我们只需要维护暴露在接口类中的接口稳定性即可,实现类的内部可以自由地进行更改
减少编译依赖性:由于接口类的实现细节被隐藏,接口类只含有实现类的指针,对实现类进行的细节改变不会导致依赖于接口类的文件重新编译,从而减少编译时间。
Pimpl模式和继承以及虚函数的作用是不重合的,并不存在相互取代的关系。
和虚函数类似,Pimpl增加了间接的指针调用,这必然会影响到程序的运行效率。
示例
包括三个文件:
Demo.h:接口类的声明
Demo.cpp:实现类的完整实现,以及接口类的实现
main ...
Linux ssh 笔记
详细记录一下关于ssh的内容,这部分内容比较繁杂。
基本使用(1)
ssh 最基本的用途就是登录远程服务器 1ssh user@hostname
其中:
user是登录用户名
hostname是主机名,它可以是域名,也可以是某个具体的 IP
地址或局域网内部的主机名。
可以缺省用户名,此时将使用本地用户名作为远程服务器的登录用户名。
1ssh hostname
用户名也可以通过-l参数指定,这样用户名和主机名就不用写在一起了,在脚本中可能更方便
1ssh -l username hostname
ssh
会默认连接远程服务器的22端口,使用-p参数也可以指定其他端口(同时也要修改远程服务器的监听端口)
1ssh -p 8821 foo.com
ssh
在连接到远程服务器后会进行验证:如果第一次通过ssh连接某一台服务器,
命令行会显示一段文字,表示不认识这台机器,提醒用户确认是否需要连接
123The authenticity of host 'foo.com (192.168.121.111)' can't be established.ECDSA ...
C/Cpp 枚举类与强枚举类
整理一下关于C/C++中枚举类的用法。
概述
C和C++中提供了枚举类型,用于定义一组相关的命名离散常量,
通常直接使用非负整数实现,并且枚举可以很方便地和非负整数进行相互转换。
但是这不符合C++类型系统的设计要求,C++将之前的枚举称为弱枚举类型,并且提供了更加安全的强枚举类型,
强枚举相比弱枚举有如下优点:
作用域限制:枚举成员不会污染所在作用域的命名空间。
类型安全:强类型枚举不允许隐式转换为整数,必须显式进行转换。
明确的基础类型:可以指定枚举成员的基础类型,默认是int。
弱枚举类型
使用enum定义枚举类型和枚举变量,例如 12345enum DAY{ MON, TUE, WED, THU, FRI, SAT, SUN};enum DAY day;
也可以将它们合在一起简写 1234enum DAY{ MON, TUE, WED, THU, FRI, SAT, SUN} day1, day2;
使用枚举类例如 12345678910111213#include <stdio.h>enum DAY ...
Cpp 进阶笔记——3.引用折叠、万能引用和完美转发
引用折叠规则
引入了右值引用后,我们必须要处理右值引用所带来的一系列类型推导问题,因为C++不允许“引用的引用”这种类型存在,
对于涉及两个连续出现的引用修饰词的类型推导时,定义了如下的引用折叠规则:
1234& + & -> && + && -> &&& + & -> &&& + && -> &&
简而言之,就是左值引用短路右值引用:只有连续两个右值引用遇到一起,才会推导出右值引用,只要出现左值引用,就会推导出左值引用。这套规则主要在模板类型匹配和auto中使用。
C++希望坚持“引用就是别名”的原则,并且不允许直接定义引用的引用(还是可以间接实现的),这与指针的指针可以任意级嵌套是不同的。虽然左值引用主要就是靠指针实现,但那其实只是编译器选择的一种实现方案,并不是语法直接规定的。
模板函数实验
我们考虑如下五类的模板函数进行实验,对它们的类型推导可谓是各不相同
1234567891011121314template &l ...
Cpp 进阶笔记——2.移动语义
手动创建将亡值
我们继续前面的函数传参的例子,但是我们做一些修改:调用方提供的不再是一个临时对象,而是一个普通的局部对象
12345678910111213void ProcessBuf(Buffer buf) { for (int i = 0; i < buf.size(); i++) { buf.at(i) = 2 * i; } for (int i = 0; i < buf.size(); i++) { std::cout << buf.at(i) << " "; } std::cout << "\n";}void test2() { Buffer a{5}; a.at(0) = 100; ProcessBuf(a);}
程序运行结果如下(这里无所谓是否关闭优化,因为编译器并不敢进行优化)
12345call constructor // 在te ...
Cpp 进阶笔记——1.右值引用
我们关注现代C++中比较难以理解的概念:右值引用,移动语义,完美转发等,
这些概念都是C++11之后才提出的,目的是进一步压榨程序的运行期效率,避免某些非必要的临时变量的拷贝构造和析构过程。这些语法是完全针对底层实现的,并不是针对于上层的语义优化,不是为了让程序变得更易读的语法糖。
左值和右值 (1)
在C++中,表达式由一个或多个运算对象通过运算符组成,对表达式求值得到一个结果。
字面量和变量是最简单的表达式,它们的结果就是字面量和变量的值。
一个表达式至少具有如下两个属性:
类型:描述计算产生的值的静态类型
值类别:描述值是如何产生的,以及表达式的行为如何被影响
从语法上检查一个表达式能否给另一个表达式赋值,既需要判断类型之间能否进行转换,还需要判断值类别是否满足要求。在本文中我们不讨论类型问题,重点关注表达式的值类别。
在C语言和C++的早期语法中,值类别被简单分为左值和右值。
简单地说,在一个合法的赋值语句中,等号左边的就是左值表达式,等号右边的就是右值表达式。
在赋值过程中,右值表达式不会被改变,而左值表达式会因为赋值而改变。
1lvalue = rvalue;
左值和右 ...