学习笔记:iOS 使用Yoga布局----一种FlexBox布局实现

集成 Yoga是Facebook开源的基于CSS FlexBox布局框架,核心使用C++实现的,在iOS上并不需要直接集成C++代码,只需通过CocoaPod引入 YogaKit(间接集成C++代码) # Podfile platform :ios, '8.0' use_frameworks! target "TestProject" do pod 'YogaKit' end 使用 集成后,YogaKit提供了UIView的方法扩展 // UIView+Yoga.h @property (nonatomic, readonly, strong) YGLayout *yoga; yoga 类型为 YGLayout,描述了UIView如何布局。 简单示例 //代码源自 https://www.jianshu.com/p/95bf92143141 -(void)test { [self.view configureLayoutWithBlock:^(YGLayout * layout) { layout.isEnabled = YES; layout.width = YGPointValue(self.view.bounds.size.width); layout.height = YGPointValue(self.view.bounds.size.height); layout.alignItems = YGAlignCenter; }]; UIView *contentView = [[UIView alloc]init]; contentView.backgroundColor = [UIColor lightGrayColor]; [contentView configureLayoutWithBlock:^(YGLayout * layout) { layout.isEnabled = true; // 4 layout.flexDirection = YGFlexDirectionRow; layout.width = YGPointValue(320); layout.height = YGPointValue(80); layout.marginTop = YGPointValue(100); layout.padding = YGPointValue(10);//设置了全部子项目的填充值 }]; UIView *child1 = [[UIView alloc]init]; child1.backgroundColor = [UIColor redColor]; [child1 configureLayoutWithBlock:^(YGLayout * layout) { layout.isEnabled = YES; layout.width = YGPointValue(80); layout.marginRight = YGPointValue(10); }]; UIView *child2 = [[UIView alloc]init]; child2.backgroundColor = [UIColor blueColor]; [child2 configureLayoutWithBlock:^(YGLayout * layout) { layout.isEnabled = YES; layout.width = YGPointValue(80); layout.flexGrow = 1; layout.height = YGPointValue(20); layout.alignSelf = YGAlignCenter; }]; [contentView addSubview:child1]; [contentView addSubview:child2]; [self.view addSubview:contentView]; [self.view.yoga applyLayoutPreservingOrigin:YES]; } 注意: ...

September 26, 2019 · 1 min · holdsky

基于Yoga的移动端布局设计方案

[TOC] DSL基本语法 可阅读的文件,其语法首先遵循xml规范 <节点名 节点类型 其他属性> <节点名 节点类型 其他属性> <节点名 节点类型 其他属性> .... <节点名/> <节点名/> <节点名 节点类型 其他属性> <节点名/> <节点名/> 节点类型 , 指当前节点的类型 : 视图类型,表示当前节点描述一个视图属性;此时节点名表示视图的类名,如Text,Button控件类名 其他待扩展 其他属性: 布局属性 数据属性 其他待扩展 示例: <Button type="view" width="10",height="10%" title="点击"> <ImageView type="view" img="xxx.png" /> <JS type="javascript"> 此处为示例,不一定支持 </JS> </Button> 主轴和交叉轴 (main axis/cross axis) 布局方式 大致和css flex box一致 文件格式 应支持两种格式 .xml .ffx(名称暂定),.xml的二进制化,加速解析效率 布局引擎可根据扩展名判断文件格式 基本属性 取名尽量和css flex box保持一致 布局方向 direction direction,子元素在父容器的布局方向。 布局方向也会影响边的起点和终点。 默认情况下(ltr) “start”是指左侧,“end”是指右侧。 ...

September 25, 2019 · 2 min · holdsky

Java:Chacha20算法(从openssl移植)

使用示例 String str = "hello world"; int key[] = {-123,-456,789,123,456,7890,456,456}; int noc[] = {-123,-456,789,123}; byte[] encryptData = Chacha20.crytpoCounter32(str.getBytes(),key,noc); byte[] decryptData = Chacha20.crytpoCounter32(encryptData,key,noc); String str2 = new String(decryptData); boolean equal = str.equals(str2); 具体代码 package com.zxs.zl; /* * Copyright 2015-2018 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ public class Chacha20 { /* * ChaCha20_ctr32 encrypts |len| bytes from |inp| with the given key and * nonce and writes the result to |out|, which may be equal to |inp|. * The |key| is not 32 bytes of verbatim key material though, but the * said material collected into 8 32-bit elements array in host byte * order. Same approach applies to nonce: the |counter| argument is * pointer to concatenated nonce and counter values collected into 4 * 32-bit elements. This, passing crypto material collected into 32-bit * elements as opposite to passing verbatim byte vectors, is chosen for * efficiency in multi-call scenarios. */ /** * function same ,encrypt and decrypt * @param inp source data (encrypt data or decrypt data) * @param key int[8] array * @param counter int[4] array * @return decrypt data or encrypt data ; see inp param. */ public static byte[] crytpoCounter32(byte[] inp, int[] key,int[] counter) { byte[] out = new byte[inp.length]; int[] input = new int[16]; byte[] buf = new byte[64]; int todo, i; /* sigma constant "expand 32-byte k" in little-endian encoding */ input[0] = ((int)'e') | ((int)'x'<<8) | ((int)'p'<<16) | ((int)'a'<<24); input[1] = ((int)'n') | ((int)'d'<<8) | ((int)' '<<16) | ((int)'3'<<24); input[2] = ((int)'2') | ((int)'-'<<8) | ((int)'b'<<16) | ((int)'y'<<24); input[3] = ((int)'t') | ((int)'e'<<8) | ((int)' '<<16) | ((int)'k'<<24); input[4] = key[0]; input[5] = key[1]; input[6] = key[2]; input[7] = key[3]; input[8] = key[4]; input[9] = key[5]; input[10] = key[6]; input[11] = key[7]; input[12] = counter[0]; input[13] = counter[1]; input[14] = counter[2]; input[15] = counter[3]; int len = inp.length; int offset = 0; while (len > 0) { todo = 64;// equal to buf.length; if (len < todo) todo = len; chacha20_core(buf, input); for (i = 0; i < todo; i++){ out[i+offset] = (byte) (inp[i+offset] ^ buf[i]); } offset += todo; len -= todo; /* * Advance 32-bit counter. Note that as subroutine is so to * say nonce-agnostic, this limited counter width doesn't * prevent caller from implementing wider counter. It would * simply take two calls split on counter overflow... */ input[12]++; } return out; } /* chacha_core performs 20 rounds of ChaCha on the input words in * |input| and writes the 64 output bytes to |output|. */ private static void chacha20_core(byte[] output, int[] input) { //output byte[64] long[] x = new long[16]; for (int i = 0 ; i < 16 ;i++){ x[i] = (input[i] & 0xFFFFFFFFL ); } for (int i = 20; i > 0; i -= 2) { QUARTERROUND(x,0, 4, 8, 12); QUARTERROUND(x,1, 5, 9, 13); QUARTERROUND(x,2, 6, 10, 14); QUARTERROUND(x,3, 7, 11, 15); QUARTERROUND(x,0, 5, 10, 15); QUARTERROUND(x,1, 6, 11, 12); QUARTERROUND(x,2, 7, 8, 13); QUARTERROUND(x,3, 4, 9, 14); } for (int i = 0; i < 16; ++i) { long v = (x[i] + input[i]) & 0xFFFFFFFFL; output[i<<2] = (byte) (v & 0xFF); output[(i<<2) + 1] = (byte) ((v>>8) & 0xFF); output[(i<<2) + 2] = (byte) ((v>>16) & 0xFF); output[(i<<2) + 3] = (byte) ((v>>24) & 0xFF); } } /* QUARTERROUND updates a, b, c, d with a ChaCha "quarter" round. */ private static void QUARTERROUND(long[]x, int a,int b,int c,int d){ x[a] = (x[a] + x[b]) & 0xFFFFFFFFL; x[d] = ROTATE((x[d] ^ x[a]),16) & 0xFFFFFFFFL; x[c] = (x[c] + x[d]) & 0xFFFFFFFFL; x[b] = ROTATE((x[b] ^ x[c]),12) & 0xFFFFFFFFL; x[a] = (x[a] + x[b]) & 0xFFFFFFFFL; x[d] = ROTATE((x[d] ^ x[a]), 8) & 0xFFFFFFFFL; x[c] = (x[c] + x[d]) & 0xFFFFFFFFL; x[b] = ROTATE((x[b] ^ x[c]), 7) & 0xFFFFFFFFL; } private static long ROTATE(long v,int n) { v = v & 0xFFFFFFFFL; return (((v) << (n)) | ((v) >> (32 - (n)))); } }

September 24, 2019 · 4 min · holdsky

学习笔记:Yoga 布局属性

本文为Google翻译+人工修正文章 参考 https://yogalayout.com/docs [TOC] 主轴和交叉轴 (main axis/cross axis) 绝对布局和相对布局 (Absolute/Relative Layout) 元素布局分为两种,一种是绝对布局,一种是相对布局。 相对布局 (默认) 默认情况下,元素的位置相对。 这意味着元素将根据布局的正常流程进行定位,然后根据上,右,下和左的值相对于该位置偏移。 偏移量不会影响任何同级元素或父元素的位置。 绝对布局 绝对位置绝对放置时,元素不会参与正常的布局流程。 相反,它的布局与兄弟姐妹无关。 根据上,右,下和左的值确定位置。 译者注:注意取值顺序,上(top),右(right),下(bottom),左(left) 位置值上(top),右(right),下(bottom),左(left)的行为取决于元素的位置类型(相对布局或绝对布局)。 对于相对布局元素,它们沿指定方向偏移元素的位置。 对于绝对布局元素,这些属性指定了元素的相对于父元素的同一边的偏移量( 译者注,这句有点绕,其实就是同边对同边,例如子元素的上(top)是从父元素的上(top)开始算起)。 演示效果参见 https://yogalayout.com/docs/absolute-relative-layout 布局方向(Layout direction) 指在层次结构中,子项和文本的布局方向。 布局方向也会影响边的起点和终点。 默认情况下,Yoga沿LTR布局方向进行布局。在此模式下,“start”是指左侧,“end”是指右侧。 使用RTL方向时,应通过将方向传递给CalculateLayout调用或在根节点上设置方向来自定义此功能。 LTR(默认)从左到右排列。 应用于元素边距和填充的开始在左侧。 RTL 从右到左排列。 应用于元素边距和填充的开始在右侧。 宽度和高度( Width and Height) Yoga中的width属性指定元素内容区域的宽度。 同样,height属性指定元素内容区域的高度。 宽度和高度都可以采用以下值: AUTO是默认值,Yoga根据元素的内容(无论是其他子元素,文本还是图像)计算元素的宽度/高度。 PIXELS 定义绝对像素的宽度/高度。 取决于Yoga节点上设置的其他属性( 译者注:如flex grow ,padding),这可能是节点的最终尺寸,也可能不是。 PERCENTAGE 分别以其父对象的宽度或高度的百分比定义宽度或高度。 演示效果参见 https://yogalayout.com/docs/width-height 宽高的最值(Max / Min Width and Height) 以下所有属性均设置元素的最大和最小尺寸限制。 这些属性的优先级高于所有其他属性,并且将始终受到(布局动作)的考虑。 约束可以指定为绝对像素值,也可以指定为其父级大小的百分比。 默认情况下,所有这些约束都是 undefined。 MAX WIDTH MIN WIDTH MAX HEIGHT MIN HEIGHT 演示效果参见 https://yogalayout.com/docs/min-max ...

September 23, 2019 · 2 min · holdsky

nginx 配置SSL证书

支持SSL/TLS 在nginx的虚拟主机配置文件中添加 server { # http配置 listen 80; listen [::]:80; server_name test.abc.com; ####### SSL配置 ######### listen 443 ssl; listen [::]:443 ssl; #解决The plain HTTP request was sent to HTTPS port # https://www.centos.bz/2018/01/nginx%E5%A6%82%E4%BD%95%E8%A7%A3%E5%86%B3the-plain-http-request-was-sent-to-https-port%E9%94%99%E8%AF%AF/ ssl off; #ssl 会话超时 ssl_session_timeout 5m; #支持的SSL/TLS协议版本 ,如SSLv2 SSLv3 TLSv1; ssl_protocols SSLv3 TLSv1; #支持的协商算法 ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP; ssl_prefer_server_ciphers on; # SSL证书位置 ssl_certificate /xxxx/xxxx/123.crt; ssl_certificate_key /xxxx/xxxx/456.key; ################ 其他配置略 ..... } 自动转发HTTP到HTTPS 原理是rerwite规则,重定向到https,所以需要创建两个虚拟主机,一个http,一个https ...

September 23, 2019 · 1 min · holdsky

Windows10:配置Visual Studio Code 以SSH方式访问远程主机

Windows10上遇到过ssh的坑,记录下过程 参考 https://code.visualstudio.com/docs/remote/troubleshooting#_installing-a-supported-ssh-client 环境和知识准备 远程主机,并开启ssh-server服务(通常端口22) Windows环境(本文Windwos10家庭版) Visual Studio Code 公钥加密算法,对SSH,通常为RSA 已经生成好的ssh公钥文件和私有文件 步骤 安装ssh-client 对于Windows10的一些版本,可以通过 设置--系统--应用和功能--管理可选功能--添加功能 来开启ssh-client,奈何本穷的Windows10不支持。 还有两种方法来安装ssh-client 通过PowerShell安装,以管理员方式启动PowerShell,具体参考 这里,反正本穷是没有成功。 于是,只有通过安装Git for Windows来安装ssh-client了, 下载地址 安装RemoteSSH 这里需要给Visual Studio Code 安装扩展包,以支持RemoteSSH。 Visual Studio Code -- 查看 --扩展,在扩展中搜索 Remote Development,然后安装这个扩展包,会自动安装相关依赖包。 配置Vistual Studio Code SSH Visual Studio Code -- 设置,搜索SSH,在结果列表中找到 扩展--Remote-SSH -- Remote.SSH:Config File,自定义RemoteSSH的配置文件路径,然后创建这个配置文件,内容如下: Host 自定义别名 User 远程主机ssh登陆的用户名 HostName 远程主机名字,可以是ip地址 Port 远程主机ssh端口号,一般是22 IdentityFile 身份验证文件路径,即ssh私钥文件路径 访问 Vistual Studio Code – 查看 –命令面板 –Remote-SSH:Connect ToHost 选择配置文件中配置好的主机即可。

September 21, 2019 · 1 min · holdsky

代码片段:php解析url的query参数

/** * @param string $url * @return array */ function ParseQuery($url) { //按照?号切割 $tmpArr = explode("?",$url); //按照&号切割 (索引count($tmpArr) -1 ,和大部分语言保持一致,便于理解和移植) $queryParts = explode('&', $tmpArr[count($tmpArr) -1]); $ret = array(); foreach ($queryParts as $param) { $item = explode('=', $param); if(count($item) == 2){ $ret [$item[0]] = $item[1]; } } return $ret; }

September 19, 2019 · 1 min · holdsky

红黑树实现 --php版本

<?php //大部分代码按照自己对算法导论的伪代码的理解编写 namespace zxszl; /* 红黑树的特性: (1)每个节点或者是黑色,或者是红色。 (2)根节点是黑色。 (3)每个叶节点(NIL)是黑色。 [注意:这里叶节点,是指为空(NIL或NULL)的子节点!] (4)如果一个节点是红色的,则它的子节点必须是黑色的。 (5)从一个节点到该节点的叶节点的所有路径上包含相同数目的黑节点。 */ //参考 https://blog.csdn.net/v_JULY_v/article/details/6105630 class RedBlackNode { public $parent;//父节点 public $left; //左子节点 public $right; //右子节点 public $isRed; //红色节点或者黑色节点 /** * 这里引入两个变量,是为了方便字典数据结构 * 其中,key作为红黑树的排序依据 */ public $key; //节点值 public $value; //节点值 public function __construct () { $this->parent = null; $this->left = null; $this->right = null; $this->isRed = true; $this->key = null; $this->value = null; } } /** * 红黑树 ,左边小节点,右边大节点 */ class RedBlackTree { /** * 深度(树高度) * @param RedBlackNode $node * @return int */ static public function depth($node) { if ($node === NULL) { return 0; } $left_d = RedBlackTree::depth($node->left); $right_d = RedBlackTree::depth($node->right); return ($left_d > $right_d ? $left_d : $right_d) + 1; } /** * 最小节点 * @return RedBlackNode 最小节点 */ static public function minNode($node) { $current = $node; if ($current !== null) { while ($current->left !== null) { $current = $current->left; } } return $current; } /** * 最大节点 * @return RedBlackNode 最大节点 */ static public function maxNode($node) { $current = $node; if ($current !== null) { while ($current->right !== null) { $current = $current->right; } } return $current; } /** * 查找指定节点 * @return RedBlackNode 节点 */ public function searchNode($key) { $current = $this->rootNode; while ($current !== NULL) { if ($current->key === $key) { return $current; } elseif ($current->key > $key) { $current = $current->left; } else { $current = $current->right; } } return null; } /** * 插入节点,若$key已经存在,则替换对应节点的$value * @return RedBlackNode 插入的节点 */ public function insertNode($key,$value) { //查找节点插入时的父亲节点 $nodeParent = null; do { $tmp = $this->rootNode; while ($tmp !== null) { $nodeParent = $tmp; if ($key === $tmp->key ) {//已经存在key,不必再插入,只要替换value就可以 $tmp->value = $value; return; } else if ( $key < $tmp->key ) { $tmp = $tmp->left; } else { $tmp = $tmp->right; } } }while(0); //创建新节点,节点为红色 $node = new RedBlackNode(); // $node->isRed = true; $node->key = $key; $node->value = $value; //插入节点 $node->parent = $nodeParent; if ($nodeParent === null) { $this->rootNode = $node; } else if ($node->key < $nodeParent->key) { $nodeParent->left = $node; } else { $nodeParent->right = $node; } //修正红黑树 $this->p_insert_fixup($node); } /** * 删除节点 */ public function deleteNode ($key) { $z = $this->searchNode($key); if ( $z !== null ) //找到$key对应的节点 { //$z //待删除节点 $y = null; $x = null; ///>>>START $z不为null,那么经过操作,$y一定不为null if ($z->left === null || $z->right === null) { $y = $z; } else { $y = RedBlackTree::minNode($z->right); //$z的最小上限 } ///<<<END if ( $y->left !== null ) { $x = $y->left; } else { $x = $y->right; } //删除节点$y if ($x !== null){ $x->parent = $y->parent; } if ($y->parent === null ) { $this->rootNode = $x; } else if ( $y === $y->parent->left ) { $y->parent->left = $x; } else { $y->parent->right = $x; } $xParent = $y->parent; //如果$y不是$z,那么用$y的信息覆盖$z,这样达到删除$z的目的 if ($y !== $z) { $z->key = $y->key; $z->value = $y->value; } //如果删除的节点是黑色,则需要修正 if ($y->isRed === false) {//$y可能是$z ,也可能是$z的最小上限 $this->p_delete_fixup($x,$xParent); } } } /** * 修正红黑树 * @param RedBlackNode node 插入的节点 */ private function p_insert_fixup($node) { while ($node->parent !== null && $node->parent->isRed === true ) //如果node的父节点是红色 (node是红色) { $grandParent = $node->parent->parent; //祖父节点,一定存在 (根据红黑树性质,红色节点一定有父节点)) if ($node->parent === $grandParent->left ) { //node的父节点是左孩子 $uncle = $grandParent->right; //case1:node的父节点是红色,且叔节点是红色 if ($uncle && $uncle->isRed === true ) { $uncle->isRed = false; $node->parent->isRed = false; $grandParent->isRed = true; $node = $grandParent; continue; //经过这一步之后,组父节点作为新节点存在(跳到case2) } //case2:node的父节点是红色,叔节点是黑色,node是其父节点的右孩子 else if ($node === $node->parent->right ) { $node = $node->parent; $this->p_left_rotate($node); } //case3:node的父节点是红色,叔节点是黑色,node是其父节点的左孩子 $node->parent->isRed = false; $grandParent->isRed = true; $this->p_right_rotate($grandParent); } else { //node的父节点是右孩子 $uncle = $grandParent->left; //case1:node的父节点是红色,且叔节点是红色 if ($uncle && $uncle->isRed === true ) { $uncle->isRed = false; $node->parent->isRed = false; $grandParent->isRed = true; $node = $grandParent; continue; //经过这一步之后,组父节点作为新节点存在(跳到case2) } //case2:node的父节点是红色,叔节点是黑色,node是其父节点的左孩子 else if ($node === $node->parent->left ) { $node = $node->parent; $this->p_right_rotate($node); } //case3:node的父节点是红色,叔节点是黑色,node是其父节点的左孩子 $node->parent->isRed = false; $grandParent->isRed = true; $this->p_left_rotate($grandParent); } } $this->rootNode->isRed = false; } /** * 修正红黑树 * @param RedBlackNode $x * @param RedBlackNode $xParent */ private function p_delete_fixup($x,$xParent) { while ( $x !== $this->rootNode && ($x ===null || $x->isRed === false ) ) { if ($x === $xParent->left ) //$x不是根节点,那么$xParent一定存在 { $w = $xParent->right; if ($w !== null ) //若为null,则$w黑色 { //case1:$x黑, 兄弟节点$w红,父节点黑 if ($w->isRed === true ) { $w->isRed = false; $xParent->isRed = true; $this->p_left_rotate($xParent); $w = $xParent->right; //在左旋处理后,$xParent->right指向的是原来兄弟结点$w的右孩子,黑色 } //case2:$x黑色, $w是黑色,且$w两个子节点都是黑色 if ( ($w->left===null || $w->left->isRed === false) && ($w->right===null || $w->right->isRed === false) ) { $w->isRed = true; $x = $xParent; $xParent = $x->parent; } else { //case3:$x黑色,$w黑色,$w左子是红色,$w右子是黑色 if ( $w->right===null || $w->right->isRed === false ) { $w->left->isRed = false; $w->isRed = true; $this->p_right_rotate($w); $w = $xParent->right; } //case4:$x黑色,$w黑色,$w右子是红色,$w左子的颜色任意 $w->isRed = $xParent->isRed; $xParent->isRed = false; if ($w->right !== null ) { $w->right->isRed = false; } $this->p_left_rotate($xParent); $x = $this->rootNode; break;//加不加break都可以,因为下次循环条件不满足 } } } else //$x是右孩子 $x不是根节点,那么$xParent一定存在 { $w = $xParent->left; if ($w !== null ) //若为null,则$w黑色 { //case1:$x黑, 兄弟节点$w红,父节点黑 if ($w->isRed === true ) { $w->isRed = false; $xParent->isRed = true; $this->p_right_rotate($xParent); $w = $xParent->left; //在右旋处理后,$xParent->left指向的是原来兄弟结点$w的左孩子,黑色 } //case2:$x黑色, $w是黑色,且$w两个子节点都是黑色 if ( ($w->left===null || $w->left->isRed === false) && ($w->right===null || $w->right->isRed === false) ) { $w->isRed = true; $x = $xParent; $xParent = $x->parent; } else { //case3:$x黑色,$w黑色,$w左子是黑色,$w右子是红色 if ( $w->left===null || $w->left->isRed === false ) { $w->right->isRed = false; $w->isRed = true; $this->p_left_rotate($w); $w = $xParent->left; } //case4:$x黑色,$w黑色,$w左子是红色,$w右子的颜色任意 $w->isRed = $xParent->isRed; $xParent->isRed = false; if ($w->left !== null ) { $w->left->isRed = false; } $this->p_right_rotate($xParent); $x = $this->rootNode; break;//加不加break都可以,因为下次循环条件不满足 } } } } if ($x !== null ) { $x->isRed = false; } } /** * 对指定节点进行左旋操作 * 左旋中的“左”,意味着“被旋转的节点将变成(自己右孩子的)一个左节点 * node right * / \ / \ * a right ======> node c * / \ / \ * b c a b * * @param RedBlackNode $node */ private function p_left_rotate($node) { $rightChild = $node->right; //右孩子 if ($rightChild === null){ //右孩子为null,左旋结束 return; } $rightChild->parent = $node->parent; //将 “node的父亲” 设为 “rightChild的父亲” if ($rightChild->parent === null) { //情况1:如果 “rightChild的父亲” 是空节点,则将rightChild设为根节点 $this->rootNode = $rightChild; } else if ($node === $node->parent->left ) { //情况2:如果 node是它父节点的左孩子,则将rightChild设为“node的父节点的左孩子” $node->parent->left = $rightChild; } else { // 情况3:(node是它父节点的右孩子) 将rightChild设为“node的父节点的右孩子” $node->parent->right = $rightChild; } $node->parent = $rightChild; //将 “node的父节点” 设为 “rightChild” $node->right = $rightChild->left; //将 “rightChild的左孩子” 设为 “node的右孩子” if ($rightChild->left !== null) { $rightChild->left->parent = $node; //将 “node” 设为 “rightChild的左孩子的父亲” } $rightChild->left = $node; //将 “node” 设为 “rightChild的左孩子” } /** * 对指定节点进行右旋操作 * 右旋中的“右”,意味着“被旋转的节点将变成(自己左孩子的)一个右节点” * left node * / \ / \ * a node <====== left c * / \ / \ * b c a b * * @param RedBlackNode $node */ private function p_right_rotate($node) { $leftChild = $node->left; //左孩子 if ($leftChild === null) { //左孩子为null,右旋结束 return; } $leftChild->parent = $node->parent; //将 “node的父节点” 设为 “leftChild的父节点” if ($leftChild->parent === null) { // 情况1:如果 “leftChild的父亲” 是空节点,则将leftChild设为根节点 $this->rootNode = $leftChild; } else if ($node === $node->parent->left ) { // 情况2:如果 node 是它父节点的左孩子,则将leftChild设为“node的父节点的左孩子” $node->parent->left = $leftChild; } else { // 情况3:如果 node 是它父节点的右孩子,则将leftChild设为“node的父节点的右孩子” $node->parent->right = $leftChild; } $node->parent = $leftChild; //将leftChild设为“node的父节点” $node->left = $leftChild->right; //将 “leftChild的右孩子” 设为"node的左孩子" if ( $leftChild->right !== null ){ $leftChild->right->parent = $node; //将node 设为 “leftChild的右孩子的父节点” } $leftChild->right = $node; //将 "node" 设为 “leftChild的右孩子” } private $rootNode; } $rbTree = new RedBlackTree(); $testN = 10000; function testInsert( $rbTree ) { global $testN; $tmpArray = array(); for ($i = 0 ; $i < $testN ; $i++) { array_push($tmpArray,$i); } shuffle($tmpArray); for ($i = 0 ; $i < $testN ; $i++) { $k = $tmpArray[$i]; $rbTree->insertNode($k,$k); } for ($i = 0 ; $i < $testN ; $i++) { $node = $rbTree->searchNode($i); if($node === null) { echo "not found $i"; } else if ($node->value !== $i ) { $value = $node->value; echo "found $i,but value is $value"; } } } function testDelete( $rbTree ) { global $testN; $tmpArray = array(); for ($i = 0 ; $i < $testN ; $i++) { array_push($tmpArray,$i); } shuffle($tmpArray); for ($i = 0 ; $i < $testN ; $i++) { $k = $tmpArray[$i]; $rbTree->deleteNode($k); } for ($i = 0 ; $i < $testN ; $i++) { $node = $rbTree->searchNode($i); if($node !== null) { echo "found $i"; } } } testInsert($rbTree); testDelete($rbTree);

September 17, 2019 · 7 min · holdsky

ubuntu18.04 php pdo : could not find driver

用PHP PDO打开数据库,出现错误 could not find driver 一个原因是没安装对应的PDO 解决方法 #查看php版本 $ php -v #安装PDO sudo apt-get install php7.3-mysql sudo apt-get install php7.3-pgsql sudo apt-get install php7.3-sqlite

September 13, 2019 · 1 min · holdsky

学习笔记:Phalcon 微应用示例

创建工程 需要先安装 Phalcon DevTools 创建Test工程 phalcon project Test 然后,只保留四个文件 Test\.htaccess (访问权限控制) Test\.htrouter.php(访问路由) Test\public\.htaccess(访问权限控制) Test\public\index.php(应用入口) 一个简单微应用的示例 将 Test\public\index.php 的内容修改成: <?php //导入Micro use Phalcon\Mvc\Micro; //创建对象 $app = new Micro(); //注册路由 //GET方法,路径为 /xxxx , 响应输出 hello xxxx $app->get("/{name}", //响应方法 function ($name){ echo "hello " . $name; }); $app->handle(); 进入 Test 目录,开启服务 phalcon serve 默认情况下开启的是8000端口,用浏览器访问 http://127.0.0.1:8000/world 应能看到输出 hello world 进一步,自定义微应用的路由 微应用使用起来很简单,我们可以在这基础上抽象出自定义的路由(这里,仅仅是演示示意,不代表一定这么做),即把 $app->getxxxx 这段拆开,定义一个路由表 <?php use Phalcon\Mvc\Micro; function func_test($name){ echo "hello " . $name; } //定义路由 $route_list = [ //GET方发 路径/xxxx 响应函数func_test ["GET", "/{name}", "func_test"], ]; $app = new Micro(); //注册路由 foreach ($route_list as $item) { if ($item[0] == "GET") { $app->get($item[1],$item[2]); } else { //错误处理; } } $app->handle(); 再次用浏览器访问 http://127.0.0.1:8000/world,看看效果

September 12, 2019 · 1 min · holdsky