寻找链表环的问题 一、简介 这篇博客主要介绍判断链表是否存在环、寻找环的入口点和计算链表的长度的解决方案,主要是介绍思想,不涉及代码。(因为本萌新的师傅一直教育思想的重要性)
这里主要介绍三种解决方案: ① hash存储 ② 反转指针 ③ 快慢指针
二、hash存储 1、核心思想
只要将遍历过的节点都存储下来,然后在遍历下一个节点的时候,使用下一个节点来和所存储的节点进行比较,如果存在相等的节点,那么就可以证明该链表存在环
2、判断链表是否存在环
因为这里会频繁的进行查找,因此自然而然的想到使用hash来提高查找效率 步骤如下: 首先遍历A节点,将其进行hash运算,运算出的值对哈希表的长度进行取余,假设落在了1,那么就查看这个位置上是否存在元素,若存在就判断是否相等,不存在就将该节点存放在该位置上,依次遍历到F点,应该是如下图 此时再遍历F节点的下一节点C节点,C进行哈希运算后取余肯定还是5,因此在它查找到哈希表中下标为5的地方的时候,发现已经有元素存在,则比较两个元素是否相等(问:为什么还要比较是否相等?答:因为首先即使是不同的对象,它们通过哈希运算算出的值可能也会相等;第二,因为我们还会对哈希表的长度进行取余运算,那么即使是不同的哈希值,在取余后得出的值可能也是相等的)。如果哈希表上已经存在相同的节点,那么就可以确认这个链表存在环
3、寻找环的入口点
通过 2、判断链表是否存在环 已经可以知道,其实在判断到第一个重复节点的时候,该节点就是入口结点
4、计算链表的长度
在遍历链表时,维护一个自增长且初始值为0的Integer对象,在判断到第一个重复节点的时候,该Integer就是此链表的长度
5、小结 时间复杂度O(n)————因为只要遍历完整个链表一次即可(无论是否有环) 空间复杂度O(n)————哈希表会将整个链表存储下来,这个不难理解
① 请问哈希值是怎么算出来的? 这里简单的提一下哈
1 Object类的hashCode.返回对象的内存地址经过处理后的结构,由于每个对象的内存地址都不一样,所以哈希码也不一样。 2 String类的hashCode.根据String类包含的字符串的内容,根据一种特殊算法返回哈希码,只要字符串所在的堆空间相同,返回的哈希码也相同。 3 Integer类,返回的哈希码就是Integer对象里所包含的那个整数的数值,例如Integer i1=new Integer(100),i1.hashCode的值就是100 。由此可见,2个一样大小的Integer对象,返回的哈希码也一样。 ②如果哈希表中已存在元素,但是所存在的元素不等于当前元素,那么当前元素应该放在哪? 答:这是经典的哈希碰撞问题,感兴趣的可以自行百度,这里就简单的介绍一种常用的,就是链地址法(也称拉链法)。简单说来就是,如果那个位置上有元素,那就以将那个元素的尾节点设为当前元素,这样就是以数组+链表的形式来存储我们的元素,像我们常用的HashMap就是这样来解决哈希碰撞的问题
该算法最大的优点:① 理解容易(个人的感觉) ② 由于使用了hash提高了查找速度,因此时间复杂度还是比较低的 缺点:如果链表比较大,那么就需要很大的存储空间 那么有没有不需要存储空间的方案呢?当然有,请耐心的跟随我来看看下面的这两种方案
三、反转指针 1、核心思想 将每一个遍历的节点指向上一次遍历的节点,如果能够回到头节点则链表存在环,否则不存在环(蛤意思?博主第一次看到这句话的时候也是懵X的状态,那么就请看下面的图方便大家理解)
2、判断链表是否存在环
以下图为例 首先A为头节点,在获取A节点的下一节点B节点之后,将A的下一节点指向Null。如图 然后继续,在获取B节点的下一节点C节点之后,将B的下一节点指向A。如图 按照这种规则遍历到E节点,在获取E节点的下一节点C节点之后,将E的下一节点指向D。如图 这里是重点 这里是重点 这里是重点 这个时候因为反转的原因,C节点的下一节点只指向B。那么继续遍历和反转,如图 再遍历和反转,如图 这样就遍历回头节点了,仔细想想,如果一个链表不存在环的话,它会回到头节点吗?答案肯定是否定的,没有环的链表只会单纯的被反转,然后尾节点变头节点而已
再来观察反转后的有环链表
是不是发现环的顺序被反转了?挺有意思的对吧。那么应该怎么还原呢? 相信聪明的小伙伴已经能想到了,再遍历一次即可(让我想起没有什么是一颗猴赛雷搞不定的。如果有,那就两颗)
3、寻找环的入口点 这种方式寻找入口结点就没那么容易了,如果一定要用这种方式来查找的话,博主只能用一种比较生硬的方式来寻找
那就是在最开始的时候克隆链表,只反转链表的副本。如果存在环,则同时遍历链表和链表副本,遍历的时候一直比较两个链表的下一节点是否相等,只要不相等,则可说明当前节点是入口结点 (问:为什么这样可以找到入口结点?答:因为仔细在反转链表的时候我们就知道,如果链表存在环的话,那么链表的环是会被反转的。因此这个时候遍历原链表和链表副本(环被反转的原链表)时,在到达入口结点时,原链表的入口节点指向的是原来环的第二个结点,而链表副本(环被反转的原链表)的入口节点指向的是原来环的最后一个节点(因为被环被反转了))
4、计算链表的长度 既然找到入口节点,那么求得链表的长度也不是什么难事。只要比较原链表和链表副本的时候,在原链表中加入一个自增的Integer,并且在判断到入口节点的时候,原链表再遍历一次环即可,该Integer就是链表的长度。
很多时候,我们制作研究区图,想要一种效果是:标注研究区在市的位置、市在省的位置、省在全国的位置,并将这三张图放一张图里。PS的方法,可以说是曲线救国吧,但最好还是用ArcGIS图框的方法来解决,避免返工不方便。老阿姨好久不制图了,快全忘干净了,重新捡起来捡起来……另外:这是一个无图说明文档哈哈哈哈哈哈!
具体操作方法:
(1)打开ArcGIS,新建空白地图文档。
(2)菜单栏的Insert选项卡——Data Frame。根据自己需要制作的地图幅数,插入Data Frame。
(3)我随机,插入两个Data Frame。然后切换数据视图到布局视图。可以看到一张出图纸上,有两个框子,一大一小。其实这里是三个框子:1.Layer框;2.New Data Frame框;3.New Data Frame2框。因为插入的Data Frame大小是默认的,所以两个Data Frame框乍一开始是重叠着的,手动可以挪开,避免重叠着乱乱看不清楚。
(4)插入数据框以后,就要开始拖入数据或添加数据开始制图了。这时候,想在哪个数据框里添加数据,就要先在布局视图单击选中一下这个框。同时,可同步在Table Of Contents中查看当前激活的是哪个数据框。
(5)然后,你就愉快的制图吧。总结陈词:插框、选中、添数据、分别调整渲染效果。
STM32F1xx官方资料:
《STM32中文参考手册V10》-第25章通用同步异步收发器(USART)
通信接口背景知识 设备之间通信的方式 一般情况下,设备之间的通信方式可以分成并行通信和串行通信两种。它们的区别是:
并、串行通信的区别 并行通信串行通信传输原理数据各个位同时传输数据按位顺序传输优点速度快占用引脚资源少缺点占用引脚资源多速度相对较慢 串行通信的分类 1、按照数据传送方向,分为:
单工:数据传输只支持数据在一个方向上传输;半双工:允许数据在两个方向上传输。但是,在某一时刻,只允许数据在一个方向上传输,它实际上是一种切换方向的单工通信;它不需要独立的接收端和发送端,两者可以合并一起使用一个端口。全双工:允许数据同时在两个方向上传输。因此,全双工通信是两个单工通信方式的结合,需要独立的接收端和发送端。 2、按照通信方式,分为:
同步通信:带时钟同步信号传输。比如:SPI,IIC通信接口。异步通信:不带时钟同步信号。比如:UART(通用异步收发器),单总线。 在同步通讯中,收发设备上方会使用一根信号线传输信号,在时钟信号的驱动下双方进行协调,同步数据。例如,通讯中通常双方会统一规定在时钟信号的上升沿或者下降沿对数据线进行采样。
在异步通讯中不使用时钟信号进行数据同步,它们直接在数据信号中穿插一些用于同步的信号位,或者将主题数据进行打包,以数据帧的格式传输数据。通讯中还需要双方规约好数据的传输速率(也就是波特率)等,以便更好地同步。常用的波特率有4800bps、9600bps、115200bps等。
在同步通讯中,数据信号所传输的内容绝大部分是有效数据,而异步通讯中会则会包含数据帧的各种标识符,所以同步通讯效率高,但是同步通讯双方的时钟允许误差小,稍稍时钟出错就可能导致数据错乱,异步通讯双方的时钟允许误差较大。
常见的串行通信接口 常见的串行通信接口 通信标准引脚说明通信方式通信方向 UART
(通用异步收发器)
TXD:发送端
RXT:接收端
GND:共地
异步通信全双工 1-wire
(单总线)
DQ:发送/接收端异步通信半双工SPI SCK:同步时钟
MISO:主机输入,从机输出
MOSI:主机输出,从机输入
同步通信全双工I2C SCK:同步时钟
SDA:数据输入/输出端
同步通信半双工 STM32串口通信基础 STM32的串口通信接口有两种,分别是:UART(通用异步收发器)、USART(通用同步异步收发器)。而对于大容量STM32F10x系列芯片,分别有3个USART和2个UART。
UART引脚连接方法 RXD:数据输入引脚,数据接受;TXD:数据发送引脚,数据发送。 对于两个芯片之间的连接,两个芯片GND共地,同时TXD和RXD交叉连接。这里的交叉连接的意思就是,芯片1的RxD连接芯片2的TXD,芯片2的RXD连接芯片1的TXD。这样,两个芯片之间就可以进行TTL电平通信了。
若是芯片与PC机(或上位机)相连,除了共地之外,就不能这样直接交叉连接了。尽管PC机和芯片都有TXD和RXD引脚,但是通常PC机(或上位机)通常使用的都是RS232接口(通常为DB9封装),因此不能直接交叉连接。RS232接口是9针(或引脚),通常是TxD和RxD经过电平转换得到的。故,要想使得芯片与PC机的RS232接口直接通信,需要也将芯片的输入输出端口也电平转换成rs232类型,再交叉连接。
经过电平转换后,芯片串口和rs232的电平标准是不一样的:
单片机的电平标准(TTL电平):+5V表示1,0V表示0;Rs232的电平标准:+15/+13 V表示0,-15/-13表示1。 RS-232通讯协议标准串口的设备间通讯结构图如下: 所以单片机串口与PC串口通信就应该遵循下面的连接方式:在单片机串口与上位机给出的rs232口之间,通过电平转换电路(如下面图中的Max232芯片) 实现TTL电平与RS232电平之间的转换。
具体要了解RS232串口的,可以查看链接RS232串口简介。
STM32的UART特点 全双工异步通信;分数波特率发生器系统,提供精确的波特率。发送和接受共用的可编程波特率,最高可达4.5Mbits/s;可编程的数据字长度(8位或者9位);可配置的停止位(支持1或者2位停止位);可配置的使用DMA多缓冲器通信;单独的发送器和接收器使能位;检测标志:① 接受缓冲器 ②发送缓冲器空 ③传输结束标志;多个带标志的中断源,触发中断;其他:校验控制,四个错误检测标志。 串口通信过程 STM32中UART参数 串口通讯的数据包由发送设备通过自身的TXD接口传输到接收设备的RXD接口,通讯双方的数据包格式要规约一致才能正常收发数据。STM32中串口异步通信需要定义的参数:起始位、数据位(8位或者9位)、奇偶校验位(第9位)、停止位(1,15,2位)、波特率设置。
UART串口通信的数据包以帧为单位,常用的帧结构为:1位起始位+8位数据位+1位奇偶校验位(可选)+1位停止位。如下图所示:
奇偶校验位分为奇校验和偶校验两种,是一种简单的数据误码校验方法。奇校验是指每帧数据中,包括数据位和奇偶校验位的全部9个位中1的个数必须为奇数;偶校验是指每帧数据中,包括数据位和奇偶校验位的全部9个位中1的个数必须为偶数。
校验方法除了奇校验(odd)、偶校验(even)之外,还可以有:0 校验(space)、1 校验(mark)以及无校验(noparity)。 0/1校验:不管有效数据中的内容是什么,校验位总为0或者1。
UART(USART)框图 这个框图分成上、中、下三个部分。本文大概地讲述一下各个部分的内容,具体的可以看《STM32中文参考手册》中的描述。
框图的上部分,数据从RX进入到接收移位寄存器,后进入到接收数据寄存器,最终供CPU或者DMA来进行读取;数据从CPU或者DMA传递过来,进入发送数据寄存器,后进入发送移位寄存器,最终通过TX发送出去。
然而,UART的发送和接收都需要波特率来进行控制的,波特率是怎样控制的呢?
这就到了框图的下部分,在接收移位寄存器、发送移位寄存器都还有一个进入的箭头,分别连接到接收器控制、发送器控制。而这两者连接的又是接收器时钟、发送器时钟。也就是说,异步通信尽管没有时钟同步信号,但是在串口内部,是提供了时钟信号来进行控制的。而接收器时钟和发送器时钟有是由什么控制的呢?
可以看到,接收器时钟和发送器时钟又被连接到同一个控制单元,也就是说它们共用一个波特率发生器。同时也可以看到接收器时钟(发生器时钟)的计算方法、USRRTDIV的计算方法。
这里需要知道一个知识点:
UART1的时钟:PCLK2(高速);UART2、UART3、UART4的时钟:PCLK1(低速)。 框图的中部分,涉及到UART(USART)的中断控制部分,在后面的文章中会具体介绍到。
一、在IDEA中设置程序的运行参数 Run -> Edit Configuration -XX:+PrintGCDetails -Xms30M -Xmx30M -Xmn10M -XX:SurvivorRatio=8 参数含义分别是:
打印GC日志
最小堆内存
最大堆内存
堆中新生代内存
新生代内存中Eden和Survivor大小之比,如果为8表示Eden占80%,另外两个Survivor各占10%
二、运行程序 package memory.gc; /** * Created by Administrator on 2018-04-11. */ public class GCLogTest { public static void main(String[] args) { System.out.println(Runtime.getRuntime().maxMemory()); System.out.println(Runtime.getRuntime().totalMemory()); Object obj = new Object(); obj = null; System.gc(); } } 程序通过System.gc()使JVM进行了一次Full GC
看到输出的日志如下
30408704 30408704 [Full GC (System.gc()) [TenuredDisconnected from the target VM, address: '127.0.0.1:55874', transport: 'socket' : 0K->528K(20480K), 0.
nginx1.9之后直接使用Stream配置就可以了,当然需要先安装stream模块
1.nginx 增加tcp ./configure --with-stream --with-pcre=../pcre-8.38 ./configure --with-stream --without-http_rewrite_module 2.配置nginx.conf http { …… } stream { upstream sftp{ hash $remote_addr consistent; server 172.0.0.1:22 max_fails=3 fail_timeout=30s; } server { listen 8080; proxy_connect_timeout 1s; proxy_timeout 30s; proxy_pass sftp; } } 资料: https://www.cnblogs.com/tinywan/p/6965467.html https://zhangge.net/5037.html https://blog.csdn.net/errizh/article/details/77936422
两单向链表相交问题 一、问题分析 (1)两个链表相交,那么两个链表中的节点一定有相同地址。
(2)两个链表相交,那么两个链表从相交节点开始到尾节点一定都是相同的节点。 (问:为什么? 答:因为每一个节点最多只能有一个下一节点,因此在相交节点之后,链表不可能再分为两个链表)
二、问题解法 根据两个链表是否存在环来分类讨论
1、无环 无环的情况有两种比较快速的解决方式,这两种方式本质上都是基于 一、问题分析 中的第二要素 ① 制造环法
如果两链表相交,只会有上面这种情况(两链表合为一个链表),如果还有其他的情况,请拍砖
那么何为制造环法呢,依然看图 首先遍历链表A,遍历到A的尾节点时,将A的尾节点的下一节点设置为链表B的头结点。这样就会出现两种情况: 无环:(分析)因为两链表不存在交点,将A的尾节点的下一节点设置为链表B的头结点后,这两个链表就成为了一个无环链表 有环:(分析)因为两链表存在交点,因此在将A的尾节点的下一节点设置为链表B的头结点后,从相交点开始,原来的链表B就构成了一个环(本质:如果两链表存在交点,则尾结点一定相同。因此链表A的尾结点也就是链表B的尾结点,将链表A尾结点的下一节点设置为链表B的头结点就等价于将链表B的尾结点的下一节点设置为链表B的头结点,故一定会构成环)
因此我们可以先将链表A的尾节点的下一节点设置为链表B的头节点。如果存在环,则AB链表存在交点;否则就是两条互不相干的链表(如何判断链表是否存在环,请参考我另外一篇博客。这篇只分析链表相交问题)
那么问题来了,如何寻找相交点?其实很简单,仔细看看上图就很容易发现,这个环的入口结点就是两链表的相交点 ② 比较尾节点法 相比上种方法,这种方法简直就是一点就通(之所以没放在第一个来讲是担心你们看了后就不认真看第二个,别打我~)
还是这张图,还是基于 一、问题分析 中的第二要素。 聪明的人肯定已经知道我接下来要说什么了,那么帅气的人就仔细听好
直接比较AB链表的尾结点是否相等即可 直接比较AB链表的尾结点是否相等即可 直接比较AB链表的尾结点是否相等即可
相等则表示有交点,不相等则表示没有交点。
那么问题又来了,这种方式又应该怎么寻找相交节点呢? 先遍历链表A得出链表A的长度S1 在遍历链表B得出链表B的长度S2 比较,选择长的那个链表(这里假设是链表A长)
先让链表A走S1-S2个节点(每次走一个节点,在链表B开始走之后也接着走);然后链表B也开始走,链表B每遍历一个节点都和链表A当前的结点比较。第一个相等的节点就是交点
2、有环 有环的话一般是两个链表都存在环 因为如果一个链表存在环而另外一个链表不存在环那么这两个链表肯定不存在交点(问:为什么?答:自己画图感受一下就会意识到这个问题有多么的愚蠢,当然如果你真的证明了存在这种情况。那么恭喜你肯定会在学术界引起轰动 )
而且如果两个链表都有环,如果它们有交点的话。那么它们一定共用一个环。如图下 两个链表一定是在环的某个地方进入这个环,如果还有其他情况,欢迎拍砖(博主头铁2333)
现在,我们可以采用快慢指针来判断两个有环的链表是否存在交点。因为这个环是两个链表共用的,所以只要两个链表使用快慢指针,就一定会发生指针碰撞。
何为快慢指针,这里简单的提及一下。就是放两个指针,一个指针一次走两个节点(也可以走3、4甚至N个),一个节点一次走一个节点。这样只要存在环,那么两个节点就一定会相遇(其实一开始我也怀疑会不会走得快的那个节点会不好刚好跳过走得慢的那个节点,不过仔细画画图即可知道,一定会相遇。就像博尔特和宋小宝在一个环里面跑步,他们一定就相遇多次;反之,如果不存在环,则他们永远也不会相遇)
在链表A中放快指针,在链表B中放慢指针(反之也可以),然后每次遍历都判断两节点是否相等,只要相等就一定存在交点
那么问题又来了?如何寻找相交点? 这个问题博主还在思考,如果入口点不同的话,那应该是不存在交点吧….
欢迎拍砖和参与讨论~
检查网络连通性 ping: 可以测试到目标机器的连通性或者网络连接速度,Ping域名还可以得出解析IP;telnet: 用于远程管理连接主机。同时也是测试目标机器的TCP端口是否开放;curl: 可以测试连接主机和访问URL。 注:windows 的 telnet大多关闭的。 可在控制面板——>程序——>打开或关闭Windows功能 下面开启。
最近两天尝试编译Mission Planner,结果遇到了和官方教程不一样的地方,参考了几篇博客,内容都比较久远了还大多雷同,经过摸索,浪费了将近两天的时间,总算编译通过了。 原官方教程链接为:http://ardupilot.org/dev/docs/buildin-mission-planner.html Mission Planner源码地址为:https://github.com/ArduPilot/MissionPlanner 最新版Mission Planner上位机软件下载链接为:http://firmware.ardupilot.org/Tools/MissionPlanner/MissionPlanner-latest.msi 1、安装visual studio 2017(官方教程要求15.3以上,我编译时的环境为15.6.5),具体操作可以参考原官方教程(其实vs2107打开工程的时候会自动扫描,如果缺少组件再自动安装也可以) 2、下载Mission Planner源码到本地 3、下载最新版的Mission Planner上位机并安装(注意此版本不要与源代码版本差别过大,源代码1.50之前使用的是vs2013编译,只用到了.NET4.0,源代码1.50及以后的版本同时用到了.NET4.0(及以上)和.NETStandard2.0(这也是坑人之处)) 4、找到源代码文件夹,使用vs2017打开MissionPlanner.sln(如图) 等工程加载完毕,在解决方案视图中会有很多项目,有些项目的依赖性会有黄色三角,如下图所示 初次加载大部分项目都会有这个,但是其实只有一个名为MissionPlanner.Utilities的项目会在编译时报错,其他的都只会产生warning,并不影响运行,可以先不管。 5、重点找到 MissionPlanner.Utilities项目,可以先编译一遍,会发现在.NETStandard2.0框架下无法加载System.Speech,进而连续报错,导致编译失败 解决办法是:先找到该项目依赖项中的System.Speech,右键将其移除(不移除后续无法添加同名dll) 然后右键依赖项,选择添加引用,选择浏览,找到用户文件夹下的.negut\packages\system.speech.dll\1.xx\lib\dnxcore50\lib\System.Speech.dll,选择添加 然后找到安装的Mission Planner上位机路径下的System.Speech.dll,同样添加进来。 按添加顺序同时勾选上点确定 (注意顺序!!!).negut文件夹下对应的是.NET4.x的dll,上位机软件下的.dll包含.NETStandard2.0,由于vs2017默认先添加到.NET4.x,所以顺序错了依然会编译出错(我实验的情况就是如此,感觉很奇葩。。。) 然后再次编译 MissionPlanner.Utilities项目发现就可以通过了,再去编译MissionPlanner项目就可以顺利通过并允许。
远心镜头相对于普通镜头来说,具有放大倍数恒定,不会随着景深变化而变化,无视差等优点。下图是用远心镜头与普通镜头拍摄工件孔径来做对比实验所得效果。
图1用普通镜头拍出来的图像。由于普通镜头存在的视觉,聚焦误差、孔径内壁易产生阴影,对于提取内孔边缘造成影响,数据不准确,精度不高。
图2用远心镜头拍摄的图像。远心镜头特有的平行光特性,确保孔径测量不会产生阴影,轮廓清晰、数据准确,不需要对图像做过多校正。
远心镜头适合检测有厚度孔径,对边缘提取要求高的测量应用、尺寸定位行业。
从前面的提升树,到 GBDT G B D T ,再到 RF R F ,我们可以发现在集成学习中,基分类器选择决策树往往能有很不错的效果,这是因为它们通常具有较低的偏差和较高的方差(分类误差小,但容易过拟合),这样的特性使其在平均过程中更有利。这一篇我们就来了解一下随机森林这个算法的方法。 随机森林( RandomForest R a n d o m F o r e s t ),是在以决策树为基分类器构建 Bagging B a g g i n g 集成的基础上进一步在 cart c a r t 决策树的训练过程引入了随机属性选择。关于随机森林这一算法,书上对其的描述都比较少,因此去看了一些论文和文章。
【算法思想】 总的来看,其实就是用 bootstrap b o o t s t r a p 自助采样得到的 T T 个数据集,以分类决策树作为基分类器进行学习,得到TT棵分类决策树,用投票法的方式将它们结合起来变为森林(将测试样本输入,每棵决策树会给出相应的分类,森林的最终分类,选择这些分类中出现最多的类别作为输出)。 随机体现在哪? 那么,随机森林的“随机”是体现在哪呢?其实就是体现在,对自助采样得到的数据集学习分类器这一学习过程中。 回忆前面的决策树生成算法,我们通常会根据每个节点上的所有特征,选择最优划分特征来进行划分节点。而在随机森林的每棵决策树生成中,我们对最优划分特征的选取集合并不是每个节点上的所有特征,而是会通过对所有特征这一集合随机选取一个子集来作为我们的选取范围,然后再在这个子集集合内选择最优划分特征。
算法过程: 输入:原始训练数据集 D D (mm个样本),特征集 A A (有KK个特征),参数 k k 输出:最终分类器(随机森林)
STM32F1xx官方资料:
《STM32中文参考手册V10》-第8章通用和复用功能IO(GPIO和AFIO )
芯片数据手册(datasheet)
STM32的GPIO介绍 STM32引脚说明 GPIO是通用输入/输出端口的简称,是STM32可控制的引脚。GPIO的引脚与外部硬件设备连接,可实现与外部通讯、控制外部硬件或者采集外部硬件数据的功能。
STM32F103ZET6芯片为144脚芯片,包括7个通用目的的输入/输出口(GPIO)组,分别为GPIOA、GPIOB、GPIOC、GPIOD、GPIOE、GPIOF、GPIOG,同时每组GPIO口组有16个GPIO口。通常简略称为PAx、PBx、PCx、PDx、PEx、PFx、PGx,其中x为0-15。
STM32的大部分引脚除了当GPIO使用之外,还可以复用位外设功能引脚(比如串口),这部分在【STM32】STM32端口复用和重映射(AFIO辅助功能时钟) 中有详细的介绍。
GPIO基本结构 每个GPIO内部都有这样的一个电路结构,这个结构在本文下面会具体介绍。
这边的电路图稍微提一下:
保护二极管:IO引脚上下两边两个二极管用于防止引脚外部过高、过低的电压输入。当引脚电压高于VDD时,上方的二极管导通;当引脚电压低于VSS时,下方的二极管导通,防止不正常电压引入芯片导致芯片烧毁。但是尽管如此,还是不能直接外接大功率器件,须加大功率及隔离电路驱动,防止烧坏芯片或者外接器件无法正常工作。P-MOS管和N-MOS管:由P-MOS管和N-MOS管组成的单元电路使得GPIO具有“推挽输出”和“开漏输出”的模式。这里的电路会在下面很详细地分析到。TTL肖特基触发器:信号经过触发器后,模拟信号转化为0和1的数字信号。但是,当GPIO引脚作为ADC采集电压的输入通道时,用其“模拟输入”功能,此时信号不再经过触发器进行TTL电平转换。ADC外设要采集到的原始的模拟信号。 这里需要注意的是,在查看《STM32中文参考手册V10》中的GPIO的表格时,会看到有“FT”一列,这代表着这个GPIO口时兼容3.3V和5V的;如果没有标注“FT”,就代表着不兼容5V。
STM32的GPIO工作方式 GPIO支持4种输入模式(浮空输入、上拉输入、下拉输入、模拟输入)和4种输出模式(开漏输出、开漏复用输出、推挽输出、推挽复用输出)。同时,GPIO还支持三种最大翻转速度(2MHz、10MHz、50MHz)。
每个I/O口可以自由编程,但I/O口寄存器必须按32位字被访问。
GPIO_Mode_AIN 模拟输入GPIO_Mode_IN_FLOATING 浮空输入GPIO_Mode_IPD 下拉输入GPIO_Mode_IPU 上拉输入GPIO_Mode_Out_OD 开漏输出GPIO_Mode_Out_PP 推挽输出GPIO_Mode_AF_OD 复用开漏输出GPIO_Mode_AF_PP 复用推挽输出 下面将具体介绍GPIO的这八种工作方式:
浮空输入模式 浮空输入模式下,I/O端口的电平信号直接进入输入数据寄存器。也就是说,I/O的电平状态是不确定的,完全由外部输入决定;如果在该引脚悬空(在无信号输入)的情况下,读取该端口的电平是不确定的。
上拉输入模式 上拉输入模式下,I/O端口的电平信号直接进入输入数据寄存器。但是在I/O端口悬空(在无信号输入)的情况下,输入端的电平可以保持在高电平;并且在I/O端口输入为低电平的时候,输入端的电平也还是低电平。
下拉输入模式 下拉输入模式下,I/O端口的电平信号直接进入输入数据寄存器。但是在I/O端口悬空(在无信号输入)的情况下,输入端的电平可以保持在低电平;并且在I/O端口输入为高电平的时候,输入端的电平也还是高电平。
模拟输入模式 模拟输入模式下,I/O端口的模拟信号(电压信号,而非电平信号)直接模拟输入到片上外设模块,比如ADC模块等等。
开漏输出模式 开漏输出模式下,通过设置位设置/清除寄存器或者输出数据寄存器的值,途经N-MOS管,最终输出到I/O端口。这里要注意N-MOS管,当设置输出的值为高电平的时候,N-MOS管处于关闭状态,此时I/O端口的电平就不会由输出的高低电平决定,而是由I/O端口外部的上拉或者下拉决定;当设置输出的值为低电平的时候,N-MOS管处于开启状态,此时I/O端口的电平就是低电平。同时,I/O端口的电平也可以通过输入电路进行读取;注意,I/O端口的电平不一定是输出的电平。
开漏复用输出模式 开漏复用输出模式,与开漏输出模式很是类似。只是输出的高低电平的来源,不是让CPU直接写输出数据寄存器,取而代之利用片上外设模块的复用功能输出来决定的。
推挽输出模式 推挽输出模式下,通过设置位设置/清除寄存器或者输出数据寄存器的值,途经P-MOS管和N-MOS管,最终输出到I/O端口。这里要注意P-MOS管和N-MOS管,当设置输出的值为高电平的时候,P-MOS管处于开启状态,N-MOS管处于关闭状态,此时I/O端口的电平就由P-MOS管决定:高电平;当设置输出的值为低电平的时候,P-MOS管处于关闭状态,N-MOS管处于开启状态,此时I/O端口的电平就由N-MOS管决定:低电平。同时,I/O端口的电平也可以通过输入电路进行读取;注意,此时I/O端口的电平一定是输出的电平。
推挽复用输出模式 推挽复用输出模式,与推挽输出模式很是类似。只是输出的高低电平的来源,不是让CPU直接写输出数据寄存器,取而代之利用片上外设模块的复用功能输出来决定的。
总结与分析 1、什么是推挽结构和推挽电路?
推挽结构一般是指两个参数相同的三极管或MOS管分别受两互补信号的控制,总是在一个三极管或MOS管导通的时候另一个截止。高低电平由输出电平决定。
推挽电路是两个参数相同的三极管或MOSFET,以推挽方式存在于电路中,各负责正负半周的波形放大任务。电路工作时,两只对称的功率开关管每次只有一个导通,所以导通损耗小、效率高。输出既可以向负载灌电流,也可以从负载抽取电流。推拉式输出级既提高电路的负载能力,又提高开关速度。
2、开漏输出和推挽输出的区别?
开漏输出:只可以输出强低电平,高电平得靠外部电阻拉高。输出端相当于三极管的集电极。适合于做电流型的驱动,其吸收电流的能力相对强(一般20ma以内);推挽输出:可以输出强高、低电平,连接数字器件。 关于推挽输出和开漏输出,最后用一幅最简单的图形来概括:
该图中左边的便是推挽输出模式,其中比较器输出高电平时下面的PNP三极管截止,而上面NPN三极管导通,输出电平VS+;当比较器输出低电平时则恰恰相反,PNP三极管导通,输出和地相连,为低电平。右边的则可以理解为开漏输出形式,需要接上拉。
3、在STM32中选用怎样选择I/O模式?
浮空输入_IN_FLOATING ——浮空输入,可以做KEY识别,RX1带上拉输入_IPU——IO内部上拉电阻输入带下拉输入_IPD—— IO内部下拉电阻输入模拟输入_AIN ——应用ADC模拟输入,或者低功耗下省电开漏输出_OUT_OD ——IO输出0接GND,IO输出1,悬空,需要外接上拉电阻,才能实现输出高电平。当输出为1时,IO口的状态由上拉电阻拉高电平,但由于是开漏输出模式,这样IO口也就可以由外部电路改变为低电平或不变。可以读IO输入电平变化,实现C51的IO双向功能推挽输出_OUT_PP ——IO输出0-接GND, IO输出1 -接VCC,读输入值是未知的复用功能的推挽输出_AF_PP ——片内外设功能(I2C的SCL、SDA)复用功能的开漏输出_AF_OD——片内外设功能(TX1、MOSI、MISO.SCK.SS)
基本方法 import os import shutil alllist=os.listdir(u"D:\\notes\\python\\资料\\") for i in alllist: aa,bb=i.split(".") if 'python' in aa.lower(): oldname= u"D:\\notes\\python\\资料\\"+aa+"."+bb newname=u"d:\\copy\\newname"+aa+"."+bb shutil.copyfile(oldname,newname) 比较全面的方法
#coding:utf-8 import os import sys import getpass import shutil# shutil.copyfile("oldfile","newfile") oldfile和newfile都只能是文件# 创建多级目录:os.makedirs("/Users/ximi/version")# 创建单个目录:os.mkdir("project")# #复制文件# shutil.copyfile('listfile.py', 'd:/test.py')# shutil.rmtree("dir") 空目录、有内容的目录都可以删# 检验给出的路径是否真地存:os.path.exists()# getpass.getuser()该函数返回登陆的用户名,不需要参数username = getpass.getuser()# 改变当前工作目录os.chdir('/Users/' + username + '/Documents/client/myProj/')# shutil.copyfile("oldfile","newfile") oldfile和newfile都只能是文件# 创建多级目录:os.makedirs("/Users/ximi/version")# 创建单个目录:os.mkdir("project")# #复制文件# shutil.copyfile('listfile.py', 'd:/test.py')# shutil.rmtree("dir") 空目录、有内容的目录都可以删# 检验给出的路径是否真地存:os.path.exists()# getpass.getuser()该函数返回登陆的用户名,不需要参数username = getpass.getuser()# 改变当前工作目录os.chdir('/Users/' + username + '/Documents/client/myProj/') 文件的拷贝用shutil.copyfile(srcFilePath,dstFilePath)
def handleVersionFile(): # os.
MATLAB如何画三轴图 前言 使用MATLAB绘图非常方便,它提供了非常丰富的图形,如:line,bar,stem等,用户可以直接调用相应的函数,但有时直接使用这些“高级”的函数不能满足我们的绘图要求,比如,如何绘制三Y轴的图形?,即一个figure中有一个X轴,三个Y轴,分别对应三个数据曲线(line或bar等),比如下图:
绘制这些图的技巧就是学会操纵对象句柄,掌握了方法之后可以非常灵活的绘制各种你想要的图形。
下面我以第一幅图像为例,介绍它的画法。
目录 文章目录 MATLAB如何画三轴图前言目录1. 预备知识2. 创建数据,并建一个figure3. 画第一个bar4. 画第二个线5. 画第三个线图6. 加label7. 封装成函数8. 常用绘图对象属性表1 Axes常用的属性2 Line的常用的属性3 text对象的属性4 bar对象属性5 control legend6 对象通用属性 1. 预备知识 MATLAB绘图实际上是在创建一些资源对象,这里的对象包括:图(figure)、轴(axes)、线(line)、柱状图(bar)以及其他标注对象(如文字(text)、图例(legend)等)等。这些对象各自都与唯一的一个句柄(handle)想关联。对象创建之后,通过 get(handle, ‘property name’) 获取对象指定的属性值,通过set(handle, ‘property name’, ‘property value’) 设置属性值。它们之间有一定的所属关系,如下图
2. 创建数据,并建一个figure % 第一个bar的数据 x1=0:.5:10; y1=sin(x1); % 第二个line的数据 x2=0:.1:10; y2=log(x2); % 第三个line的数据 x3=x2; y3 = tan(x3); figure; 3. 画第一个bar % 建第一个axes ha(1) = axes('ycolor','b','yminortick','on','xminortick','off'); hold on; % 保持以上属性,因为下面的bar有自动调整axes属性的作用 h(1) = bar(x1, y1,'parent',ha(1),'facecolor','b'); % 画第一个bar图 xlim1 = get(ha(1),'xlim'); % 获取第一个axes的x轴的范围,这个值很关键 得到如下图:
>>> import numpy as np >>> a = np.random.randint(-5, 5, (5, 5)) >>> a array([[-4, -4, -5, 2, 1], [-1, -2, -1, 3, 3], [-1, -2, 3, -5, 3], [ 0, -3, -5, 1, -4], [ 0, 3, 1, 3, -4]]) # 方式一 >>> np.maximum(a, 0) array([[0, 0, 0, 2, 1], [0, 0, 0, 3, 3], [0, 0, 3, 0, 3], [0, 0, 0, 1, 0], [0, 3, 1, 3, 0]]) # 方式二 >>> (a + abs(a)) / 2 array([[0, 0, 0, 2, 1], [0, 0, 0, 3, 3], [0, 0, 3, 0, 3], [0, 0, 0, 1, 0], [0, 3, 1, 3, 0]]) # 方式三 >>> b = a.
原文传送
要点:
1. 服务器端的入站规则需要开启TCP 21
2. 客户端修改成主动传输模式
接口规范 最新公司新的项目,使用spring boot,cloud,服务之间使用rest api进行调用,所有使用了restful 风格的接口
@RequestMapping(value = "/getByRegionId/{regionId}", method = RequestMethod.GET) @ResponseBody public ObjectRestResponse<List<RegionsDTO>> getByRegionId(@PathVariable("regionId") String regionId) {} @RequestMapping(value = "/{id}/menu", method = RequestMethod.POST) @ResponseBody public ObjectRestResponse modifyMenuAuthority(@PathVariable String id) {} restful 风格接口的利弊 利:接口名称相同,请求method,通过RequestMethod.GET/POST/PUT/DELETE来区别,就可以实现增删改查 弊:前端传参不方便,如http://www.xxx.com/getByRegionId/x232323,在请求地址中拼接,如果regionId为空,就会出错.
其他方式: 如http://www.xxx.com/getByRegionId ,通过表单参数POST,或GET地址栏参数传regionId,如
http://www.xxx.com/getByRegionId?id=x232323 规范 HTTP 协议是不区分大小写的,所有不需要使用驼峰式 http://www.xxx.com/getbyregionId?id=x232323 单词要使用英文来命名,不要拼音英文混合,不要英文简写,除非这个简写大家都认识 同一名称不同人名称要相同 名称可以长一些,单不要有歧义
烽火的笔试题记不得了,就不说了,就说一下面试感受。
到南京烽火大厦后先在那等了一会,之后被叫去第一面。一进去看到一个女的面试官把我就搞蒙了,不知道这是人事面还是专业面。因为面软件开发的一般第一面是技术面,第二面才会是人事面,但技术面怎么是个女的,一般女的都是人事面。我也不清楚,就当它是技术面来自我介绍,自我介绍完我把我的代码集给她看,她大概看了一下,什么也没说,就问我你喜欢那门课,我随便回答一下,她再问你觉得你性格如何,我也如实回答。她就说你还有什么问题嘛,把我吓了一跳,这不是面试结束的信号嘛,这就完啦?我就说我没问题,就出来了。hr叫我在外面等结果,我感觉是gg了,因为才面不到5分钟。
等了一会,有个hr就叫我们一起等的几个过去进行下一面,我整个人都是蒙的,我问了其他的同学他们都面了很久,有的还现场编程。等了一会,叫我们几个进去开始第二面,我才发现第二面居然是群面,我当时就觉得很好玩。先编号1到5号,在举手自我介绍,之后是他说一个问题,我们举手回答。先说一下问题第一个是你对指针有什么了解,之后就是一个问题引出下一个问题,从指针到引用到函数的参数传递到堆和栈等等。说一下我的做法,自我介绍我是第二个举手的,其他问题我都是第一个举手的,因为我认为问题的答案可能有很多但我们知道的可能都差不多,所以你一定要第一个说这样,别人说的内容就变少了。还有就是你一定的把气势拿出来,因为群面可能是几个中挑一个所以你一定要比别人表现好,就算你不是很强但你比其他几个都强,那面试官就会认为你很优秀。所以我就把袖子一撸,把包里的水那出来,回答完一个问题就喝一口水。这样就表现的你很强。
之后晚上hr就打电话给我说我过了,因为一些很sb的个人原因最后没有去烽火,但这次的群面也让我收获很多。
背景 本文并不介绍服务发现的基本原理。除了一致性算法之外,其他并没有太多高深的算法,网上的资料很容易让大家明白上面是服务发现。
想直接查看结论的同学,请直接跳到文末。
目前,市面上有非常多的服务发现工具,《Open-Source Service Discovery》(http://jasonwilder.com/blog/2014/02/04/service-discovery-in-the-cloud/)一文中列举了如下开源的服务发现工具。
NameTypeAP or CPLanguageDependenciesIntegrationZookeeperGeneralCPJavaJVMClient BindingDoozerGeneralCPGo
Client BindingEtcdGeneralMixed (1)Go
Client Binding/HTTPSmartStackDedicatedAPRubyhaproxy/ZookeeperSidekick (nerve/synapse)EurekaDedicatedAPJavaJVMJava ClientNSQ (lookupd)DedicatedAPGo
Client BindingSerfDedicatedAPGo
Local CLISpotify (DNS)DedicatedAPN/ABindDNS LibrarySkyDNSDedicatedMixed (2)Go
HTTP/DNS Library (1) If using the consistent parameter, inconsistent reads are possible
(2) If using a caching DNS client in front of SkyDNS, reads could be inconsistent
上面表格中,前三个是通用的,后面都是各大公司自己造的轮子,应用范围并不广,我也就不深入研究了。
此外,这篇文章是14年写的,当时它并没有研究Consul,放到表格中,Consul则应该是General、CP、Go、No dependency、Http/DNS Library。
截止到今天,除了容器编排框架k8s、istio/envoy自己实现了服务发现机制(他们也兼容第三方的服务发现工具),似乎也没有其他的知名的服务发现框架出现了。
下面我就zookeeper、etcd、consul这三款进行下比较。
比较 ZooKeeper ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services.
在网上投了天朔的简历,过了一久才通知去面试。一到公司就拿了一张试卷给我做,搞笑的是有一个同学来也拿给他做,快做了一小时,问他是面软件开发的嘛,他说不是,hr说“那你不早说,其他的不用笔试。”。蠢蠢的陪我做,搞笑。
先说一下笔试题,在纸上写程序,我比较烦这一点。总共有五道题吧,第一道是考智商的题,其他的记得不是很清楚,大概是字符串倒序输出,二分法,冒泡排序,还有一道记不清楚了。这些题目都不是很难只是有点麻烦,大概思想都比较简单,这里就不多说了。
笔试完就带你去面试,先来了两个人做的是java方面的,聊了一会,换了一个C++的来,这是我面试最长的一次,面试的知识点问了很多很多,而且很多都是细节方面的。这个面试官有点好玩的就是他问你一个问题如果你答的不全,他就会说,还有了、就这些。他这样问你的话,会把你问的不好回答,有时候他还会提醒你。感觉蛮专业的,如果进去的话应该能学到很多东西。
面完之后hr说第二天给消息,第二天也没给我,过了两天我打电话问了一下她说我过了,过了几天才给我发的offer。总体来说就是笔试不难,面试问了很多,hr你不联系她她也不联系你。
在日常编程中,我们肯定会遇到用socket传送文件内容,如果是大文件的,总不能传送到一半因某原因断掉了,又从新传送文件内容吧。对,我们需要续传,也就是接着上次传送的位置继续发送文件内容。
续传的话,其实并不难,我理解的思路大概如下:
客户端发送消息询问服务端,你上次接收到的文件内容位置服务端告诉客户端上次接收到的文件内容位置客户端就从上次断点的位置继续发送文件内容客户端发送文件内容完毕后通知服务端,然后断开连接 下面我们看看代码的实现
服务端 // file name: server.go package main import ( "os" "io" "net" "log" "strconv" // "time" ) // 把接收到的内容append到文件 func writeFile(content []byte) { if len(content) != 0 { fp, err := os.OpenFile("test_1.txt", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0755) defer fp.Close() if err != nil { log.Fatalf("open file faild: %s\n", err) } _, err = fp.Write(content) if err != nil { log.Fatalf("append content to file faild: %s\n", err) } log.Printf("append content: 【%s】 success\n"
本章是在nvidia_video_sdk_6.0.1的基础之上做封装的,我研究了其中的NvDecodeGL工程;由于自己工作会遇到显示多路rtsp视频流及解码的情况,所以进行了研究。
网上有其它的介绍ffmpeg和nvdia结合解码视频的文章,这里我将其实现了,并将官方的代码进行了精简和封装,封装后使用方法相当简单,示例如下
#include "NvDecode.h" #include "opencv.hpp" #include <iostream> int main() { NvDecode decod;//rtsp://admin:123ABCabc@192.168.2.236:554/Streaming/Channels/102?transportmode=unicast&profile=Profile_1 //rtsp://184.72.239.149/vod/mp4://BigBuckBunny_175k.mov decod.start(std::string("rtsp://184.72.239.149/vod/mp4://BigBuckBunny_175k.mov")); unsigned char *rgbaPtr = nullptr; int width = 0, height = 0; unsigned long long timestamp = 0; while (!decod.m_pFrameQueue->isEndOfDecode()) //到了视频末尾退出循环 { if (decod.deQueueFrame(&rgbaPtr, &width, &height, timestamp)) { cv::Mat frame(height, width, CV_8UC4, rgbaPtr); cv::imshow("video", frame); cv::waitKey(30); } else { cv::waitKey(20); //如果队列里面没有视频帧就等待一下 continue; } } return 0; } 我是使用的opencv进行显示的,出来的结果已经是rgba了,具体是bgra还是rgba还有点懵,opencv能播放,应该是bgra吧。但是官方的cuda函数写的是rgba。先不管这个了。
其中进行了大量的调试,官方的工程功能众多,主要说下流程吧
一、初始化设备、获取cuda的格式转换函数
__cu(cuInit(0, __CUDA_API_VERSION, hHandleDriver)); __cu(cuvidInit(0)); __cu(cuDeviceGet(&device, 0)); //使用0号显卡 __cu(cuCtxCreate(&cudaCtx, CU_CTX_SCHED_AUTO, device)); __cu(cuvidCtxLockCreate(&ctxLock, cudaCtx)); m_pFrameQueue = new CUVIDFrameQueue(ctxLock); CUresult oResult; //.
移动网站加载速度缓慢的原因
1、网站服务器
网站服务器(比如软件),默认情况下运行缓慢,或者尚未针对加载速度最大化进行合适的配置
2、虚拟主机解决方案
移动网站被托管于一个相对缓慢的虚拟主机解决方案(或硬件)中,或者这个网站流量非常高,经常超出虚拟主机可以处理的流量水平。
3、网站浏览器缓存
移动网站尚未被配置使用网站浏览器缓存
4、文件大小
移动网站页面要求下载资源,并且这些资源的文件大小加起来过大了。
5、HTTP请求
移动网站页面要求下载过多的资源,比如图片、音频、视频、js、css等文件,这会导致过多的http请求,每一次http请求都会执行三次握手,每次握手都会消耗较多的时间。
6、DNS查询
移动网站页面要求从过多的不同的主机名处下载各种资源,比如图片、音频、视频、js、css等文件,这会增加DNS查询次数,并且使网页加载速度变慢。
7、总体连接速度缓慢
一些有意或者无意的设置(过多的重定向、无效的请求等),会大大减慢页面加载速度
8、CDN
移动网站的用户大部分来自于面积极大的国家(或者横跨非常大的地理位置),但却没有使用CDN
9、网络自身速度缓慢
网站服务器与请求移动网站页面的用户(比如浏览器)之间的网络连接较慢。
HTML5框架可以提升网站的访问速度,通过优化前端将响应时间加快,使用户的等待时间减少。如何优化HTML5在移动设置上的性能表现,下面看一张图:
总之PC端性能优化的方法都可以应用到移动端来,而且移动端的时间消耗大部分在资源下载过程。
一:加载优化
1、减少HTTP请求数目
因为手机浏览器同时响应请求为4个请求(Android支持4个,iOS 5后可支持6个),所以要尽量减少页面的请求数,首次加载同时请求数不能超过4个。下面介绍减少HTTP请求数目的方法:
A、CSS Sprites:国内俗称 CSS 精灵,即雪碧图,这是将多张小图片合并成一张图片,达到减少 HTTP 请求的一种解决方案。可以通过 CSS background 属性来访问图片内容。这种方案同时还可以减少图片总字节数,节省命名词汇量(由命名多张图片文件变成一张)。
B、合并 CSS 和 JS 文件:现在前端有很多工程化打包工具,如:grunt、gulp、webpack等。为了减少 HTTP 请求数量,可以通过这些工具再发布前将多个 CSS 或者 多个 JS 合并成一个文件。
C、采用 lazyLoad:俗称懒加载,可以控制网页上的内容在一开始无需加载,不需要发请求,等到用户操作真正需要的时候立即加载出内容。这样就控制了网页资源一次性请求数量。
2、缓存
使用缓存可以减少向服务器的请求数,节省加载时间,所以所有静态资源都要在服务器端设置缓存,并且尽量使用长Cache(长Cache资源的更新可使用时间戳)。
A、缓存一切可缓存的资源
B、使用长Cache(使用时间戳更新Cache)
C、使用外联式引用CSS、JavaScript
3、压缩HTML、CSS、JavaScript
减少资源大小可以加快网页显示速度,所以要对HTML、CSS、JavaScript等进行代码压缩,并在服务器端设置GZip。
A、压缩(例如,多余的空格、换行符和缩进、注释)
B、启用GZip
4、使用首屏加载(对一些重要内容优先加载显示,一些次要内容可延迟加载)
首屏的快速显示,可以大大提升用户对页面速度的感知,因此应尽量针对首屏的快速显示做优化。
5、按需加载(按需加载可能会导致很多的重绘,影响渲染性能)
将不影响首屏的资源和当前屏幕资源不用的资源,放到用户需要时在加载,可以大大提升重要资源的显示速度和降低总体流量。
A、LazyLoad
B、滚屏加载
C、通过Media Query加载
6、预加载
大型重资源页面(如游戏)可使用增加Loading的方法,资源加载完成后再显示页面,但Loading时间过长,会造成用户流失。
A、可感知Loading(如进入空间游戏的Loading)
B、不可感知的Loading(如提前加载下一页)
数据来源大富翁期货数据,文件存放示例 F:\share\zc\20180108\ZC805_20180108.csv F:\share\zc\20180109\ZC805_20180109.csv
以下 代码生成1分钟、5分钟、15分钟k线数据,包括RSI
数据示例:
大富翁数据中心_市场代码,合约代码,时间,最新,持仓,增仓,成交额,成交量,开仓,平仓,成交类型,方向,买一价,卖一价,买一量,卖一量
zc,ZC805,2018-01-02 08:59:00.000,605.0000,235386,10,165770.0000,274.0000,142,132,空开,S,605.0000,605.4000,28,33 zc,ZC805,2018-01-02 09:00:00.000,604.2000,235470,84,73810.0000,122.0000,103,19,空开,S,604.2000,605.0000,1,4 zc,ZC805,2018-01-02 09:00:01.000,604.0000,235478,8,44676.0000,74.0000,41,33,空开,S,604.0000,604.4000,2,2 zc,ZC805,2018-01-02 09:00:01.000,603.8000,235508,30,56738.4000,94.0000,62,32,空开,S,603.6000,603.8000,33,10 #coding: utf-8
#!/usr/bin/env python import numpy as np import pandas as pd import os def rsiFunc(prices, n=14): deltas = np.diff(prices) seed = deltas[:n+1] up = (seed[seed>=0].sum())/n+0.000001 down = (-seed[seed<0].sum())/n+0.000001 rs = up/down rsi = np.zeros_like(prices) rsi[:n] = 100. - 100./(1.+rs) for i in range(n, len(prices)): delta = deltas[i-1] # cause the diff is 1 shorter if delta>0: upval = delta downval = 0.
序列化类:
public final class PushMsg { private final MsgType msgType; private String msgId; private String content; public PushMsg(MsgType msgType,String msgId,String content) { this.msgType = msgType; this.msgId = msgId; this.content = content; } public PushMsg(MsgType msgType) { this.msgType = msgType; } public static PushMsg build(MsgType msgType, String content) { PushMsg pushMessage = new PushMsg(msgType); pushMessage.setContent(content); return pushMessage; } public MsgType getMsgType(){ return msgType; } public String getMsgId() { return msgId; } public void setMsgId(String msgId) { this.
短短几年时间,人脸识别冲破技术应用难题入驻日常生活。前有支付宝刷脸支付,后有iPhone X 刷脸解锁,应用市场上更是群狼环视,各大技术企业争出奇招。一时间人脸识别技术风头无两,街头陋巷网络小报,到处充斥着“刷脸”应用,就连进出门都要用到人脸识别了。
人脸变身“门禁卡”横扫安防市场
没有门禁卡,不用钥匙,无需指纹,凭借一张脸就可以顺利通过小区大门。这样的场景,从前看似天方夜谭,如今不过随手日常,小区门口安装的摄像头点出其中玄机——人脸识别。
为提升小区安保等级,保障民众生命安全,国内不少生活社区启用了门禁系统。早期的门禁系统,主要依赖指纹识别、磁卡识别等技术,住户需要借助门禁卡、指纹等工具才能顺利通过小区大门。随着人脸识别技术深入研究与应用,市面上开始出现人脸识别门禁系统,该系统凭借人脸难以复制的特性横扫安防市场。
清晨匆忙出门,冲到小区门口才发现忘带门禁卡怎么办?要么掉头回去找,要么乖乖等人开门。平时还好,若是碰上工作日就有点悲剧了。对于分秒必争的上班族而言,等待的那一段时间或许就意味着全勤奖的泡汤。启用人脸识别门禁系统之后,人脸就成了全新的、随身携带的“门禁卡”,想要出门刷脸就行,无接触高速度,还能防止皮肤细菌传染。
当然,也有住户提出疑问:晚上咋办?黑乎乎的,脸都看不清还怎么刷脸?针对夜间人脸识别效果问题,云脉技术人员也解释道:人脸识别技术今非昔比,环境光对如今的人脸识别技术而言影响不大,即使是在夜间灯光下也可以轻松识别人脸。“夜间不能识别人脸”只是个不成问题的问题。
杜绝陌生人随意进出,强化小区安全管理
老旧小区或多或少存在管理不严问题。贴广告的、搞推销的、发传单的、认识的不认识的人员车辆随意出入,带来极大的安全隐患。启用门禁系统后,该现象明显得到缓解,然而拦得住无意人,防不住有心人。门禁卡复制成本低廉,指纹有指纹膜可以替代,只要想进来,什么门禁都不是问题。
在云脉人脸识别门禁系统正式启用之前,社区服务中心会通知住户进行身份证信息录入和人脸采集。正式启用人脸识别门禁之后,不曾在系统里登记过信息的人无法自由出入,有效杜绝陌生人随意进出,进一步强化社区安全管理。
亲友前来拜访,想要进入小区该怎么办?每次都要自己下来开门?显然不现实。针对这个问题,社区管理做出解释:“业主租户可以通过电话、视频等方式确认访客身份,随后进行临时性的人脸和身份证登记,就可以顺利进出小区了。”
由于小区人口经常发生变动,比如搬家、租房等,管理处需要及时为新住户更换指纹资料,配备门禁卡、钥匙等,非常麻烦。云脉人脸识别门禁投入使用之后,新来的住户只需要在社区管理处登记人脸信息,即可自由进出,大大节省社区人员变动管理成本。
曾经看似高深莫测的人脸识别,如今就在触手可及之处。云脉人脸识别门禁的投入应用,改变以往的出入模式,有效阻拦陌生人随意进出小区,尽可能降低小区安全事故发生的频率,提高住户生活体验,推进小区服务科技化,打造全新的物业管理模式,实现智能化管理。
转载于:https://my.oschina.net/u/3798904/blog/1789831
<input type="checkbox" name="selectall"/> 全选 <input name="partnerId" type="checkbox">aaaaaa <input name="partnerId" type="checkbox">bbbbbb $('input[name="selectall"]').click(function(){ if($(this).is(':checked')){ $('input[name="partnerId"]').each(function(){ //此处如果用attr,会出现第三次失效的情况 $(this).prop("checked",true); }); }else{ $('input[name="partnerId"]').each(function(){ $(this).removeAttr("checked",false); }); } });
<input type="text" :disabled="disabled"> data:{ disabled:false }
无论是公司的生产环境,还是自己搭建的测试环境,Zookeeper集群的节点个数都是奇数个。至于为什么要是奇数个,以前只是模糊的知道是为了满足选举需要,并不知道详细的原因。最近重点学习zookeeper,了解到其中的原理,现将其整理记录下来。
首先需要明确zookeeper选举的规则:leader选举,要求 可用节点数量 > 总节点数量/2 。注意 是 > , 不是 ≥。
注:为什么规则要求 可用节点数量 > 集群总结点数量/2 ? 如果不这样限制,在集群出现脑裂的时候,可能会出现多个子集群同时服务的情况(即子集群各组选举出自己的leader), 这样对整个zookeeper集群来说是紊乱的。 换句话说,如果遵守上述规则进行选举,即使出现脑裂,集群最多也只能回出现一个子集群可以提供服务的情况(能满足节点数量> 总结点数量/2 的子集群最多只会有一个)。 所以要限制 可用节点数量 > 集群总结点数量/2 。 采用奇数个的节点主要是出于两方面的考虑:
1、防止由脑裂造成的集群不可用。
首先,什么是脑裂?集群的脑裂通常是发生在节点之间通信不可达的情况下,集群会分裂成不同的小集群,小集群各自选出自己的master节点,导致原有的集群出现多个master节点的情况,这就是脑裂。
下面举例说一下为什么采用奇数台节点,就可以防止由于脑裂造成的服务不可用:
(1) 假如zookeeper集群有 5 个节点,发生了脑裂,脑裂成了A、B两个小集群: (a) A : 1个节点 ,B :4个节点 (b) A : 2个节点, B :3个节点 可以看出,上面这两种情况下,A、B中总会有一个小集群满足 可用节点数量 > 总节点数量/2 。所以zookeeper集群仍然能够选举出leader , 仍然能对外提供服务,只不过是有一部分节点失效了而已。
(2) 假如zookeeper集群有4个节点,同样发生脑裂,脑裂成了A、B两个小集群:
(a) A:1个节点 , B:3个节点 (b) A:2个节点 , B:2个节点
可以看出,情况(a) 是满足选举条件的,与(1)中的例子相同。 但是情况(b) 就不同了,因为A和B都是2个节点,都不满足 可用节点数量 > 总节点数量/2 的选举条件, 所以此时zookeeper就彻底不能提供服务了。
解决 Eclipse不支持tomcat9 前言: 我在配置eclipse+tomcat时,因为eclipse版本问题,里面没有Server选项;
好不容易找到了添加工具包,却发现没有tomcat;
一番功夫下来,新的工具包却只支持到tomcaHt8。
最后找到合适的方法,共享给大家。
解决方法: 1、在eclipse下: Help -> Eclipse Marketplace
2、搜索:apache-tomcat
3、发现两个扩展包,如图:
4、解释一下:
第一个JST Server Adapters 安装后只有tomcat8,应该是比较早的扩展了
第二个JAVA EE Developer Tools 东西有些多,不过好歹能用,顺带把其他工具更新一下。
5、安装过程有些慢,耐心等待。安装结束,会弹出提示,大概意思是有配置更改,需要重启。确认过后eclipse自动关闭,你再打开就可以在windows->perferences下找到Server -> Runtime Environment,添加tomcat9了。
简介 Preloader是一个用于异步加载数据的工具。它提供同步或者异步的获取结果回调。 适当地使用可让业务层获取数据的时间点提前。 使用例子 以简单activity跳转的例子为例,从MainActivity跳转到SubActivity。其中SubActivity的完整 显示需要发起一次请求,获取到结果后显示在中央的textView。 利用Preloader,我们可以在MainActivity发起跳转的时候开始请求,在SubActivity需要的时候将结果取出。 这样子可以把获取结果的时间点提前,起到加速显示SubActivity的作用。 代码如下所示: MainActivity: PreloadTask<String> task = new PreloadTask<String>() { @Override public void run(Preloader.Result<String> result) throws Exception { try { // 模拟5秒的同步请求 Thread.sleep(5*1000); // 设置请求结果 result.set("hello world"); } catch (InterruptedException e) { throw e; } } @Override public void onCancel() { Log.d(TAG, "onCancel() called"); } }; // 启动task,获取taskId。 int taskId = Preloader.start(task); // 传递taskId,用于获取结果。 Intent intent = new Intent(this, SubActivity.class); intent.putExtra("preload_task_id", taskId); startActivity(intent); SubActivity: mTextView = findViewById(R.
注: 1.eclipse所在环境为windows 2.hadoop版本2.8.3 3.hadoop-eclipse-plugin版本2.8.3 4.eclipse版本Luna Service Release 1 (4.4.1) 5.JDK 1.7
插件安装 hadoop-eclipse-plugin编译 因为我本地使用的JDK为1.7,而现在网上能找到的hadoop-eclipse-plugin-2.8.3都是基于JDK1.8编译的,所以都不能使用,因此需要下载hadoop-eclipse-plugin的源码然后在本地编译,过程中需要Hadoop-2.8.3的支持。当然如果你能找到符合自己环境的插件包,这步就可以跳过了。 Hadoop-2.8.3.tar.gz hadoop2x-eclipse-plugin (github托管的源码) apache-ant-1.9.11-bin.zip 下载完后解压apache-ant-1.9.11-bin.zip,并配置环境变量。 新建ANT_HOME=E:apache-ant-1.9.4 在PATH后面加;%ANT_HOME%\bin 测试下
ant -version 解压Hadoop-2.8.3.tar.gz,hadoop2x-eclipse-plugin 编辑E:\hadoop2x-eclipse-plugin-master\src\contrib\eclipse-plugin\build.xml 添加下图红框中的部分,3项代表的意思应该都懂,就不多说了。 然后往下翻能发现有一堆这个东西,之后编译时大概会出错的地方。先打开放在这,不用修改。① 然后编辑E:\hadoop2x-eclipse-plugin-master\ivy\libraries.properties.xml 一般来讲只要修改下红框中的版本即可,然后这里有一大堆版本,而上面①图中那些都是在引用这里的版本。这里的版本又对应着Hadoop-2.8.3中的资源。在编译时可能会出现这里写的版本和Hadoop实际用的版本不一样导致找不到jar包的报错,这时就可以根据报错信息来修改下方的版本号,使得符合实际。基本都在${hadoop.home}/share/hadoop/common/lib文件夹中 进入hadoop2x-eclipse-plugin-master\src\contrib\eclipse-plugin目录,运行cmd命令行
ant jar 编译完成,遇到错误就根据提示修改,最大可能遇到的就是我上面提到的问题,还有当编译时长时间卡在ivy-resolve-common: 处时,大概率已经编译失败。 编译完成后的文件在 hadoop2x-eclipse-plugin-master\build\contrib\eclipse-plugin文件夹中 将jar包放入eclipse/plugins文件夹中,重启eclipse 可以看到如下图标 添加 window->show view->other 配置连接,如下图所示,随便取个名字就行 然后如果连接成功的话就如下图所示,这里刚新搭建的Hadoop环境的话应该一开始就是空的,所以可能会抛空指针异常,没什么影响的,直接新建东西就行。 新建后需要刷新一下,同时可以访问http://xx.xx.xx.xx:50070/explorer.html#/网址查看是否真的新建了。 通过这个我们可以轻松快捷的将文件上传给Hadoop文件系统,方便本地调试。
window->preferences,选择Hadoop文件,这里主要目的是可以直接引用相关jar包 使用例子,单词计数 首先需要下载hadoop.dll,这个网上找找对应版本的吧,我用的是2.X的,放在C/windows/System32下。 File->New->other next,填写名字,finish 新建4个文件 WordCountMapper.java
package com.hadoop.demo; import java.io.IOException; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Mapper; /* * KEYIN:输入kv数据对中key的数据类型 * VALUEIN:输入kv数据对中value的数据类型 * KEYOUT:输出kv数据对中key的数据类型 * VALUEOUT:输出kv数据对中value的数据类型 */ public class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable>{ /* * map方法是提供给map task进程来调用的,map task进程是每读取一行文本来调用一次我们自定义的map方法 * map task在调用map方法时,传递的参数: * 一行的起始偏移量LongWritable作为key * 一行的文本内容Text作为value */ @Override protected void map(LongWritable key, Text value,Context context) throws IOException, InterruptedException { //拿到一行文本内容,转换成String 类型 String line = value.
查了下网上资料,Mark下 ,请参考:
1. https://zhuanlan.zhihu.com/p/25889246
点击直接下载地址
2.https://jingyan.baidu.com/article/adc815139f66c2f723bf7383.html
介绍通过Arcgis方式下载
3.https://blog.csdn.net/jianbinzheng/article/details/53649211
本文主要讲矩阵对角化的证明及应用。 矩阵对角化条件 定义一:若存在可逆矩阵 S S ,使得S−1ASS−1AS为对角矩阵,则称为矩阵 A A 是可对角化的(diagonalized)。
设n×nn×n矩阵有 n n 个线性无关的特征向量x1,...,xnx1,...,xn,令 S=(x1,...,xn) S = ( x 1 , . . . , x n ) ,则: AS=A(x1,...,xn)=(λ1x1,...,λnxn)=(x1,...,xn)⎛⎝⎜λ1...λn⎞⎠⎟ A S = A ( x 1 , . . . , x n ) = ( λ 1 x 1 , . . . , λ n x n ) = ( x 1 , . . . , x n ) ( λ 1 .
2018年4月1日愚人节,我第一次参加了有关计算机算法类比赛“蓝桥杯”,这篇算是经验总结和题目回顾,水平有限,有不妥之处欢迎留言批评指正,也可以加QQ891465170交流~ 下面进入正题: 第一题:第几天 2000年的1月1日,是那一年的第1天。 那么,2000年的5月4日,是那一年的第几天? 注意:需要提交的是一个整数,不要填写任何多余内容。
哈哈这激动的啊,太简单直接脑算,结果坑爹了,我把闰年二月记成28天普通年29天,直接错了,送分题都没拿到。
解法:2000年是闰年二月有29天,一月和三月有31天,四月有30天,所以: 31+29+31+30+4=125 第二题:方格记数 如图p1.png所示,在二维平面上有无数个1x1的小方格。 我们以某个小方格的一个顶点为圆心画一个半径为1000的圆。 你能计算出这个圆里有多少个完整的小方格吗? 注意:需要提交的是一个整数,不要填写任何多余内容。
这个题不太会做,计算出这个圆的内接正方形编成为1000sqrt(2)=1414,正方形中方格个数为14141414,关键在于正方形外不会计算。
第三题:复数幂 设i为虚数单位。对于任意正整数n,(2+3i)^n 的实部和虚部都是整数。 求 (2+3i)^123456 等于多少? 即(2+3i)的123456次幂,这个数字很大,要求精确表示。 答案写成 "实部±虚部i"
的形式,实部和虚部都是整数(不能用科学计数法表示),中间任何地方都不加空格,实部为正时前面不加正号。(2+3i)^2 写成: -5+12i,
(2+3i)^5 的写成: 122-597i
注意:需要提交的是一个很庞大的复数,不要填写任何多余内容。
这个好办,写段程序,把实部和虚部存储,连乘123456次,即循环123456次。
public class T3 { public static void main(String[] args) { int a = 2, b = 3; for(int i = 1; i<123456; i++){ int temp = 2*a-3*b; b = 3*a+2*b; a = temp; } System.out.println(a+"+"+b+"i"); } } 答案:13483137+1100011648i 这题更正一下,由于是大数运算使用int类型当然是不行的,哎,第一次遇到这么大数运算也是无奈,使用BigInteger类型。
一、解释 每个类可以对应一个伴生对象 伴生对象的成员全局独一份 伴生对象的成员类似于Java的静态成员
二、Java中 调用kotlin类的方法需要加上 @JvmStatic 调用kotlin类的成员变量需要加上 @JvmField
三、形如java.lang包中math类 它所有的方法全部都是静态的,在使用的时候,直接就可以math.xxx(方法) 四、形如Integer类中的方法,在Java中这样使用
Integer a = Integer.valueOf(3); 五、在Kotlin中,形如这样的可以直接调用 看一下代码
Integer a = Integer.valueOf(3); 六、看一下例子 先看一下kotlin中的类
package net.println.kotlin.chapter4 /** * @author:wangdong * @description:伴生对象和静态成员 */ fun main(args: Array<String>) { //val a = minOf(args[0].toInt(),args[1].toInt()) //用一下下面的定义 val latitude = Latitude.ofDouble(40.3) val latitude2 = Latitude.ofLatitude(latitude) println(Latitude.TAG) } /**定义一个纬度类*/ class Latitude private constructor(val value: Double){ //类的伴生对象 companion object { //定义一个静态方法 @JvmStatic fun ofDouble(double: Double): Latitude { return Latitude(double) } //定义一个静态方法 @JvmStatic fun ofLatitude(latitude: Latitude): Latitude { return Latitude(latitude.
今天经过长时间的尝试和搜索,设置是切换各种镜像源的尝试,都无法正常安装,目前已找到解决方法了,一开始网上并没有确切的答案,但是经过不断的试错,终于找到了问题的源头,现在分享下,避免以后其他人走太多弯路。
发现问题 info There appears to be trouble with your network connection. Retrying... info There appears to be trouble with your network connection. Retrying... info There appears to be trouble with your network connection. Retrying... info There appears to be trouble with your network connection. Retrying... error An unexpected error occurred: "https://registry.npm.taobao.org/autoprefixer: tunneling socket could not be established, cause=connect ETIMEDOUT 10.129.49.21:8080". 经过沉着冷静的思考后,分析关键词:tunneling socket could not be established
通过百度和Google搜索引擎的帮助,终于发现了解决方案
解决方案 代理出现了问题,删除之
代码读取图片并修改文件大小:
# Author:NDK # -*- coding:utf-8 -*- from PIL import Image import os import cv2 import numpy as np import glob # old_dir = './test/' # def read_image(cwd, newpath): # for roots, dirs, files in os.walk(cwd): # print(dirs) # for i in dirs: # print(i) # os.chdir(cwd + i) # for pic in glob.glob('*.png'): # _, image = pic.split('_') # img = image.split('.')[0] # print(img) # if len(img) != 0: # if int(img) % 2 !
1.ServletContext方式
采用ServletContext读取配置文件realpath,然后通过文件流读出来。
优点:可以读取任意位置的文件
采用文件流读取,所以可以读取不同格式的文件
缺点:不能在servlet外面读取配置文件
实现:
package com.xunjie.common.utils; import java.io.FileInputStream; import java.io.InputStreamReader; import java.util.Properties; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class Profile { // 采用ServletContext读取配置文件的realpath,然后通过文件流读取出来 public void readProfileByServletContext(HttpServletRequest request, HttpServletResponse response) { // 通过servletcontext读取到文件路径 String realPath = request.getServletContext().getRealPath("jdbc.properties"); //InputStream 是字节输入流的所有类的超类,一般我们使用它的子类,如FileInputStream InputStreamReader reader; //Properties类,主要用于读取Java的配置文件 Properties props = new Properties(); try { // 建议使用Reader来读,因为reader体系中有个InputStreamReader可以指定编码 reader = new InputStreamReader(new FileInputStream(realPath), "utf-8"); // load ( InputStream inStream)方法 // 从输入流中读取属性列表(键和元素对)。 通过对指定的文件(比如说上面的jdbc.properties文件)进行装载来获取该文件中的所有键 - 值对。 以供 getProperty ( String key) 来搜索。 props.
1、导包mybatis-spring-1.3.2.jar
http://repo2.maven.org/maven2/org/mybatis/mybatis-spring/1.3.2/
2、在web.xml引入spring配置文件
<!-- 引入spring其它配置文件 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext-*.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> 3、在根目录src下创建xml文件applicationContext-dao.xml
<!-- 引入数据库参数文件 --> <context:property-placeholder location=" classpath:resources/database.properties"/> 配置数据源
<!-- spring数据库源 --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName"> <value>com.mysql.jdbc.Driver</value> </property> <property name="url"> <value>${jdbc.url}</value> </property> <property name="username"> <value>${jdbc.username}</value> </property> <property name="password"> <value>${jdbc.password}</value> </property> </bean> 配置sqlSessionFactory
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 数据库源 --> <property name="dataSource" ref="dataSource"/> <!-- mybatis配置文件 --> <property name="configLocation" value="classpath:/resources/mybatis-config2.xml"/> </bean> 配置dao/mapper扫描器
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!-- 扫描需要注入所依赖的dao --> <property name="basePackage" value="
1、在入口文件index.html中加入loading动画: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport"> <!--浏览器兼容模式用最新的文档渲染模式--> <meta http-equiv="X-UA-Compatible" content ="IE=edge"/> <title></title> <style type="text/css"> #Loading { top:50%; left:50%; position: absolute; -webkit-transform: translateY(-50%) translateX(-50%); transform: translateY(-50%) translateX(-50%); z-index:100; } @-webkit-keyframes ball-beat { 50% { opacity: 0.2; -webkit-transform: scale(0.75); transform: scale(0.75); } 100% { opacity: 1; -webkit-transform: scale(1); transform: scale(1); } } @keyframes ball-beat { 50% { opacity: 0.2; -webkit-transform: scale(0.75); transform: scale(0.75); } 100% { opacity: 1; -webkit-transform: scale(1); transform: scale(1); } } .
为什么不行啊
#include<iostream>
using namespace std; //class stu //{ //public: // stu(int b); // ~stu(); //public: // int a; //}; //stu::stu(int b) //{ // a = b; //} // // //stu::~stu() //{ //} int main() { class str { public: str(int b); ~str(); private: int a; }; str::str(int b) { a = b; } str::~str() { } }
server { listen 443; server_name eee.top; ssl on; root /data/webroot/test; index index.html index.htm; ssl_certificate cert/2.pem; ssl_certificate_key cert/244.key; ssl_session_timeout 5m; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; location / { if (!-e $request_filename){ rewrite (.*) /index.php last;} } location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; include fastcgi_params; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_script_name; } location ~ /\.ht { deny all; } }
1.PID算法演示软件1 (1)P太小,实际值和设定值时间有很大的偏差,实际值偏小或偏大。长时间回不到设定值附近,或者实际值小于设定值,实际值一直到不了设定值。 (2)P太大,初始时刻有抖动,或出现波浪曲线。 (3)I太大,有静态偏差,实际值先偏大,然后很长时间才能回到设定值。 (4)D太小,在起始时刻,实际值会超过设定值,然后较快回到设定值。 (5)增大D值,可消除在起始时刻出现的超值现象。但积分太大,会出现严重抖动。 2.PID算法演示软件2 (1)P值太小(此时只调试P值),实际值和设定值之间存在静差。 (2)P值太大,实际值总存在类似于正弦震荡。 在上述的基础上,然后设定P值为最大值(在最大值时,实际的曲线在最大值和最小值之间震荡)的一半。 (3)I太小,实际值回到设定值较慢。 (4)I太大,起始时刻存在以设定值为中心的阻尼震荡。 在上面的基础上,已经设定了P和I的值。 (5)D太大,在起始时刻存在以设定值为中心的反阻尼震荡。 (6)D相对较大,在起始时刻存在以设定值为中心的阻尼震荡。
以上是我个人经验总结的笔记,有总结的不到位的地方,还请指正!
````
import matplotlib.pyplot as plt
import numpy as np
def show_values(pc, fmt="%.2f", **kw):
'''
Heatmap with text in each cell with matplotlib's pyplot
Source: https://stackoverflow.com/a/25074150/395857 By HYRY
'''
from itertools import izip
pc.update_scalarmappable()
#ax = pc.get_axes()
ax = pc.axes
for p, color, value in izip(pc.get_paths(), pc.get_facecolors(), pc.get_array()):
x, y = p.vertices[:-2, :].mean(0)
if np.all(color[:3] > 0.5):
color = (0.0, 0.0, 0.0)
else:
color = (1.0, 1.0, 1.0)
ax.text(x, y, fmt % value, ha="
1,为什么拷贝构造函数传入的必须是引用?
如果拷贝构造函数中的参数不是一个引用,即形如CClass(const CClass c_class),那么就相当于采用了传值的方式(pass-by-value),而传值的方式会调用该类的拷贝构造函数,从而造成无穷递归地调用拷贝构造函数。因此拷贝构造函数的参数必须是一个引用。
需要澄清的是,传指针其实也是传值,如果上面的拷贝构造函数写成CClass(const CClass* c_class),也是不行的。事实上,只有传引用不是传值外,其他所有的传递方式都是传值。 #include<iostream> using namespace std; class CExample { private: int m_nTest; public: CExample(int x) : m_nTest(x) //带参数构造函数 { cout << "constructor with argument"<<endl; } // 拷贝构造函数,参数中的const不是严格必须的,但引用符号是必须的 CExample(const CExample & ex) //拷贝构造函数 { m_nTest = ex.m_nTest; cout << "copy constructor"<<endl; } CExample& operator = (const CExample &ex) //赋值函数(赋值运算符重载) { cout << "assignment operator"<<endl; m_nTest = ex.m_nTest; return *this; } void myTestFunc(CExample ex) { } }; int main(void) { CExample aaa(2); // 实例化对象,调用构造函数 CExample bbb(3); // 实例化对象,调用构造函数 bbb = aaa; // 赋值函数 CExample ccc = aaa; // 拷贝构造函数,对象ccc不存在,通过对象aaa实例化, bbb.
一、今天写了两个文件上传的接口用到了@RequestParam和@RequestPart @RequestPart
/** * 单文件上传 * @param file * @param bucket * @return */ @RequestMapping("uploadFile") public JsonResult uploadFile(@RequestPart("file") MultipartFile file, @RequestParam String bucket){ String fileUrl = aliossService.uploadFile(file, bucket); Map<String,String> result = new HashMap<>(); result.put("fileUrl",fileUrl); return success(result); } @RequestParam
/** * 上传字符串 * @param stringFile * @param bucket * @return */ @RequestMapping("uploadStringFile") public JsonResult uploadStringFile(@RequestParam("stringFile") String stringFile, @RequestParam("bucket") String bucket){ String fileUrl = aliossService.uploadStringFile(stringFile, bucket); Map<String,String> result = new HashMap<>(); result.
1.创建screen会话 以下是创建的第一个会话窗口,用来连接100服务器
若想创建第二个窗口
按(ctrl+a)+c,下面为第二个窗口
继续创建第三个窗口
2.ctrl+a+w,显示所有窗口列表 我已经创建了三个窗口,并且显示在上面
3.窗口切换 C-a C-a 切换到之前显示的窗口
C-a n 切换到下一个窗口
C-a p 切换到前一个窗口
C-a 0...9 切换到窗口0...9
4.关闭或杀死窗口 C-a k 5.暂时断开screen会话 C-a d 6.查看所有会话 screen -ls 7.进入某一个会话 *screen -r 4307(指定进入某个会话,当只有一个会话的时候可以不用加)
2018年1月份给师姐做的一个小项目,本来不打算写的,因为论文还没发表,涉及查重等乱七八糟的问题。。。。
感觉现在不写,以后应该来不及了,因为已经在实习岗位了。。。。
不做过多介绍,只做大概的描述,我是在别人程序上进行改进和优化的。。。。
之前还想把博文写的好看一点,现在没时间也没心思了,每天挤三个小时公交车去上班,那有多余时间来弄博文。
参考几位大神的博文和百度知道:
https://blog.csdn.net/bettarwang/article/details/12179995#insertcode
https://blog.csdn.net/lmm6895071/article/details/78329045?locationNum=7&fps=1
https://zhidao.baidu.com/question/574425289.html?push=keyword#answer-1447459538 https://blog.csdn.net/chen_jp/article/details/7947059
粒子群算法的原理:
这个网上一大堆,上面的博文中也详细的描述了,没必要要照葫芦画瓢了。
约束问题的描述:
对于 ,算法描述: 当 当作为0处理,当 当作 处理。 意思就是,满足条件直接在原来的基础上加上一个正值,让目标变大。当不满足条件,那就等于0,或者等于一个负值,目的让目标变小。因为优化的目标为大,反之相反即可!
对于 ,C++代码描述: float result = 3x + 2y + ((2x+3y-2000)>0?0:abs(2x+3y-2000)); 下面的几个约束就类似,比较简单了。
粒子群算法的C++实现VS2015控制台版本:
论文还未发表,暂时不上传代码,如果需要的朋友请留邮箱!
粒子群算法的C++实现QT5.7.0界面版:
论文还未发表,暂时不上传代码,如果需要的朋友请留邮箱!
Select e1.Name as Employee from Employee e1 , Employee e2 where e1.ManagerId = e2.Id and e1.Salary > e2.Salary 或者使用join
# Write your MySQL query statement below Select e1.Name as Employee from Employee e1 join Employee e2 on e1.ManagerId = e2.Id and e1.Salary > e2.Salary
直接查询如果不存在第二高的Salary不会返回值,所以应该用子查询
select (select distinct Salary from Employee order by Salary desc limit 1,1) as SecondHighestSalary 也可以用IFNULL ifnull(exr1,exr2) 如果exr1是null那么返回exr2否则返回exr1
select ifnull( (select distinct Salary from Employee order by Salary desc limit 1 offset 1), NULL) as SecondHighestSalary select max(Salary) as SecondHighestSalary from Employee where Salary <> (select max(Salary) from Employee)