damoncy / blog Goto Github PK
View Code? Open in Web Editor NEW博客分享
博客分享
二叉树是每个结点最多有两个子树的树结构。通常子树被称作“左子树”(left subtree)和“右子树”(right subtree)。二叉树常被用于实现二叉查找树和二叉堆。
class BinaryTree {
constructor() {
this.root = null;
}
node(key) {
return {
key: key,
right: null,
left: null
}
}
insert(parentNode, key) {
if (this.root === null) {
const node = this.node(key);
return this.root = node;
}
// 右子树
if (key > parentNode.key) {
if (parentNode.right === null) {
const node = this.node(key);
parentNode.right = node;
} else {
this.insert(parentNode.right, key);
}
} else {
// 左子树
if(parentNode.left === null) {
const node = this.node(key);
parentNode.left = node;
} else {
this.insert(parentNode.left, key);
}
}
}
getRoot() {
return this.root;
}
// 前序遍历
preTraverse(node, collect) {
if (node.key !== null) {
collect.push(node.key);
if (node.left) {
this.preTraverse(node.left, collect)
}
if(node.right) {
this.preTraverse(node.right, collect);
}
}
}
// 中序遍历
inorderTraverse(node, collect) {
if (node.left !== null) {
this.inorderTraverse(node.left, collect)
}
if(node.key !==null ) {
collect.push(node.key);
}
if(node.right) {
this.inorderTraverse(node.right, collect)
}
}
// 后续遍历
postTraverse(node, collect) {
if (node.left) {
this.postTraverse(node.left, collect);
}
if(node.right) {
this.postTraverse(node.right, collect);
}
if(node.key) {
collect.push(node.key);
}
}
// 获取最小值
minNode(node){
if(node.left !== null) {
this.minNode(node.left)
} else {
console.log('最小值:', node.key);
}
}
// 获取最大值
maxNode(node) {
if(node.right !== null) {
this.maxNode(node.right)
} else {
console.log('最大值:', node.key);
}
}
// 查找指定值
searchNode(node, key, collect) {
if(node === null) {
return false
}
if(key < node.key) {
collect.push(node.key);
this.searchNode(node.left, key, collect);
} else if (key > node.key){
collect.push(node.key);
this.searchNode(node.right, key, collect)
} else {
collect.push(node.key);
}
}
}
const binaryTrees = new BinaryTree()
const nodes = [8, 3, 10, 1, 5, 14, 4, 6, 13];
nodes.forEach(key => {
// (为了方便理解)每次将新数据插入到 最新的树(binaryTress.getRoot())中
binaryTrees.insert(binaryTrees.getRoot(), key)
});
// 树
console.log(`当前树:`, binaryTrees.getRoot())
// 前序遍历
const preMap = [];
binaryTrees.preTraverse(binaryTrees.getRoot(), preMap);
console.log(`前序遍历: ${preMap}`)
// 中序遍历
const inorderMap = [];
binaryTrees.preTraverse(binaryTrees.getRoot(), inorderMap);
console.log(`中序遍历: ${inorderMap}`)
// 后续遍历
const postMap = [];
binaryTrees.postTraverse(binaryTrees.getRoot(), postMap);
console.log(`后序遍历: ${postMap}`)
// 最小值
binaryTrees.minNode(binaryTrees.getRoot())
// 最大值
binaryTrees.maxNode(binaryTrees.getRoot())
// 查找指定值
const searchCollect = [];
const targetKey = 4;
binaryTrees.searchNode(binaryTrees.getRoot(), targetKey, searchCollect);
// 查找路径中最后一个值为指定值,则存在
console.log(`查找指定值: ${targetKey},结果:${searchCollect.unshift() === targetKey ? '存在': '不存在'},查询路径:${searchCollect}`)
两个基本概念容器与镜像:
容器是安装在docker环境中的。所以需要先安装docker。
注意:如果是windows电脑,需要购买支持虚拟化的版本,如Win10专业版,Win10家庭版是不行的。
三步得到一个虚拟机container
我们安装上述三个步骤来完成:
# Dockerfile文件 内部使用的是shell命令
# 使用指定版的node镜像
FROM node:10
# 程序运行的端口
EXPOSE 8888
执行命令:
docker image build ./ -t hello-docker:1.0.0
解释:docker image build ./ -t hello-docker:1.0.0
基于 ./
当前目录打包一个镜像,镜像的名字叫 hello-docker
,镜像的版本是1.0.0
,该命令会根据当前目录下的Dockerfile生成镜像
命令执行完成后会看到如下的信息:
![image-20191218221304757](/Users/wuxi/Library/Application Support/typora-user-images/image-20191218221304757.png)
查看我们当前创建的镜像:(所有镜像通过docker统一管理的)
docker image -a // -a 展示所有
![image-20191218222139509](/Users/wuxi/Library/Application Support/typora-user-images/image-20191218222139509.png)
运行镜像:
docker run -t -i 9378fafcdb31 /bin/bash
![image-20191218223827758](/Users/wuxi/Library/Application Support/typora-user-images/image-20191218223827758.png)
docker run -t -i 9378fafcdb31 /bin/bash
执行了
/bin/bash
启动了容器的/bin/bash
,此时通过bash shell 执行命令。
delegates是由TJ大神开发的,可以方便快捷的使用设计模式中的委托模式,即外层暴露对象将请求委托给内部对象进行处理。
基本委托方法:
const delegates = require('delegates');
const animal = {
cat: {
name: '花花',
age: 1,
address: '北京',
weight: 1,
say() {
console.log('你好 花花');
}
}
}
delegates(animal, 'cat')
.getter('name')
.setter('age')
.access('address')
.method('say')
.fluent('weight')
// getter 只能获取
console.log(animal.name); // 花花
// getter 不能被设置属性
animal.name = '花花2';
console.log(animal.name); // 赋值 花花2 不成功,仍然输出:花花
// setter
console.log(animal.age) // undefined setter只能赋值操作,所以读取值的时候为undefined
// access
animal.address = '重庆'; // 使用了access方法,既能 赋值也能 读取值(赋值animal.address时代理到了animal.cat.address)
console.log(animal.address); // 重庆
console.log(animal.cat.address); // 重庆
// method
animal.say(); // 你好 花花 (相当于执行了 animal.cat.say方法)
animal.cat.say(); // 你好 花花
// fluent方法,可以通过函数的方式设置属性值
console.log(animal.weight(2).weight()) // 2
console.log(animal.weight) // [Function] fluent代理成了一个方法
console.log(animal.cat.weight) // 2
console.log(animal);
/*{ cat:
{ name: '花花',
age: 1,
address: '重庆',
weight: 2,
say: [Function: say] },
name: [Getter],
age: [Setter],
address: [Getter/Setter],
say: [Function],
weight: [Function] }*/
实际使用的是对象原型的 __defineGetter__
方法
delegates(animal, 'cat')
.getter('name')
// 相当于
Delegator.prototype.getter = function(name){
animal.__defineGetter__(name, function(){
return this.cat[name];
});
};
通过__defineGetter__
在animal上定义getter方法,相当于在animal上添加了一个getter方法,通过getter方法代理去访问animal.cat上的属性
/*
此时
animal = {
cat: {
name: '花花'
},
name: [Getter], // 在外层添加getter方法,实际访问的还是内部的cat.name
}
*/
现在一般都不使用 __defineGetter__
去定义getter方法,可以直接通过get定义,如下方式
/*
此时
animal = {
cat: {
name: '花花'
},
get name() {
return this.cat.name //
},
}
*/
delegates(animal, 'cat')
.setter('age')
// 相当于
Delegator.prototype.setter = function(name){
animal.__defineSetter__(name, function(val){
return this.cat[name] = val;
});
};
使用 对象的原型方法 __defineSetter__
与getter类似
相当于同时给代理对象添加getter、setter方法代理访问目标对象
Delegator.prototype.access = function(name){
return this.getter(name).setter(name); // 在放回的this上再添加setter方法
};
给代理对象添加方法(方法为目标属性的名)(与getter setter不同)
delegates(animal, 'cat')
.fluent('weight')
Delegator.prototype.fluent = function (name) {
var proto = this.proto;
var target = this.target;
this.fluents.push(name);
proto[name] = function(val){
if ('undefined' != typeof val) {
this[target][name] = val;
return this;
} else {
return this[target][name];
}
};
return this;
};
/*
animal = {
cat: {
weight: 1
},
weight(val) {
if ('undefined' != typeof val) {
this.cat.weight = val;
return this;
} else {
return this.cat.weight;
}
}
}
*/
异步方式:
spawn
exec
execFile
fork
同步方式
child_process.spawn(command[, args][, options])
command: 要执行的指令
args: 传递参数
options: 配置项
const {spawn} = require('child_process');
const child = spawn('ls');
执行时控制台并没输出相关信息,这是为什么呢?
子进程有自己的stdio流(stdin, stdout, stderr)
,在执行子进程时,当前进程是看不到子进程的输出信息。1、如果希望看到输出信息,可以通过子进程的stdout与当前进程的stdout之间建立管道实现。
child.stdout.pipe(process.stdout)
2、可以通过监听事件的方式(子进程的stdio流实现了EventEmitter API,所以可以通过监听事件的方式)
// 监听子进程stdio流
child.stdout.on('data', function(data) {
process.stdout.write(data);
})
3、还可以通过子进程和当前进程公用stdio流的方式实现
const child = spawn('ls', {
stdio: 'inhrite'
})
stdio选项用户配置父进程和子进程之间建立的管道,由于stdio管道有三个(stdin、stdout、stderr)因此stdio的三个可能的值是数组的简写。
['pipe', 'pipe', 'pipe']
默认值['ingore', 'ingore', 'ingore']
[process.stdin, process.stdout, process.stderr]
(相当于直接使用父进程stdio)如果我们执行 spawn('ls -a')
就会报错,因为ls -a
相当于创建了连个spawn命令方式。可以使用 exec创建子shell,所以可以直接执行shell管道命令。spawn采用流的方式来输出命令的执行结果,而exec是将命令的执行结果缓存起来统一放在回调函数的参数里,因此exec只适用于命令执行结果数据小的情况
spawn也可以通过配置shell option的方式来创建子shell进而支持管道命令:
const { spawn } = require('child_process');
const child = spawn('ls -l | wc -l', {
shell: true
})
child.stdout.pipe(process.stdout);
cwd 更改命令的执行目录
env用于指定子进程的环境变量(如不指定的化,默认获取当前进程的环境变量)
// test.js
// 指定env环境变量,会覆盖默认的环境变量
spawn('echo $NODE_TEST $NODE_ENV', {
shell: true,
stdio: 'inhrit',
cwd: '/usr',
env: {
NODE_TEST: 'abc'
}
})
// 执行
$: NODE_ENV=123 node test.js
// 输出结果 abc
detachead 用于将子进程与父进程断开连接
execFile与exec不同,execFile通常用于执行文件
,而且并不会创建子shell环境
fork方法是spawn方法的一个特例,fork用于执行js文件创建Node.js子进程。而fork方式创建的子进程与父进程之间建立了IPC通信管道,因此子进程和父进程之间可以通过send的方式发送消息。
(fork方式创建的子进程与父进程是完全独立的,它拥有单独的内存,单独的V8实例,因此不推荐创建很多的Node.js子进程)
fork方式的父子进程之间的通信:
// parent.js
const { fork } = require('child_process')
const forked = fork('child.js');
forked.on('message', (msg) => {
console.log('Message from child', msg);
})
forked.send({ name: 'damon' })
// child.js
process.on('message', (msg) => {
console.log('Message from parent:', msg);
})
let counter = 0;
setInterval(() => {
process.send({ counter: counter++ });
}, 1000);
node parent.js
// 输出结果
Message from parent: { hello: 'world' }
Message from child { counter: 0 }
Message from child { counter: 1 }
Message from child { counter: 2 }
Message from child { counter: 3 }
Message from child { counter: 4 }
Message from child { counter: 5 }
前述的几种方式创建的子进程都是实现了EventEmitter, 因此可以对进程进行监听
常用的事件:
close: 当子进程的stdio流关闭的时候触发,
exit :子进程结束时触发
error:
无法创建子进程
无法结束进程
给进程发送消息失败
当代码执行出错的时候,error事件并不会触发,exit事件会触发,code为非0的异常退出码
message
close与exit事件的回调函数有两个参数code和signal, code代表子进程最终的退出码。如果子进程是由于接收到signal信号终止的话,signal会记录子进程接受的signal值。
const { exec } = require('child_process');
const child = exec('ls -l', {
timeout: 300
});
child.on('exit', function(code, signal) {
console.log(code);
console.log(signal);
});
// 正常退出 输出结果
0
null
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.