上药三品,神与气精

曾因酒醉鞭名马 生怕情多累美人


  • 首页

  • 关于

  • 分类

  • 标签

  • 归档

  • 搜索

红黑树详细

发表于 2019-04-05 | 阅读次数:
字数统计: 315 | 阅读时长 ≈ 1

红黑树是一种含有红黑结点并能自平衡的二叉查找树。它必须满足下面性质:

性质1:每个节点要么是黑色,要么是红色。

性质2:根节点是黑色。

性质3:每个叶子节点(NIL)是黑色。

性质4:每个红色结点的两个子结点一定都是黑色。

性质5:任意一结点到每个叶子结点的路径都包含数量相同的黑结点。

从性质5又可以推出:

性质5.1:如果一个结点存在黑子结点,那么该结点肯定有两个子结点

红黑树能自平衡,它靠的是什么?三种操作:左旋、右旋和变色。

左旋:以某个结点作为支点(旋转结点),其右子结点变为旋转结点的父结点,右子结点的左子结点变为旋转结点的右子结点,左子结点保持不变。

右旋:以某个结点作为支点(旋转结点),其左子结点变为旋转结点的父结点,左子结点的右子结点变为旋转结点的左子结点,右子结点保持不变。

变色:结点的颜色由红变黑或由黑变红。

图的两种遍历

发表于 2019-04-05 | 分类于 leetcode | 阅读次数:
字数统计: 64 | 阅读时长 ≈ 1

深度优先搜索使用递归的方式需要栈结构辅助实现

广度优先搜索需要使用队列辅助实现

连通图 任意顶点出发可以访问图中的所有顶点


图的深度搜索

字符串题

发表于 2019-04-05 | 分类于 leetcode | 阅读次数:
字数统计: 594 | 阅读时长 ≈ 3

125 验证回文串

左指针 右指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

class Solution {
public boolean isPalindrome(String s) {
if(s.length() == 0)
return true;
int l = 0, r = s.length() - 1;
while(l < r){
//确定指定的字符是否为字母或数字
if(!Character.isLetterOrDigit(s.charAt(l))){
l++;
}else if(!Character.isLetterOrDigit(s.charAt(r))){
r--;
}else{
if(Character.toLowerCase(s.charAt(l)) != Character.toLowerCase(s.charAt(r)))
return false;
l++;
r--;
}
}
return true;
}
}

131 分割回文串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

class Solution {
List<List<String>> res = new ArrayList<>();

public List<List<String>> partition(String s) {
if(s==null||s.length()==0)
return res;
dfs(s,new ArrayList<String>(),0);
return res;
}

public void dfs(String s,List<String> remain,int left){
if(left==s.length()){ //判断终止条件
res.add(new ArrayList<String>(remain)); //添加到结果中
return;
}
for(int right=left;right<s.length();right++){ //从left开始,依次判断left->right是不是回文串
if(isPalindroom(s,left,right)){ //判断是否是回文串
remain.add(s.substring(left,right+1)); //添加到当前回文串到list中
dfs(s,remain,right+1); //从right+1开始继续递归,寻找回文串
remain.remove(remain.size()-1); //回溯,从而寻找更长的回文串
}
}
}
/**
* 判断是否是回文串
*/
public boolean isPalindroom(String s,int left,int right){
while(left<right&&s.charAt(left)==s.charAt(right)){
left++;
right--;
}
return left>=right;
}
}

139 单词拆分

动态规划

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

class Solution {
public boolean wordBreak(String s, List<String> wordDict) {
int n = s.length();
int max_length=0;
for(String temp:wordDict){
max_length = temp.length() > max_length ? temp.length() : max_length;
}
// memo[i] 表示 s 中以 i - 1 结尾的字符串是否可被 wordDict 拆分
boolean[] memo = new boolean[n + 1];
memo[0] = true;
for (int i = 1; i <= n; i++) {
for (int j = i-1; j >= 0 && max_length >= i - j; j--) {
if (memo[j] && wordDict.contains(s.substring(j, i))) {
memo[i] = true;
break;
}
}
}
return memo[n];
}
}

344 反转字符串

从两头往中间走

1
2
3
4
5
6
7
8
9
10
11
12
13
14


class Solution {
public:
string reverseString(string s) {
int i = 0, j = s.size() - 1;
while (i < j){
swap(s[i],s[j]);
i++;
j--;
}
return s;
}
};

字符串转换为整数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19


public class Solution {
public int StrToInt(String str) {
if (str == null || str.length() == 0)
return 0;
boolean isNegative = str.charAt(0) == '-';
int ret = 0;
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (i == 0 && (c == '+' || c == '-')) /* 符号判定 */
continue;
if (c < '0' || c > '9') /* 非法输入 */
return 0;
ret = ret * 10 + (c - '0');
}
return isNegative ? -ret : ret;
}
}

设计模式之责任链

发表于 2019-04-03 | 阅读次数:
字数统计: 382 | 阅读时长 ≈ 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84

# encoding: utf-8
"""
责任链模式
使多个对象都以机会处理请求, 从而避免请求的发送者和接受者之间的耦合关系
将这个对象连成一条链, 沿着这条链传递请求, 直到有一个对象处理它为止
- 可以随意增加或修改处理一个请求的链式结构
"""

from abc import ABCMeta, abstractmethod


class Handler(object):
"""
定义一个处理请求的接口
"""
__metaclass__ = ABCMeta

def __init__(self):
self.__successor = None

@property
def successor(self):
return self.__successor

@successor.setter
def successor(self, value):
self.__successor = value

@abstractmethod
def handle_request(self, request):
pass


class ConcreteHandlerA(Handler):
"""
具体处理类, 处理它所负责的请求
如果可以处理该请求, 处理之, 否则转给后继者
"""

def handle_request(self, request):
if 0 <= request < 10:
print "%s process %s" % (self.__class__.__name__, request)
else:
self.successor.handle_request(request)


class ConcreteHandlerB(Handler):
"""
具体处理类, 处理它所负责的请求
如果可以处理该请求, 处理之, 否则转给后继者
"""

def handle_request(self, request):
if 10 <= request < 20:
print "%s process %s" % (self.__class__.__name__, request)
else:
self.successor.handle_request(request)


class ConcreteHandlerC(Handler):
"""
具体处理类, 处理它所负责的请求
如果可以处理该请求, 处理之, 否则转给后继者
"""

def handle_request(self, request):
if 20 <= request < 30:
print "%s process %s" % (self.__class__.__name__, request)
else:
self.successor.handle_request(request)


if __name__ == '__main__':
h1 = ConcreteHandlerA()
h2 = ConcreteHandlerB()
h3 = ConcreteHandlerC()

h1.successor = h2
h2.successor = h3

for req in [2, 14, 22]:
print req
h1.handle_request(req)

sanic源码阅读

发表于 2019-04-02 | 阅读次数:
字数统计: 2.2k | 阅读时长 ≈ 8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33


## Sanic源码阅读:基于0.1.2

`Sanic`是一个可以使用`async/await`语法编写项目的异步非阻塞框架,它写法类似于`Flask`,但使用了异步特性,而且还使用`uvloop`作为事件循环,其底层使用的是`libuv`,从而使 `Sanic`的速度优势更加明显。

本章,我将和大家一起看看`Sanic`里面的运行机制是怎样的,它的`Router Blueprint`等是如何实现的。

如果你有以下的需求:

- 想深入了解Sanic,迫切想知道它的运行机制
- 直接阅读源码,做一些定制
- 学习

将Sanic-0.1.2阅读完后的一些建议,我觉得你应该有以下基础再阅读源码才会理解地比较好:

- 理解[装饰器](https://github.com/howie6879/Sanic-For-Pythoneer/blob/master/docs/part2/%E9%99%84%E5%BD%95%EF%BC%9A%E5%85%B3%E4%BA%8E%E8%A3%85%E9%A5%B0%E5%99%A8.md),见附录
- 理解协程

Sanic-0.1.2 的核心文件如下:
``` shell
.
├── __init__.py
├── blueprints.py
├── config.py
├── exceptions.py
├── log.py
├── request.py
├── response.py
├── router.py
├── sanic.py
├── server.py
└── utils.py

通过运行下面的示例,这些文件都会被我们看到它的作用,拭目以待吧,为了方便诸位的理解,我已将我注解的一份Sanic代码上传到了github,见sanic_annotation。

simple_server.py

让我们从simple_server开始吧,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13

from sanic_0_1_2.src import Sanic
from sanic_0_1_2.src.response import json

app = Sanic(__name__)


@app.route("/")
async def test(request):
return json({"test": True})


app.run(host="0.0.0.0", port=8000)

或许你直接把sanic_annotation项目直接clone到本地比较方便调试+理解:

1
2
git clone https://github.com/howie6879/sanic_annotation
cd sanic_annotation/sanic_0_1_2/examples/

那么,现在一切准备就绪,开始阅读吧。

前两行代码导入包:

  • Sanic:构建一个 Sanic 服务必须要实例化的类
  • json:以json格式返回结果,实际上是HTTPResponse类,根据实例化参数content_type的不同,构建不同的实例,如:
    • text:content_type="text/plain; charset=utf-8"
    • html:content_type="text/html; charset=utf-8"

实例化一个Sanic对象,app = Sanic(__name__),可见sanic.py,我已经在这个文件里面做了一些注释,这里也详细说下Sanic类:

  • route():装饰器,构建uri和视图函数的映射关系,调用Router().add()方法

  • exception():装饰器,和上面差不多,不过针对的是错误处理类Handler

  • middleware():装饰器,针对中间件

  • register_blueprint():注册视图的函数,接受第一个参数是视图类blueprint,再调用该类下的register方法实现将此蓝图下的route、exception、middleware统一注册到app.route、app.exception、app.exception

  • handle_request():这是一个很重要的异步函数,当服务启动后,如果客户端发来一个有效的请求,会自动执行 on_message_complete函数,该函数的目的是异步调用 handle_request函数,handle_request函数会回调write_response函数,write_response接受的参数是此uri请求对应的视图函数,比如上面demo中,如果客户端请求’/‘,那么这里write_response就会接受json({"test": True}),然后进一步处理,再返回给客户端

  • run():Sanic服务的启动函数,必须执行,实际上会继续调用server.serve函数,详情下面会详细讲

  • stop():终止服务

其实上面这部分介绍已经讲了Sanic基本的运行逻辑,如果你理解了,那下面的讲解对你来说是轻轻松松,如果不怎么明白,也不要紧,这是只是一个大体的介绍,跟着步骤来,也很容易理解,继续看代码:

1
2
3
4
# 此处将路由 / 与视图函数 test 关联起来
@app.route("/")
async def test(request):
return json({"test": True})

app.route,上面介绍过,随着Sanic服务的启动而启动,可定义参数uri, methods

目的是为url的path和视图函数对应起来,构建一对映射关系,本例中Sanic.router类下的Router.routes = []

会增加一个名为Route的namedtuple,如下:

1
[Route(handler=<function test at 0x10a0f6488>, methods=None, pattern=re.compile('^/$'), parameters=[])]

看到没,uri '/' 和视图函数test对应起来了,如果客户端请求'/',当服务器监听到这个请求的时候,handle_request可以通过参数中的request.url来找到视图函数test并且执行,随即生成视图返回

那么这里write_response就会接受视图函数test返回的json({"test": True})

说下Router类,这个类的目的就是添加和获取路由对应的视图函数,把它想象成dict或许更容易理解:

  • add(self, uri, methods, handler):添加一个映射关系到self.routes
  • get(self, request):获取request.url对应的视图函数

最后一行,app.run(host="0.0.0.0", port=8000),Sanic 下的run函数,启动一个http server,主要是启动run里面的serve函数,参数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

try:
serve(
host=host,
port=port,
debug=debug,
# 服务开始后启动的函数
after_start=after_start,
# 在服务关闭前启动的函数
before_stop=before_stop,
# Sanic(__name__).handle_request()
request_handler=self.handle_request,
# 默认读取Config
request_timeout=self.config.REQUEST_TIMEOUT,
request_max_size=self.config.REQUEST_MAX_SIZE,
)
except:
pass

让我们将目光投向server.py,这也是Sanic框架的核心代码:

  • serve():里面会创建一个TCP服务的协程,然后通过loop.run_forever()运行这个事件循环,以便接收客户端请求以及处理相关事件,每当一个新的客户端建立连接服务就会创建一个新的Protocol实例,接受请求与返回响应离不开其中的HttpProtocol,里面的函数支持接受数据、处理数据、执行视图函数、构建响应数据并返回给客户端

  • HttpProtocol:asyncio.Protocol的子类,用来处理与客户端的通信,我在server.py里写了对应的注释

至此,Sanic 服务启动了

不要小看这一个小小的demo,执行一下,竟然涉及到下面这么多个文件,让我们总结一下:

  • sanic.py
  • server.py
  • router.py
  • request.py
  • response.py
  • exceptions.py
  • config.py
  • log.py

除去__init__.py,Sanic项目一共就10个文件,这个小demo不显山不露水地竟然用到了8个,虽然其中几个没有怎么用到,但也足够说明,你如果理解了这个demo,Sanic的运行逻辑以及框架代码你已经了解地很深入了

blueprints.py

这个例子看完,我们就能轻易地明白什么是blueprints,以及blueprints的运行方式,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

from sanic_0_1_2.src import Sanic
# 引入Blueprint
from sanic_0_1_2.src import Blueprint
from sanic_0_1_2.src.response import json, text

app = Sanic(__name__)
blueprint = Blueprint('name', url_prefix='/my_blueprint')
blueprint2 = Blueprint('name2', url_prefix='/my_blueprint2')


@blueprint.route('/foo')
async def foo(request):
return json({'msg': 'hi from blueprint'})


@blueprint2.route('/foo')
async def foo2(request):
return json({'msg': 'hi from blueprint2'})


app.register_blueprint(blueprint)
app.register_blueprint(blueprint2)

app.run(host="0.0.0.0", port=8000, debug=True)

让我们从这两行开始:

1
2
3

blueprint = Blueprint('name', url_prefix='/my_blueprint')
blueprint2 = Blueprint('name2', url_prefix='/my_blueprint2')

显然,blueprint以及blueprint2是Blueprint根据不同的参数生成的不同的实例对象,接下来要干嘛?没错,分析blueprints.py:

  • BlueprintSetup:蓝图注册类
    • add_route:添加路由到app
    • add_exception:添加对应抛出的错误到app
    • add_middleware:添加中间件到app
  • Blueprint:蓝图类,接收两个参数:name(蓝图名称) url_prefix 该蓝图的url前缀
    • route:路由装饰器,将会生成一个匿名函数到self.deferred_functions列表里稍后一起处理注册到app里
    • middleware:同上
    • exception:同上
    • record:注册一个回调函数到self.deferred_functions列表里面,
    • make_setup_state:实例化BlueprintSetup
    • register:注册视图,实际就是注册route、middleware、exception到app,此时会利用make_setupstate返回的BlueprintSetup示例进行对于的add*一系列操作,相当于Sanic().route()效果

请看下route和register函数,然后再看下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 生成一个匿名函数到self.deferred_functions列表里 包含三个参数 handler(foo), uri, methods
@blueprint.route('/foo')
async def foo(request):
return json({'msg': 'hi from blueprint'})


@blueprint2.route('/foo')
async def foo2(request):
return json({'msg': 'hi from blueprint2'})

# 上一个例子说过这个函数,Sanic().register_blueprint() 注册蓝图
app.register_blueprint(blueprint)
app.register_blueprint(blueprint2)

怎么样,现在来看,是不是很轻松,这一行app.run(host="0.0.0.0", port=8000, debug=True)服务启动代码不用多说吧?

总结

看到这里,相信你已经完全理解了Sanic的运行机制,虽然还有middleware&exception的注册以及调用机制没讲,但这和route的运行机制一样,如果你懂了route那么这两个也很简单。

如果诸位一遍没怎么看明白,这里我建议可以多看几遍,多结合编辑器Debug下源码,坚持下来,会发下Sanic真的很简单,当然,这只是第一个小版本的Sanic,和目前的版本相比,不论是代码结构的复杂程度以及功能对比,都有很大差距,毕竟,Sanic一直在开源工作者的努力下,慢慢成长。

```

1…222324…109
John Cheung

John Cheung

improve your python skills

543 日志
33 分类
45 标签
RSS
GitHub Email
© 2020 John Cheung
本站访客数:
|
主题 — NexT.Pisces v5.1.4
博客全站共226.3k字