-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Your Name
committed
Dec 28, 2023
0 parents
commit 08380dd
Showing
140 changed files
with
9,066 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# These are supported funding model platforms | ||
|
||
github: [PegasusWang] | ||
custom: ["https://www.paypal.me/pegasuswang"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# media | ||
*.mp4 | ||
*.mov | ||
*.avi | ||
|
||
|
||
# python | ||
__pycache__/ | ||
*.py[cod] | ||
*.pyc | ||
*$py.class | ||
.python-version | ||
|
||
|
||
# vim | ||
.vimrc | ||
.lvimrc | ||
.*.sw[a-z] | ||
*.un~ | ||
Session.vim | ||
|
||
# cache | ||
.cache | ||
.tmp | ||
.idea | ||
|
||
# mkdocs | ||
site/ | ||
|
||
# vscode | ||
.vscode/ | ||
|
||
# pytest | ||
.pytest_cache/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
MIT License | ||
|
||
Copyright (c) 2019 PegasusWang | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
push: | ||
git push origin master | ||
|
||
serve: | ||
mkdocs serve | ||
|
||
publish: | ||
git push origin master | ||
mkdocs gh-deploy |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# 什么是算法和数据结构? | ||
|
||
程序 = 算法 + 数据结构 | ||
|
||
算法(Algorithm):是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,算法代表着用系统的方法描述解决问题的策略机制。也就是说,能够对一定规范的输入,在有限时间内获得所要求的输出。 | ||
|
||
数据结构(Data Structures):是计算机存储和组织数据的一种方式,可以用来高效地处理数据。 | ||
|
||
- # QA | ||
- 你了解 redis 吗,你知道它有哪几个常用的数据结构吗?你知道它的底层实现方式吗? | ||
- [redis](https://www.cnblogs.com/powertoolsteam/p/redis.html) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
# Python 一切皆对象(面向对象编程) | ||
|
||
|
||
在后面实现新的数据类型时,使用 python 的 class 实现,它包含属性和方法。 | ||
属性一般是使用某种特定的数据类型,而方法一般是对属性的操作。后续实例不会使用继承等特性。 | ||
|
||
|
||
# 什么是抽象数据类型 ADT | ||
|
||
实际上 python 内置的 list 就可以看成一种抽象数据类型。 | ||
|
||
ADT: Abstract Data Type,抽象数据类型,我们在组合已有的数据结构来实现一种新的数据类型, ADT 定义了类型的数据和操作。 | ||
|
||
我们以抽象一个背包(Bag) 数据类型来说明,背包是一种容器类型,我们可以给它添加东西,也可以移除东西,并且我们想知道背包里 | ||
有多少东西。于是我们可以定义一个新的数据类型叫做 Bag(data;method). | ||
|
||
```py | ||
class Bag: | ||
""" 背包类型 """ | ||
pass | ||
``` | ||
|
||
|
||
# 实现一个 Bag ADT | ||
视频中我们将使用 python 的 class 来实现一个新的容器类型叫做 Bag。 | ||
|
||
|
||
# 实现 ADT 我们应该注意什么? | ||
- 如何选用恰当的数据结构作为存储? | ||
- 选取的数据结构能否满足 ADT 的功能需求 | ||
- 实现效率如何? | ||
|
||
|
||
# QA: | ||
- python 的魔术方法`__len__` ,方法 | ||
- 使用 pytest 运行单元测试,保证我们实现的数据结构和算法是正确的。 | ||
|
||
# 延伸阅读: | ||
|
||
[数据结构与算法--ADT](http://www.atjiang.com/data-structures-using-python-ADT/) | ||
|
||
[http://www.nhu.edu.tw/~chun/CS-ch12-Abstract%20Data%20Types.pdf](http://www.nhu.edu.tw/~chun/CS-ch12-Abstract%20Data%20Types.pdf) | ||
|
||
[pytest](https://www.jianshu.com/p/932a4d9f78f8) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
# coding: utf8 | ||
|
||
|
||
class Bag(object): | ||
|
||
def __init__(self, maxsize=10): | ||
self.maxsize = maxsize | ||
self._items = list() | ||
|
||
def add(self, item): | ||
if len(self) >= self.maxsize: | ||
raise Exception('Full') | ||
self._items.append(item) | ||
|
||
def remove(self, item): | ||
self._items.remove(item) | ||
|
||
def __len__(self): | ||
return len(self._items) | ||
|
||
def __iter__(self): | ||
for item in self._items: | ||
yield item | ||
|
||
|
||
def test_bag(): | ||
bag = Bag() | ||
|
||
bag.add(1) | ||
bag.add(2) | ||
bag.add(3) | ||
|
||
assert len(bag) == 3 | ||
|
||
bag.remove(3) | ||
assert len(bag) == 2 | ||
|
||
for i in bag: | ||
print(i) | ||
|
||
|
||
if __name__ == '__main__': | ||
test_bag() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
# 线性结构 | ||
本节我们从最简单和常用的线性结构开始,并结合 Python 语言本身内置的数据结构和其底层实现方式来讲解。 | ||
虽然本质上数据结构的思想是语言无关的,但是了解 Python 的实现方式有助于你避免一些坑。 | ||
|
||
我们会在代码中注释出操作的时间复杂度。 | ||
|
||
|
||
# 数组 array | ||
|
||
数组是最常用到的一种线性结构,其实 python 内置了一个 array 模块,但是大部人甚至从来没用过它。 | ||
Python 的 array 是<span style="border-bottom:2px solid black;">内存连续</span>、存储的都是<span style="border-bottom:2px solid black;">同一数据类型</span>的结构,而且只能存数值和字符。 | ||
|
||
array 的文档:https://docs.python.org/2/library/array.html | ||
|
||
推荐用 numpy.array) | ||
|
||
本章最后用 list 来实现一个固定长度、并且支持所有 Python 数据类型的数组 Array. | ||
|
||
|
||
# 列表 list | ||
如果你学过 C++,list 其实和 C++ STL(标准模板库)中的 vector 很类似,它可能是你的 Python 学习中使用最频繁的数据结构之一。 | ||
这里我们不再去自己实现 list,因为这是个 Python 提供的非常基础的数据类型,我会在视频中讲解它的工作方式和内存分配策略, | ||
避免使用过程中碰到一些坑。当然如果你有毅力或者兴趣的了解底层是如何实现的,可以看看 cpython 解释器的具体实现。 | ||
[O(1)](http://gongsichuang.com/news/post/TygxKeS7gOS5iOaEj+aAnQ==.html#:~:text=O%20%281%29%E6%98%AF%E6%9C%80%E4%BD%8E%E7%9A%84%E6%97%B6%E7%A9%BA%E5%A4%8D%E6%9D%82%E5%BA%A6%EF%BC%8C%E4%B9%9F%E5%B0%B1%E6%98%AF%E8%80%97%E6%97%B6%2F%E8%80%97%E7%A9%BA%E9%97%B4%E4%B8%8E%E8%BE%93%E5%85%A5%E6%95%B0%E6%8D%AE%E5%A4%A7%E5%B0%8F%E6%97%A0%E5%85%B3%EF%BC%8C%E6%97%A0%E8%AE%BA%E8%BE%93%E5%85%A5%E6%95%B0%E6%8D%AE%E5%A2%9E%E5%A4%A7%E5%A4%9A%E5%B0%91%E5%80%8D%EF%BC%8C%E8%80%97%E6%97%B6%2F%E8%80%97%E7%A9%BA%E9%97%B4%E9%83%BD%E4%B8%8D%E5%8F%98%E3%80%82,%E5%93%88%E5%B8%8C%E7%AE%97%E6%B3%95%E5%B0%B1%E6%98%AF%E5%85%B8%E5%9E%8B%E7%9A%84O%20%281%29%E6%97%B6%E9%97%B4%E5%A4%8D%E6%9D%82%E5%BA%A6%EF%BC%8C%E6%97%A0%E8%AE%BA%E6%95%B0%E6%8D%AE%E8%A7%84%E6%A8%A1%E5%A4%9A%E5%A4%A7%EF%BC%8C%E9%83%BD%E5%8F%AF%E4%BB%A5%E5%9C%A8%E4%B8%80%E6%AC%A1%E8%AE%A1%E7%AE%97%E5%90%8E%E6%89%BE%E5%88%B0%E7%9B%AE%E6%A0%87%EF%BC%88%E4%B8%8D%E8%80%83%E8%99%91%E5%86%B2%E7%AA%81%E7%9A%84%E8%AF%9D%EF%BC%89%E3%80%82) | ||
|
||
操作 | 平均时间复杂度 | | ||
--------------------------------------|----------------| | ||
list[index] | O(1) | | ||
list.append | O(1) | | ||
list.insert | O(n) | | ||
list.pop(index), default last element | O(1) | | ||
list.remove | O(n) | | ||
|
||
 | ||
|
||
# 用 list 实现 Array ADT | ||
讲完了 list 让我们来实现一个定长的数组 Array ADT,在其他一些语言中,内置的数组结构就是定长的。 | ||
这里我们会使用 list 作为 Array 的一个成员(代理)。具体请参考视频讲解和代码示例,后边我们会使用到这个 Array 类。 | ||
|
||
|
||
# 小问题 | ||
- 线性结构的查找,删除,访问一个元素的平均时间复杂度(简单地理解为一个操作需要的平均步骤) | ||
- list 内存重新分配的时候为什么要有冗余?不会浪费空间吗? | ||
- 当你频繁的pop list 的第一个元素的时候,会发生什么?如果需要频繁在两头增添元素,你知道更高效的数据结构吗?后边我们会讲到 | ||
|
||
|
||
# 延伸阅读 | ||
|
||
[Python list implementation](https://www.laurentluce.com/posts/python-list-implementation/) | ||
|
||
[https://github.com/python/cpython/blob/master/Objects/listobject.c](https://github.com/python/cpython/blob/master/Objects/listobject.c) | ||
|
||
|
||
# 勘误 | ||
视频里的 Array.clear 方法有误。应该是 `for i in range(len(self._items))`,已经在后续所有使用到 Array 的代码里修正 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
# -*- coding: utf-8 -*- | ||
|
||
# https://docs.python.org/2/library/array.html | ||
from array import array # python 提供的比较原始的 array 类 | ||
|
||
|
||
arr = array('u', 'asdf') | ||
|
||
print(arr[0], arr[1], arr[2], arr[3]) | ||
|
||
|
||
# 实现定长的 Array ADT,省略了边界检查等 | ||
|
||
class Array(object): | ||
|
||
def __init__(self, size=32): | ||
self._size = size | ||
self._items = [None] * size | ||
|
||
def __getitem__(self, index): | ||
return self._items[index] | ||
|
||
def __setitem__(self, index, value): | ||
self._items[index] = value | ||
|
||
def __len__(self): | ||
return self._size | ||
|
||
def clear(self, value=None): | ||
for i in range(len(self._items)): | ||
self._items[i] = value | ||
|
||
def __iter__(self): | ||
for item in self._items: | ||
yield item | ||
|
||
|
||
def test_array(): | ||
size = 10 | ||
a = Array(size) | ||
a[0] = 1 | ||
assert a[0] == 1 | ||
assert len(a) == 10 | ||
|
||
# py.test array_and_list.py |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
# -*- coding: utf-8 -*- | ||
|
||
|
||
class Node(object): | ||
__slots__ = ('value', 'prev', 'next') # save memory | ||
|
||
def __init__(self, value=None, prev=None, next=None): | ||
self.value, self.prev, self.next = value, prev, next | ||
|
||
|
||
class CircularDoubleLinkedList(object): | ||
"""循环双端链表 ADT | ||
多了个循环其实就是把 root 的 prev 指向 tail 节点,串起来 | ||
""" | ||
|
||
def __init__(self, maxsize=None): | ||
self.maxsize = maxsize | ||
node = Node() | ||
node.next, node.prev = node, node | ||
self.root = node | ||
self.length = 0 | ||
|
||
def __len__(self): | ||
return self.length | ||
|
||
def headnode(self): | ||
return self.root.next | ||
|
||
def tailnode(self): | ||
return self.root.prev | ||
|
||
def append(self, value): # O(1), 你发现一般不用 for 循环的就是 O(1),有限个步骤 | ||
if self.maxsize is not None and len(self) >= self.maxsize: | ||
raise Exception('LinkedList is Full') | ||
node = Node(value=value) | ||
tailnode = self.tailnode() or self.root | ||
|
||
tailnode.next = node | ||
node.prev = tailnode | ||
node.next = self.root | ||
self.root.prev = node | ||
self.length += 1 | ||
|
||
def appendleft(self, value): | ||
if self.maxsize is not None and len(self) >= self.maxsize: | ||
raise Exception('LinkedList is Full') | ||
node = Node(value=value) | ||
if self.root.next is self.root: # empty | ||
node.next = self.root | ||
node.prev = self.root | ||
self.root.next = node | ||
self.root.prev = node | ||
else: | ||
node.prev = self.root | ||
headnode = self.root.next | ||
node.next = headnode | ||
headnode.prev = node | ||
self.root.next = node | ||
self.length += 1 | ||
|
||
def remove(self, node): # O(1),传入node 而不是 value 我们就能实现 O(1) 删除 | ||
"""remove | ||
:param node # 在 lru_cache 里实际上根据key 保存了整个node: | ||
""" | ||
if node is self.root: | ||
return | ||
else: # | ||
node.prev.next = node.next | ||
node.next.prev = node.prev | ||
self.length -= 1 | ||
return node | ||
|
||
def iter_node(self): | ||
if self.root.next is self.root: | ||
return | ||
curnode = self.root.next | ||
while curnode.next is not self.root: | ||
yield curnode | ||
curnode = curnode.next | ||
yield curnode | ||
|
||
def __iter__(self): | ||
for node in self.iter_node(): | ||
yield node.value | ||
|
||
def iter_node_reverse(self): | ||
"""相比单链表独有的反序遍历""" | ||
if self.root.prev is self.root: | ||
return | ||
curnode = self.root.prev | ||
while curnode.prev is not self.root: | ||
yield curnode | ||
curnode = curnode.prev | ||
yield curnode | ||
|
||
|
||
def test_double_link_list(): | ||
dll = CircularDoubleLinkedList() | ||
assert len(dll) == 0 | ||
|
||
dll.append(0) | ||
dll.append(1) | ||
dll.append(2) | ||
|
||
assert list(dll) == [0, 1, 2] | ||
|
||
assert [node.value for node in dll.iter_node()] == [0, 1, 2] | ||
assert [node.value for node in dll.iter_node_reverse()] == [2, 1, 0] | ||
|
||
headnode = dll.headnode() | ||
assert headnode.value == 0 | ||
dll.remove(headnode) | ||
assert len(dll) == 2 | ||
assert [node.value for node in dll.iter_node()] == [1, 2] | ||
|
||
dll.appendleft(0) | ||
assert [node.value for node in dll.iter_node()] == [0, 1, 2] | ||
|
||
|
||
if __name__ == '__main__': | ||
test_double_link_list() |
Oops, something went wrong.