From b8ca70f4061b191e45b3d2b54b51e3c3b85455e1 Mon Sep 17 00:00:00 2001 From: wxnacy <371032668@qq.com> Date: Fri, 5 Jul 2019 18:01:46 +0800 Subject: [PATCH] add email demo --- goland/src/leetcode/15-3sum.go | 53 +++++++ goland/src/sorts/heap_sort.go | 41 +++++ goland/src/sorts/quick_sort.go | 44 ++++++ goland/src/tests/loop_test.go | 70 +++++++++ java/generic/GenericClass.java | 17 ++ javascript/leetcode/15-3sum.js | 36 +++++ python/algorithm/fibonacci_sequence.py | 69 +++++++++ python/algorithm/string_compression.py | 57 +++++++ python/email_demo/myemail.py | 70 +++++++++ python/flask_cache_demo/redis_cache.py | 14 ++ python/flask_cache_demo/requirements.txt | 12 ++ .../07-closure-deco/07_01_deco.py | 22 +++ .../07-closure-deco/07_02_registration.py | 42 +++++ python/fluent_python/07-closure-deco/07_05.py | 30 ++++ .../07-closure-deco/07_08_average_oo.py | 18 +++ .../07-closure-deco/07_09_average.py | 25 +++ .../07-closure-deco/07_14_nonlocal.py | 21 +++ .../07-closure-deco/07_15_clockdeco_demo.py | 31 ++++ .../07-closure-deco/07_17_clockdeco2.py | 43 ++++++ .../07-closure-deco/07_19_fibonacci.py | 46 ++++++ .../07-closure-deco/07_21_htmlize.py | 38 +++++ .../07-closure-deco/07_23_register_param.py | 29 ++++ .../07-closure-deco/07_26_clockdeco_param.py | 29 ++++ .../14-it-generator/14_01_sentence.py | 53 +++++++ .../14-it-generator/14_04_sentence_iter.py | 54 +++++++ .../14-it-generator/14_05_sentence_gen.py | 41 +++++ .../14-it-generator/14_07_sentence_gen2.py | 39 +++++ .../14-it-generator/14_09_sentence_genexp.py | 38 +++++ .../14-it-generator/14_11_aritgrog.py | 31 ++++ .../14-it-generator/14_12_aritgrog_gen.py | 19 +++ .../14-it-generator/14_13_aritgrog_v3.py | 17 ++ .../16-coroutine/coroaverager.py | 42 +++++ .../16-coroutine/coroaverager1.py | 47 ++++++ python/gunicorn_demo/config.py | 17 ++ python/gunicorn_demo/flask_app.py | 30 ++++ python/leetcode/0068-text-justification.py | 145 ++++++++++++++++++ python/leetcode/15-3sum.py | 54 ++++--- python/leetcode/43-multiply-strings.py | 54 +++++++ python/leetcode/utils.py | 20 +++ python/office_module/json_demo/demo.py | 10 ++ python/office_module/json_demo/dumps.py | 47 ++++++ python/simple/test.py | 47 ++++-- python/simple/walk.py | 99 ++++++++++++ python/sorts/bubble_sort.py | 44 ++++-- python/sorts/bucket_sort.py | 67 ++++++++ python/sorts/contrast_speed.py | 79 ++++++++-- python/sorts/counting_sort.py | 45 ++++++ python/sorts/heap_sort.py | 58 +++++++ python/sorts/insertion_sort.py | 41 +++++ python/sorts/merge_sort.py | 60 ++++++++ python/sorts/quick_sort.py | 85 +++++++--- python/sorts/radix_sort.py | 53 +++++++ python/sorts/random_util.py | 11 +- python/sorts/selection_sort.py | 42 +++++ python/sorts/shell_sort.py | 48 ++++++ python/sorts/test_sorts.py | 31 ++++ python/sorts/utils.py | 48 ++++++ python/test/test.py | 6 + python/test/test_sorts.py | 37 +++++ 59 files changed, 2429 insertions(+), 87 deletions(-) create mode 100644 goland/src/leetcode/15-3sum.go create mode 100644 goland/src/sorts/heap_sort.go create mode 100644 goland/src/sorts/quick_sort.go create mode 100644 goland/src/tests/loop_test.go create mode 100644 java/generic/GenericClass.java create mode 100644 javascript/leetcode/15-3sum.js create mode 100644 python/algorithm/fibonacci_sequence.py create mode 100644 python/algorithm/string_compression.py create mode 100644 python/email_demo/myemail.py create mode 100644 python/flask_cache_demo/requirements.txt create mode 100644 python/fluent_python/07-closure-deco/07_01_deco.py create mode 100644 python/fluent_python/07-closure-deco/07_02_registration.py create mode 100644 python/fluent_python/07-closure-deco/07_05.py create mode 100644 python/fluent_python/07-closure-deco/07_08_average_oo.py create mode 100644 python/fluent_python/07-closure-deco/07_09_average.py create mode 100644 python/fluent_python/07-closure-deco/07_14_nonlocal.py create mode 100644 python/fluent_python/07-closure-deco/07_15_clockdeco_demo.py create mode 100644 python/fluent_python/07-closure-deco/07_17_clockdeco2.py create mode 100644 python/fluent_python/07-closure-deco/07_19_fibonacci.py create mode 100644 python/fluent_python/07-closure-deco/07_21_htmlize.py create mode 100644 python/fluent_python/07-closure-deco/07_23_register_param.py create mode 100644 python/fluent_python/07-closure-deco/07_26_clockdeco_param.py create mode 100644 python/fluent_python/14-it-generator/14_01_sentence.py create mode 100644 python/fluent_python/14-it-generator/14_04_sentence_iter.py create mode 100644 python/fluent_python/14-it-generator/14_05_sentence_gen.py create mode 100644 python/fluent_python/14-it-generator/14_07_sentence_gen2.py create mode 100644 python/fluent_python/14-it-generator/14_09_sentence_genexp.py create mode 100644 python/fluent_python/14-it-generator/14_11_aritgrog.py create mode 100644 python/fluent_python/14-it-generator/14_12_aritgrog_gen.py create mode 100644 python/fluent_python/14-it-generator/14_13_aritgrog_v3.py create mode 100644 python/fluent_python/16-coroutine/coroaverager.py create mode 100644 python/fluent_python/16-coroutine/coroaverager1.py create mode 100644 python/gunicorn_demo/config.py create mode 100644 python/gunicorn_demo/flask_app.py create mode 100644 python/leetcode/0068-text-justification.py create mode 100644 python/leetcode/43-multiply-strings.py create mode 100644 python/office_module/json_demo/demo.py create mode 100644 python/office_module/json_demo/dumps.py create mode 100644 python/simple/walk.py create mode 100644 python/sorts/bucket_sort.py create mode 100644 python/sorts/counting_sort.py create mode 100644 python/sorts/heap_sort.py create mode 100644 python/sorts/insertion_sort.py create mode 100644 python/sorts/merge_sort.py create mode 100644 python/sorts/radix_sort.py create mode 100644 python/sorts/selection_sort.py create mode 100644 python/sorts/shell_sort.py create mode 100644 python/sorts/test_sorts.py create mode 100644 python/sorts/utils.py create mode 100644 python/test/test.py create mode 100644 python/test/test_sorts.py diff --git a/goland/src/leetcode/15-3sum.go b/goland/src/leetcode/15-3sum.go new file mode 100644 index 0000000..86cea90 --- /dev/null +++ b/goland/src/leetcode/15-3sum.go @@ -0,0 +1,53 @@ +package main +// 三数之和 + +import ( + "testing" + "sort" +) +// 执行用时 : 1356 ms, 在3Sum的Go提交中击败了85.58% 的用户 +// 内存消耗 : 155.8 MB, 在3Sum的Go提交中击败了12.01% 的用户 +func threeSum(nums []int) [][]int { + res := make([][]int, 0) + sort.Ints(nums) + i := 0 + length := len(nums) + for i < length - 2 { + if nums[i] > 0 { + break + } + left := i + 1 + right := length - 1 + for left < right { + s := nums[i] + nums[left] + nums[right] + if s == 0 { + res = append(res, []int{nums[i], nums[left], nums[right]}) + } + if s <= 0 { + left++ + for left < right && nums[left] == nums[left - 1] { + left++ + } + } else { + right-- + for left < right && nums[right] == nums[right + 1] { + right-- + } + } + } + i++ + for nums[i] == nums[i-1] { + i++ + } + } + return res +} + +func TestThreeSum(t *testing.T) { + + rev := threeSum([]int{-1, 0, 1, 2, -1, -4}) + if rev != [][]int{[]int{-1, -1, 2}, []int{-1, 0, 1}} { + t.Errorf("%d is error", rev) + } + +} diff --git a/goland/src/sorts/heap_sort.go b/goland/src/sorts/heap_sort.go new file mode 100644 index 0000000..153d090 --- /dev/null +++ b/goland/src/sorts/heap_sort.go @@ -0,0 +1,41 @@ +package main + +import ( + "fmt" +) + +func HeapSort(nums []int) { + num_len := len(nums) + i := (num_len >> 1) - 1 + for i > -1 { + heapify(nums, i, num_len) + i-- + } + + for i := num_len - 1; i > -1; i-- { + nums[i], nums[0] = nums[0], nums[i] + heapify(nums, 0, i) + } + fmt.Println(nums) +} + +func heapify(nums []int, i, num_len int) { + k := i + left, right := i * 2 + 1, i * 2 + 2 + if left < num_len && nums[left] > nums[k]{ + k = left + } + if right < num_len && nums[right] > nums[k] { + k = right + } + if k != i { + nums[k], nums[i] = nums[i], nums[k] + heapify(nums, k, num_len) + } +} + +func main() { + var nums = []int{6, 5, 8,4, 7, 2, 9, 3, 1} + HeapSort(nums) + +} diff --git a/goland/src/sorts/quick_sort.go b/goland/src/sorts/quick_sort.go new file mode 100644 index 0000000..d77e600 --- /dev/null +++ b/goland/src/sorts/quick_sort.go @@ -0,0 +1,44 @@ +package main + +import ( + "fmt" +) + +func QuickSort(nums []int) { + quickSort(nums, 0, len(nums) - 1) +} + +func quickSort(nums []int, left, right int) { + if right >= left { + return + } + pivot := partition(nums, left, right) + quickSort(nums, left, pivot - 1) + quickSort(nums, pivot + 1, right) + +} + +func partition(nums []int, left, right int) int { + t := nums[left] + x := left + y := right + for x < y { + for x < y && nums[y] >= t { + y-- + } + nums[x] = nums[y] + for x < y && nums[x] <= t { + x++ + } + nums[y] = nums[x] + } + nums[x] = t + return x +} + +func main() { + var nums = []int{6, 5, 8,4, 7, 2, 9, 3, 1} + QuickSort(nums) + fmt.Println(nums) + +} diff --git a/goland/src/tests/loop_test.go b/goland/src/tests/loop_test.go new file mode 100644 index 0000000..e21f48d --- /dev/null +++ b/goland/src/tests/loop_test.go @@ -0,0 +1,70 @@ +package main + +import ( + "testing" + "fmt" +) + +var LIST = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14} +// var LIST []int + +// func GetList() { + // if LIST == [] { + // LIST = make([]int, 0) + // for i := 0; i < 10000; i++ { + // LIST = append(LIST, i) + // } + // } + // return LIST +// } + +func For() { + var total int + for i := 0; i < len(LIST); i++ { + for k := 0; k < len(LIST); k++ { + total += LIST[k] + } + } +} + +func While() { + var total int + i := 0 + for i < len(LIST) { + total += LIST[i] + i++ + } +} + +func ForEach(b *testing.B) { + var total int + for _, d := range LIST { + total += d + } +} + +func BenchmarkWhile(b *testing.B) { + var total int + i := 0 + for i < len(LIST) { + total += LIST[i] + i++ + } +} + +func BenchmarkForEach(b *testing.B) { + var total int + for _, d := range LIST { + total += d + } +} + +func BenchmarkFor(b *testing.B) { + For() + +} + +func main() { + + fmt.Print(LIST) +} diff --git a/java/generic/GenericClass.java b/java/generic/GenericClass.java new file mode 100644 index 0000000..2461168 --- /dev/null +++ b/java/generic/GenericClass.java @@ -0,0 +1,17 @@ +public class GenericClass{ + private T key; + + public GenericClass(T key) { + this.key = key; + + } + + public T getKey() { + return this.key; + } + public static void main(String args[]){ + System.out.println("Hello World"); + GenericClass gc = new GenericClass("wxnacy"); + System.out.println(gc.getKey()); + } +} diff --git a/javascript/leetcode/15-3sum.js b/javascript/leetcode/15-3sum.js new file mode 100644 index 0000000..88cd5be --- /dev/null +++ b/javascript/leetcode/15-3sum.js @@ -0,0 +1,36 @@ +// 执行用时 : 280 ms, 在3Sum的JavaScript提交中击败了91.01% 的用户 +// 内存消耗 : 46.7 MB, 在3Sum的JavaScript提交中击败了67.20% 的用户 + +var threeSum = function (nums) { + let res = [] + let length = nums.length; + nums.sort((a, b) => a - b) // 先排个队,最左边是最弱(小)的,最右边是最强(大)的 + // 同符号,则无解退出 + if( ( nums[0] < 0 && nums[length - 1] < 0 ) + || ( nums[0] > 0 && nums[length - 1] > 0 ) ) { + return res + } + for (let i = 0; i < length - 2;) { + if (nums[i] > 0) break; // 优化2: 最左值为正数则一定无解 + let first = i + 1 + let last = length - 1 + do { + if (first >= last || nums[i] * nums[last] > 0) break // 两人选相遇,或者三人同符号,则退出 + let result = nums[i] + nums[first] + nums[last] + if (result === 0) { // 如果可以组队 + res.push([nums[i], nums[first], nums[last]]) + } + if (result <= 0 ) { // 实力太弱,把菜鸟那边右移一位 + while (first < last && nums[first] === nums[++first]){} // 如果相等就跳过 + } else { // 实力太强,把大神那边右移一位 + while (first < last && nums[last] === nums[--last]) {} + } + } while (first < last) + while (nums[i] === nums[++i]) {} + } + return res +} + + +var res = threeSum([-1, 0, 1, 2, -1, -4]) +console.log(res) diff --git a/python/algorithm/fibonacci_sequence.py b/python/algorithm/fibonacci_sequence.py new file mode 100644 index 0000000..d5b317a --- /dev/null +++ b/python/algorithm/fibonacci_sequence.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: 斐波那契数列 + +def fibonacci_recursive(n): + ''' + 递归的方式,理解简单,不会在真实开发中用到 + ''' + if n < 3: + return 1 + else: + return fibonacci_recursive(n - 1) + fibonacci_recursive(n - 2) + +def fibonacci_for(n): + ''' + 使用 for 循环挨个计算,减少了递归中的重复计算 + 时间复杂度 O(n) + 空间复杂度 O(1) + ''' + if n < 3: + return 1 + n1, n2 = 1, 1 + n3 = 0 + for i in range(3, n + 1): + n3 = n1 + n2 + n1, n2 = n2, n3 + return n3 + +nums = [1, 1] +def fibonacci_array(n): + ''' + for 循环的方式已经很快了,但是如果想要获取多个值时,每次都要从头计算 + 这时候我们可以把计算的结果保存起来,下次可以直接使用,这是一种空间换时间的算法。 + 时间复杂度 O(n) + 空间复杂度 O(n) + ''' + if len(nums) < n: + for i in range(len(nums), n): + nums.append(nums[i - 1] + nums[i - 2]) + return nums[n - 1] + +import unittest + +class TestMain(unittest.TestCase): + + def setUp(self): + '''before each test function''' + pass + + def tearDown(self): + '''after each test function''' + pass + + def do(self, func): + '''todo''' + n = 8 + res = 21 + self.assertEqual(func(n), res) + pass + + def test_func(self): + self.do(fibonacci_recursive) + self.do(fibonacci_for) + self.do(fibonacci_array) + +if __name__ == "__main__": + unittest.main() + diff --git a/python/algorithm/string_compression.py b/python/algorithm/string_compression.py new file mode 100644 index 0000000..a0f2d37 --- /dev/null +++ b/python/algorithm/string_compression.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: 字符串压缩算法 +# aabbbccccdef => a2b3c4d1e1f1 + +def compress(s): + if not s: + return s + tmp = [s[0]] + res = '' + for i in range(1, len(s)): + if tmp[-1] == s[i]: + tmp.append(s[i]) + else: + res = f"{res}{tmp[-1]}{len(tmp)}" + tmp = [s[i]] + res = f"{res}{tmp[-1]}{len(tmp)}" + return res + +def decompress(s): + if not s: + return s + res = [] + for i in range(0, len(s), 2): + res.extend([s[i]] * int(s[i + 1])) + return ''.join(res) + + +import unittest + +class TestMain(unittest.TestCase): + + def setUp(self): + '''before each test function''' + pass + + def tearDown(self): + '''after each test function''' + pass + + def do(self, func): + '''todo''' + s = "aabbbccccdef" + res = "a2b3c4d1e1f1" + self.assertEqual(decompress(func(s)), s) + pass + + def test_func(self): + self.do(compress) + +if __name__ == "__main__": + unittest.main() + + + + diff --git a/python/email_demo/myemail.py b/python/email_demo/myemail.py new file mode 100644 index 0000000..d185e91 --- /dev/null +++ b/python/email_demo/myemail.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: 发送邮件 + +from email.mime.text import MIMEText +from email.header import Header +import smtplib +import traceback + +class Email(): + def __init__(self, smtp_host, smtp_port, user, password, sender, + sender_name, **kwargs): + kw = locals() + kw.pop('self') + for k, v in kw.items(): + setattr(self, k, v) + + def connect(self): + '''建立连接''' + try: + smtpObj = smtplib.SMTP() + # smtpObj.set_debuglevel(1) + smtpObj.connect(self.smtp_host, self.smtp_port) + smtpObj.login(self.user, self.password) + + self.client = smtpObj + self.sender = self.sender + self.sender_name = self.sender_name + except smtplib.SMTPException as e: + traceback.print_exc(e) + + def send(self, receivers, subject, message, maintype='plain', cc=[]): + ''' + 发送邮件 + ''' + self.connect() + message = MIMEText(message, maintype, 'utf-8') + message['From'] = Header(self.sender_name, 'utf-8') + message['To'] = Header(','.join(receivers), 'utf-8') + if cc: + message['Cc'] = Header(','.join(cc), 'utf-8') + # message['Bcc'] = Header(','.join(receivers), 'utf-8') + message['Subject'] = Header(subject, 'utf-8') + receivers.extend(cc) + try: + self.client.sendmail(self.sender, receivers, + message.as_string()) + self.client.quit() + return True + except Exception as e: + traceback.format_exc(e) + self.client.quit() + return False + +if __name__ == '__main__': + # 以阿里邮箱为例 + smtp_host = 'smtp.mxhichina.com' # smtp 地址 + smtp_port = 25 # smtp 端口 + user = '' # 发送方邮箱 + password = '' # 发送方密码 + sender = '' # 发送方邮箱 + sender_name = '' # 发送方名称 + + e = Email(**locals()) + receivers = ['.inner at 0x101609378> diff --git a/python/fluent_python/07-closure-deco/07_02_registration.py b/python/fluent_python/07-closure-deco/07_02_registration.py new file mode 100644 index 0000000..119c8cd --- /dev/null +++ b/python/fluent_python/07-closure-deco/07_02_registration.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: 装饰器的一个关键特性是,它们在被装饰的函数定义之后立即运行。 +# 这通常是在导入时(即Python加载模块时) + + +registry = [] + +def register(func): + print(f'running register({func})') + registry.append(func) + return func + +@register +def f1(): + print('running f1()') + +@register +def f2(): + print('running f2()') + +def f3(): + print('running f3()') + +def main(): + print('running main()') + print(f'registry -> {registry}') + f1() + f2() + f3() + +if __name__ == "__main__": + main() + +# running register() +# running register() +# running main() +# registry -> [, ] +# running f1() +# running f2() +# running f3() diff --git a/python/fluent_python/07-closure-deco/07_05.py b/python/fluent_python/07-closure-deco/07_05.py new file mode 100644 index 0000000..a96fdf4 --- /dev/null +++ b/python/fluent_python/07-closure-deco/07_05.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: 变量作用域 + +b = 3 + +def f1(a): + print(a) + print(b) # UnboundLocalError: local variable 'b' referenced before assignment + b = 9 + +def f2(): + b = 9 + print(b) + +def f3(): + global b + print(b) + b = 9 + + +if __name__ == "__main__": + # f1(1) + f2() # 9 + print(b) # 3 + f3() # 3 + print(b) # 9 + + diff --git a/python/fluent_python/07-closure-deco/07_08_average_oo.py b/python/fluent_python/07-closure-deco/07_08_average_oo.py new file mode 100644 index 0000000..308afa2 --- /dev/null +++ b/python/fluent_python/07-closure-deco/07_08_average_oo.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: + +class Averager(): + def __init__(self, *args, **kwargs): + self.series = [] + + def __call__(self, new_value): + self.series.append(new_value) + return sum(self.series) / len(self.series) + +if __name__ == "__main__": + ave = Averager() + print(ave(10)) # 10.0 + print(ave(11)) # 10.5 + print(ave(12)) # 11.0 diff --git a/python/fluent_python/07-closure-deco/07_09_average.py b/python/fluent_python/07-closure-deco/07_09_average.py new file mode 100644 index 0000000..ef503ea --- /dev/null +++ b/python/fluent_python/07-closure-deco/07_09_average.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: + +def make_averager(): + series = [] + + def averager(new_value): + series.append(new_value) + return sum(series) / len(series) + return averager + + + +if __name__ == "__main__": + avg = make_averager() + print(avg(10)) # 10.0 + print(avg(11)) # 10.5 + print(avg(12)) # 11.0 + print(dir(avg.__code__)) + print(avg.__code__.co_varnames) # 局部变量 ('new_value',) + print(avg.__code__.co_freevars) # 自由变量 ('series',) + print(avg.__closure__) # (,) + print(avg.__closure__[0].cell_contents) # [10, 11, 12] diff --git a/python/fluent_python/07-closure-deco/07_14_nonlocal.py b/python/fluent_python/07-closure-deco/07_14_nonlocal.py new file mode 100644 index 0000000..c699f23 --- /dev/null +++ b/python/fluent_python/07-closure-deco/07_14_nonlocal.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: + +def make_averager(): + count = 0 + total = 0 + + def averager(new_value): + nonlocal count, total + count += 1 + total += new_value + return total / count + return averager + +if __name__ == "__main__": + avg = make_averager() + print(avg(10)) # 10.0 + print(avg(11)) # 10.5 + print(avg(12)) # 11.0 diff --git a/python/fluent_python/07-closure-deco/07_15_clockdeco_demo.py b/python/fluent_python/07-closure-deco/07_15_clockdeco_demo.py new file mode 100644 index 0000000..0e3aeb8 --- /dev/null +++ b/python/fluent_python/07-closure-deco/07_15_clockdeco_demo.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: 简单的装饰器 +# 方法的属性会被覆盖掉 + +import time + +def clock(func): + def clocked(*args): + '''计时''' + t0 = time.perf_counter() + result = func(*args) + elapsed = time.perf_counter() - t0 + print(f'[{elapsed:0.8f}s] {func.__name__}({args}) -> {result}') + return result + return clocked + +@clock +def f1(n): + return n if n < 3 else f1(n-1) + f1(n-2) + +if __name__ == "__main__": + # [0.00000080s] f1((2,)) -> 2 + print(f1(2)) # 2 + print(f1) # .clocked at 0x10bb5a158> + print(f1.__name__) # clocked + print(f1.__doc__) # 计时 + + + diff --git a/python/fluent_python/07-closure-deco/07_17_clockdeco2.py b/python/fluent_python/07-closure-deco/07_17_clockdeco2.py new file mode 100644 index 0000000..5514c9e --- /dev/null +++ b/python/fluent_python/07-closure-deco/07_17_clockdeco2.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: 改进的装饰器 +# 使用 functools.wraps 装饰器可以把 func 的相关属性复制到 clocked 中 +# 使用递归实现斐波那契数列非常耗时,会有很多重复计算函数 + +import time +from functools import wraps + +def clock(func): + @wraps(func) + def clocked(*args, **kwargs): + '''计时''' + t0 = time.perf_counter() + result = func(*args, **kwargs) + elapsed = time.perf_counter() - t0 + print(f'[{elapsed:0.8f}s] {func.__name__}({args}, {kwargs}) -> {result}') + return result + return clocked + +@clock +def f1(n): + '''斐波那契数列''' + return n if n < 3 else f1(n-1) + f1(n-2) + +if __name__ == "__main__": +# [0.00000049s] f1((2,), {}) -> 2 +# [0.00000042s] f1((1,), {}) -> 1 +# [0.00003052s] f1((3,), {}) -> 3 +# [0.00000028s] f1((2,), {}) -> 2 +# [0.00003689s] f1((4,), {}) -> 5 +# [0.00000032s] f1((2,), {}) -> 2 +# [0.00000027s] f1((1,), {}) -> 1 +# [0.00000547s] f1((3,), {}) -> 3 +# [0.00004824s] f1((5,), {}) -> 8 + print(f1(5)) # 8 + print(f1) # + print(f1.__name__) # f1 + print(f1.__doc__) # 斐波那契数列 + + + diff --git a/python/fluent_python/07-closure-deco/07_19_fibonacci.py b/python/fluent_python/07-closure-deco/07_19_fibonacci.py new file mode 100644 index 0000000..1b32e47 --- /dev/null +++ b/python/fluent_python/07-closure-deco/07_19_fibonacci.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: 改进的装饰器 +# 使用递归实现斐波那契数列非常耗时,会有很多重复计算函数 +# 使用 functools.lru_cache(maxsize, typed) 装饰器起到缓存的作用 +# maxsize参数指定存储多少个调用的结果。缓存满了之后,旧的结果会被扔掉,腾出空间。 +# 为了得到最佳性能,maxsize应该设为2的幂。 +# typed参数如果设为True,把不同参数类型得到的结果分开保存, +# 即把通常认为相等的浮点数和整数参数(如1和1.0)区分开。 + +import time +from functools import wraps +from functools import lru_cache + +def clock(func): + @wraps(func) + def clocked(*args, **kwargs): + '''计时''' + t0 = time.perf_counter() + result = func(*args, **kwargs) + elapsed = time.perf_counter() - t0 + print(f'[{elapsed:0.8f}s] {func.__name__}({args}, {kwargs}) -> {result}') + return result + return clocked + +@lru_cache(maxsize=128, typed=True) # 必须放在最外层 +@clock +def f1(n): + '''斐波那契数列''' + return n if n < 3 else f1(n-1) + f1(n-2) + +if __name__ == "__main__": +# [0.00000053s] f1((2,), {}) -> 2 +# [0.00000041s] f1((1,), {}) -> 1 +# [0.00003426s] f1((3,), {}) -> 3 +# [0.00003875s] f1((4,), {}) -> 5 +# [0.00004331s] f1((5,), {}) -> 8 + print(f1(5)) # 8 + print(f1) # + print(f1.__name__) # f1 + print(f1.__doc__) # 斐波那契数列 + print(f1.__code__) + + + diff --git a/python/fluent_python/07-closure-deco/07_21_htmlize.py b/python/fluent_python/07-closure-deco/07_21_htmlize.py new file mode 100644 index 0000000..977c971 --- /dev/null +++ b/python/fluent_python/07-closure-deco/07_21_htmlize.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: +# Python3.4新增的functools.singledispatch装饰器可以把整体方案拆分成多个模块, +# 甚至可以为你无法修改的类提供专门的函数。使用 @singledispatch 装饰的普通函数会变成泛函数(genericfunction):根据第一个参数的类型,以不同方式执行相同操作的一组函数。 +# 这才称得上是单分派。如果根据多个参数选择专门的函数,那就是多分派了。 + +from functools import singledispatch +from collections import abc +import html +import numbers + +@singledispatch +def htmlize(obj): + content = html.escape(repr(obj)) + return f'
{content}
' + +@htmlize.register(str) +def _(text): + content = html.escape(text).replace('\n', '
\n') + return f'

{content}

' + +@htmlize.register(numbers.Integral) +def _(n): + return f'
{n} (0x{n:x})
' + +@htmlize.register(tuple) +@htmlize.register(abc.MutableSequence) +def _(seq): + inner = '\n
  • '.join(htmlize(item) for item in seq) + return f'
      \n
    • {inner}
    • \n
    ' + +if __name__ == "__main__": + print(htmlize('wxnacy')) + print(htmlize('wxnacy\nwebsite')) + print(htmlize(4)) + print(htmlize([1, 2, 3])) diff --git a/python/fluent_python/07-closure-deco/07_23_register_param.py b/python/fluent_python/07-closure-deco/07_23_register_param.py new file mode 100644 index 0000000..8fc7d23 --- /dev/null +++ b/python/fluent_python/07-closure-deco/07_23_register_param.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: 参数化装饰器 + +registry = set() + +def register(active=True): + + def decorate(func): + if active: + registry.add(func) + else: + registry.discard(func) + return func + return decorate + +@register() +def f1(): + print('running f1') + +@register(active=False) +def f2(): + print('running f2') + +if __name__ == "__main__": + f1() + f2() + print(registry) # {} diff --git a/python/fluent_python/07-closure-deco/07_26_clockdeco_param.py b/python/fluent_python/07-closure-deco/07_26_clockdeco_param.py new file mode 100644 index 0000000..7d7e497 --- /dev/null +++ b/python/fluent_python/07-closure-deco/07_26_clockdeco_param.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: 计时器参数化装饰器版本 + +import timeit +import time + +FMT='[{T:0.8f}s] {F} -> {R}' + +def clock(fmt=FMT): + def clocked(func): + def _clock(*args, **kw): + t0 = timeit.default_timer() + result = func(*args, **kw) + R = repr(result) + T = timeit.default_timer() - t0 + F = func.__name__ + print(fmt.format(**locals())) + return result + return _clock + return clocked + +@clock() +def snooze(s): + time.sleep(s) + +if __name__ == "__main__": + snooze(.321) # [0.32474239s] snooze -> None diff --git a/python/fluent_python/14-it-generator/14_01_sentence.py b/python/fluent_python/14-it-generator/14_01_sentence.py new file mode 100644 index 0000000..10303b4 --- /dev/null +++ b/python/fluent_python/14-it-generator/14_01_sentence.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: 实现可迭代对象 +# 按照《设计模式:可复用面向对象软件的基础》一书讲解迭代器设计模式的实现方式 +# 但并不符合 Python 的开发模式 + +import re +import reprlib +from collections.abc import Iterable +from collections.abc import Iterator + +RE_WORD = re.compile('\w+') + +class Sentence(): + def __init__(self, text): + self.text = text + # .findall 函数返回的结果,因此直接返回指定索引位上的单词。 + self.words = RE_WORD.findall(text) + self.size = len(self.words) + + def __getitem__(self, index): + ''' + 可以直接使用索引获取单词的魔法函数 + + 如果没有实现 __iter__ 方法,但是实现了 __getitem__ 方法, + Python 会创建一个迭代器,尝试按顺序(从索引 0 开始)获取元素。 + ''' + return self.words[index] + + def __len__(self): + return self.size + + def __repr__(self): + ''' + reprlib.repr 这个实用函数用于生成大型数据结构的简略字符串 + 默认情况下,reprlib.repr 函数生成的字符串最多有 30 个字 符。 + ''' + return f'Sentence({reprlib.repr(self.text)})' + + + +if __name__ == "__main__": + s = Sentence("My name is wxnacy. The website is 'https://wxnacy.com'") + print(isinstance(s, Iterable)) # False + print(isinstance(iter(s), Iterator)) # True + print(s) # Sentence("My name is w...//wxnacy.com'") + print(list(s)) # ['My', 'name', 'is', 'wxnacy', 'The', 'website', 'is', + # 'https', 'wxnacy', 'com'] + print(len(s)) # 10 + print(s[0]) # My + for w in s: + print(w) diff --git a/python/fluent_python/14-it-generator/14_04_sentence_iter.py b/python/fluent_python/14-it-generator/14_04_sentence_iter.py new file mode 100644 index 0000000..ccafe7c --- /dev/null +++ b/python/fluent_python/14-it-generator/14_04_sentence_iter.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: 使用迭代器实现可迭代对象 + +import re +import reprlib +from collections.abc import Iterable +from collections.abc import Iterator + +RE_WORD = re.compile('\w+') + +class Sentence(): + def __init__(self, text): + self.text = text + # .findall 函数返回的结果,因此直接返回指定索引位上的单词。 + self.words = RE_WORD.findall(text) + + def __iter__(self): + return SentenceIterator(self.words) + + def __repr__(self): + ''' + reprlib.repr 这个实用函数用于生成大型数据结构的简略字符串 + 默认情况下,reprlib.repr 函数生成的字符串最多有 30 个字 符。 + ''' + return f'Sentence({reprlib.repr(self.text)})' + +class SentenceIterator(): + def __init__(self, words): + self.words = words + self.index = 0 + + def __next__(self): + try: + word = self.words[self.index] + except IndexError: + raise StopIteration() + self.index += 1 + return word + + def __iter__(self): + return self + + +if __name__ == "__main__": + s = Sentence("My name is wxnacy. The website is 'https://wxnacy.com'") + print(isinstance(s, Iterable)) # True + print(isinstance(iter(s), Iterator)) # True + print(s) # Sentence("My name is w...//wxnacy.com'") + print(list(s)) # ['My', 'name', 'is', 'wxnacy', 'The', 'website', 'is', + # 'https', 'wxnacy', 'com'] + for w in s: + print(w) diff --git a/python/fluent_python/14-it-generator/14_05_sentence_gen.py b/python/fluent_python/14-it-generator/14_05_sentence_gen.py new file mode 100644 index 0000000..bc3057f --- /dev/null +++ b/python/fluent_python/14-it-generator/14_05_sentence_gen.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: 使用生成器实现可迭代对象 + +import re +import reprlib +from collections.abc import Iterable +from collections.abc import Iterator +from collections.abc import Generator + +RE_WORD = re.compile('\w+') + +class Sentence(): + def __init__(self, text): + self.text = text + # .findall 函数返回的结果,因此直接返回指定索引位上的单词。 + self.words = RE_WORD.findall(text) + + def __iter__(self): + for w in self.words: + yield w + + def __repr__(self): + ''' + reprlib.repr 这个实用函数用于生成大型数据结构的简略字符串 + 默认情况下,reprlib.repr 函数生成的字符串最多有 30 个字 符。 + ''' + return f'Sentence({reprlib.repr(self.text)})' + + +if __name__ == "__main__": + s = Sentence("My name is wxnacy. The website is 'https://wxnacy.com'") + print(isinstance(s, Iterable)) # True + print(isinstance(iter(s), Iterator)) # True + print(isinstance(iter(s), Generator)) # True + print(s) # Sentence("My name is w...//wxnacy.com'") + print(list(s)) # ['My', 'name', 'is', 'wxnacy', 'The', 'website', 'is', + # 'https', 'wxnacy', 'com'] + for w in s: + print(w) diff --git a/python/fluent_python/14-it-generator/14_07_sentence_gen2.py b/python/fluent_python/14-it-generator/14_07_sentence_gen2.py new file mode 100644 index 0000000..2ba7dac --- /dev/null +++ b/python/fluent_python/14-it-generator/14_07_sentence_gen2.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: 惰性实现 + +import re +import reprlib +from collections.abc import Iterable +from collections.abc import Iterator +from collections.abc import Generator + +RE_WORD = re.compile('\w+') + +class Sentence(): + def __init__(self, text): + self.text = text + + def __iter__(self): + for match in RE_WORD.finditer(self.text): + yield match.group() + + def __repr__(self): + ''' + reprlib.repr 这个实用函数用于生成大型数据结构的简略字符串 + 默认情况下,reprlib.repr 函数生成的字符串最多有 30 个字 符。 + ''' + return f'Sentence({reprlib.repr(self.text)})' + + +if __name__ == "__main__": + s = Sentence("My name is wxnacy. The website is 'https://wxnacy.com'") + print(isinstance(s, Iterable)) # True + print(isinstance(iter(s), Iterator)) # True + print(isinstance(iter(s), Generator)) # True + print(s) # Sentence("My name is w...//wxnacy.com'") + print(list(s)) # ['My', 'name', 'is', 'wxnacy', 'The', 'website', 'is', + # 'https', 'wxnacy', 'com'] + for w in s: + print(w) diff --git a/python/fluent_python/14-it-generator/14_09_sentence_genexp.py b/python/fluent_python/14-it-generator/14_09_sentence_genexp.py new file mode 100644 index 0000000..8c414dc --- /dev/null +++ b/python/fluent_python/14-it-generator/14_09_sentence_genexp.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: 生成器表达式 + +import re +import reprlib +from collections.abc import Iterable +from collections.abc import Iterator +from collections.abc import Generator + +RE_WORD = re.compile('\w+') + +class Sentence(): + def __init__(self, text): + self.text = text + + def __iter__(self): + return (match.group() for match in RE_WORD.finditer(self.text)) + + def __repr__(self): + ''' + reprlib.repr 这个实用函数用于生成大型数据结构的简略字符串 + 默认情况下,reprlib.repr 函数生成的字符串最多有 30 个字 符。 + ''' + return f'Sentence({reprlib.repr(self.text)})' + + +if __name__ == "__main__": + s = Sentence("My name is wxnacy. The website is 'https://wxnacy.com'") + print(isinstance(s, Iterable)) # True + print(isinstance(iter(s), Iterator)) # True + print(isinstance(iter(s), Generator)) # True + print(s) # Sentence("My name is w...//wxnacy.com'") + print(list(s)) # ['My', 'name', 'is', 'wxnacy', 'The', 'website', 'is', + # 'https', 'wxnacy', 'com'] + for w in s: + print(w) diff --git a/python/fluent_python/14-it-generator/14_11_aritgrog.py b/python/fluent_python/14-it-generator/14_11_aritgrog.py new file mode 100644 index 0000000..30d8909 --- /dev/null +++ b/python/fluent_python/14-it-generator/14_11_aritgrog.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: + +class ArithmeticProgression(): + + def __init__(self, begin, step, end=None): + self.begin = begin + self.step = step + self.end = end + + def __iter__(self): + result = type(self.begin + self.step)(self.begin) + forever = self.end is None + index = 0 + while forever or result < self.end: + yield result + index += 1 + result = self.begin + self.step * index + + +if __name__ == "__main__": + ap = ArithmeticProgression(0, 2, 7) + print(list(ap)) # [0, 2, 4, 6] + for a in ap: + print(a) +# 0 +# 2 +# 4 +# 6 diff --git a/python/fluent_python/14-it-generator/14_12_aritgrog_gen.py b/python/fluent_python/14-it-generator/14_12_aritgrog_gen.py new file mode 100644 index 0000000..bdc4689 --- /dev/null +++ b/python/fluent_python/14-it-generator/14_12_aritgrog_gen.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: 使用生成器函数创建生成器 + + +def aritprog_gen(begin, step, end=None): + result = type(begin + step)(begin) + forever = end is None + index = 0 + while forever or result < end: + yield result + index += 1 + result = begin + step * index + + +if __name__ == "__main__": + ap = aritprog_gen(0, 2, 7) + print(list(ap)) # [0, 2, 4, 6] diff --git a/python/fluent_python/14-it-generator/14_13_aritgrog_v3.py b/python/fluent_python/14-it-generator/14_13_aritgrog_v3.py new file mode 100644 index 0000000..df2b237 --- /dev/null +++ b/python/fluent_python/14-it-generator/14_13_aritgrog_v3.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: 使用生成器函数创建生成器 + +import itertools + +def aritprog_gen(begin, step, end=None): + ap_gen = itertools.count(begin, step) + if end is not None: + ap_gen = itertools.takewhile(lambda x: x < end, ap_gen) + return ap_gen + + +if __name__ == "__main__": + ap = aritprog_gen(0, 2, 7) + print(list(ap)) # [0, 2, 4, 6] diff --git a/python/fluent_python/16-coroutine/coroaverager.py b/python/fluent_python/16-coroutine/coroaverager.py new file mode 100644 index 0000000..8e1b017 --- /dev/null +++ b/python/fluent_python/16-coroutine/coroaverager.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: + +def averager(): + total = 0.0 + count = 0 + average = None + while True: + term = yield average + total += term + count += 1 + average = total / count + +import unittest + +class TestMain(unittest.TestCase): + + def setUp(self): + '''before each test function''' + pass + + def tearDown(self): + '''after each test function''' + pass + + def do(self, func): + '''todo''' + self.assertEqual(1, 1) + pass + + def test_func(self): + a = averager() + next(a) + self.assertEqual(10.0, a.send(10)) + self.assertEqual(15.0, a.send(20)) + self.assertEqual(20.0, a.send(30)) + +if __name__ == "__main__": + unittest.main() + diff --git a/python/fluent_python/16-coroutine/coroaverager1.py b/python/fluent_python/16-coroutine/coroaverager1.py new file mode 100644 index 0000000..1c0831f --- /dev/null +++ b/python/fluent_python/16-coroutine/coroaverager1.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: + +from functools import wraps + +def coroutine(func): + @wraps(func) + def primer(*args, **kwargs): + gen = func(*args, **kwargs) + next(gen) + return gen + return primer + +@coroutine +def averager(): + total = 0.0 + count = 0 + average = None + while True: + term = yield average + total += term + count += 1 + average = total / count + +import unittest + +class TestMain(unittest.TestCase): + + def setUp(self): + '''before each test function''' + pass + + def tearDown(self): + '''after each test function''' + pass + + def test_func(self): + a = averager() + self.assertEqual(10.0, a.send(10)) + self.assertEqual(15.0, a.send(20)) + self.assertEqual(20.0, a.send(30)) + +if __name__ == "__main__": + unittest.main() + diff --git a/python/gunicorn_demo/config.py b/python/gunicorn_demo/config.py new file mode 100644 index 0000000..ae4ae0e --- /dev/null +++ b/python/gunicorn_demo/config.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: 常用 gunicorn 配置 + +import multiprocessing + +# workers=multiprocessing.cpu_count() * 2 + 1 +workers=1 +timeout=6 # 请求的超时秒数,仅在 sync 模式下生效 +# worker_class='gevent' +bind='127.0.0.1:8765' +reload = True +access_log_format = '%(h)s %(t)s %(r)s %(m)s %(s)s %(T)s %(D)s %(B)s %(U)s %(q)s' +accesslog='/tmp/gunicorn.log' + + diff --git a/python/gunicorn_demo/flask_app.py b/python/gunicorn_demo/flask_app.py new file mode 100644 index 0000000..dd3ab75 --- /dev/null +++ b/python/gunicorn_demo/flask_app.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: 测试 gunicorn 配置 +# 运行:gunicorn -c config.py flask_app:app + +from flask import Flask +import time + +app = Flask(__name__) + +@app.route('/out5seconds') +def out5seconds(): + time.sleep(5) + return 'Hello World' + +@app.route('/out11seconds') +def out11seconds(): + time.sleep(11) + return 'Hello World' + +@app.route('/hello') +def hello(): + print('hello') + app.logger.info('Hello World') + return 'Hello World' + +if __name__ == "__main__": + app.run() + diff --git a/python/leetcode/0068-text-justification.py b/python/leetcode/0068-text-justification.py new file mode 100644 index 0000000..4697afe --- /dev/null +++ b/python/leetcode/0068-text-justification.py @@ -0,0 +1,145 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: 文本左右对齐 + +''' +给定一个单词数组和一个长度 maxWidth,重新排版单词,使其成为每行恰好有 maxWidth 个字符,且左右两端对齐的文本。 + +你应该使用“贪心算法”来放置给定的单词;也就是说,尽可能多地往每行中放置单词。必要时可用空格 ' ' 填充,使得每行恰好有 maxWidth 个字符。 + +要求尽可能均匀分配单词间的空格数量。如果某一行单词间的空格不能均匀分配,则左侧放置的空格数要多于右侧的空格数。 + +文本的最后一行应为左对齐,且单词之间不插入额外的空格。 + +说明: + +单词是指由非空格字符组成的字符序列。 +每个单词的长度大于 0,小于等于 maxWidth。 +输入单词数组 words 至少包含一个单词。 +示例: + +输入: +words = ["This", "is", "an", "example", "of", "text", "justification."] +maxWidth = 16 +输出: +[ +   "This    is    an", +   "example  of text", +   "justification.  " +] +示例 2: + +输入: +words = ["What","must","be","acknowledgment","shall","be"] +maxWidth = 16 +输出: +[ +  "What   must   be", +  "acknowledgment  ", +  "shall be        " +] +解释: 注意最后一行的格式应为 "shall be " 而不是 "shall be", +  因为最后一行应为左对齐,而不是左右两端对齐。 + 第二行同样为左对齐,这是因为这行只包含一个单词。 +示例 3: + +输入: +words = ["Science","is","what","we","understand","well","enough","to","explain", +  "to","a","computer.","Art","is","everything","else","we","do"] +maxWidth = 20 +输出: +[ +  "Science  is  what we", + "understand      well", +  "enough to explain to", +  "a  computer.  Art is", +  "everything  else  we", +  "do                  " +] +''' + +from utils import clock + +class Solution: + @clock(1) + def fullJustify(self, words, maxWidth: int): + ''' + 执行用时 : 36 ms , 在所有 Python3 提交中击败了 99.08% 的用户 + 内存消耗 : 13.1 MB , 在所有 Python3 提交中击败了 69.32% 的用户 + ''' + res = [] + left, right, line_len = 0, 0, 0 + while right < len(words): + word_len = len(words[right]) + (1 if right > left else 0) + next_len = line_len + word_len + if next_len == maxWidth: + right += 1 + res.append(' '.join(words[left:right])) + line_len = 0 + left = right + elif next_len > maxWidth: + space_len = maxWidth - line_len + space_count = len(words[left:right]) - 1 + if space_count > 0: + avg = ( space_count + space_len ) // space_count + mod = ( space_count + space_len ) % space_count + spaces = [' ' * avg] * space_count + for m in range(mod): + spaces[m] += " " + line = '' + wds = words[left:right] + for i in range(len(spaces)): + wds[i] += spaces[i] + line = ''.join(wds) + else: + line = words[left] + ' ' * space_len + res.append(line) + line_len = 0 + left = right + else: + line_len = next_len + right +=1 + if line_len > 0: + line = ' '.join(words[left:right]) + res.append(line + ' ' * (maxWidth - len(line))) + return res + +s = Solution() + +import unittest + +class TestMain(unittest.TestCase): + + def setUp(self): + '''before each test function''' + pass + + def tearDown(self): + '''after each test function''' + pass + + def do(self, func): + '''todo''' + words = ["This", "is", "an", "example", "of", "text", "justification."] + maxWidth = 16 + res =["This is an", "example of text","justification. "] + self.assertEqual(res, func(words, maxWidth)) + words = ["What","must","be","acknowledgment","shall","be"] + maxWidth = 16 + # res = ["What   must   be","acknowledgment  ","shall be        "] + res = ["What must be","acknowledgment ","shall be "] + self.assertEqual(res, func(words, maxWidth)) + + words = ["Science","is","what","we","understand","well","enough","to", + "explain","to","a","computer.","Art","is","everything","else","we","do"] + maxWidth = 20 + res = ["Science is what we","understand well","enough to explain to","a computer. Art is","everything else we","do "] + self.assertEqual(res, func(words, maxWidth)) + + def test_func(self): + self.do(s.fullJustify) + +if __name__ == "__main__": + unittest.main() + diff --git a/python/leetcode/15-3sum.py b/python/leetcode/15-3sum.py index 83d160a..6342e5d 100644 --- a/python/leetcode/15-3sum.py +++ b/python/leetcode/15-3sum.py @@ -26,18 +26,41 @@ def twoSum(self, nums, target): if n in m: return [m[n], i] m[nums[i]] = i - return [-1, -1] + return [0, 0] def threeSum(self, nums: 'List[int]') -> 'List[List[int]]': + ''' +执行用时 : 1208 ms, 在3Sum的Python3提交中击败了58.01% 的用户 +内存消耗 : 16.6 MB, 在3Sum的Python3提交中击败了93.52% 的用户 + ''' res = [] - for i in range(len(nums) - 2): - target = 0 - nums[i] - i1, i2 = self.twoSum(nums[i + 1:], target) - if i1 > -1: - i1 += i + 1 - i2 += i + 1 - print(i, i1, i2) - res.append([nums[i], nums[i1], nums[i2]]) + if not nums: + return res + nums.sort() + if ( nums[0] > 0 and nums[-1] > 0 ) or ( nums[0] < 0 and nums[-1] < 0): + return res + length = len(nums) + last_begin = nums[0] + for i in range(length - 2): + if nums[i] > 0: + break + if i > 0 and nums[i] == last_begin: + continue + last_begin = nums[i] + left = i + 1 + right = length - 1 + while left < right: + _sum = nums[i] + nums[left] + nums[right] + if _sum == 0: + res.append([nums[i], nums[left], nums[right]]) + if _sum <= 0: + left += 1 + while left < right and nums[left] == nums[left - 1]: + left += 1 + else: + right -= 1 + while left < right and nums[right + 1] == nums[right]: + right -=1 return res import unittest @@ -56,17 +79,10 @@ def tearDown(self): def do(self, func): nums = [-1, 0, 1, 2, -1, -4] - res = [ [-1, 0, 1], [-1, -1, 2] ] + res = [ [-1, -1, 2],[-1, 0, 1] ] self.assertEqual(func(nums), res) - # nums = [-1, 0, 1] - # res = [ [-1, 0, 1]] - # self.assertEqual(func(nums), res) - # nums = [-1, 0] - # res = [[]] - # self.assertEqual(nums, res) - # nums = [-1, 0, 1, -1, 0, 1] - # res = [ [-1, 0, 1]] - # self.assertEqual(func(nums), res) + self.assertEqual(func([]), []) + self.assertEqual(func([0, 0, 0, 0]), [[0, 0, 0]]) def test_func(self): self.do(s.threeSum) diff --git a/python/leetcode/43-multiply-strings.py b/python/leetcode/43-multiply-strings.py new file mode 100644 index 0000000..9867572 --- /dev/null +++ b/python/leetcode/43-multiply-strings.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: 字符串相乘 + +class Solution: + def multiply(self, num1: str, num2: str) -> str: + ''' +执行用时 : 296 ms , 在所有Python3提交中击败了 28.74% 的用户 +内存消耗 : 13 MB , 在所有Python3提交中击败了 97.59% 的用户 + ''' + if not num1 or not num2: + return num1 + num2 + if num1[0] == "0" or num2[0] == "0": + return "0" + res = 0 + c1 = 0 + for i1 in range(len(num1) - 1, -1, -1): + c2 = c1 + for i2 in range(len(num2) - 1, -1, -1): + n3 = int(num1[i1]) * int(num2[i2]) * ( 10 ** c2) + res += n3 + c2 += 1 + c1 += 1 + return str(res) + +s = Solution() + +import unittest + +class TestMain(unittest.TestCase): + + def setUp(self): + '''before each test function''' + pass + + def tearDown(self): + '''after each test function''' + pass + + def do(self, func): + '''todo''' + # self.assertEqual(func("2", "3"), "6") + self.assertEqual(func("123", "456"), "56088") + pass + + def test_func(self): + self.do(s.multiply) + +if __name__ == "__main__": + unittest.main() + + + diff --git a/python/leetcode/utils.py b/python/leetcode/utils.py index 4c87f2b..e124ce6 100644 --- a/python/leetcode/utils.py +++ b/python/leetcode/utils.py @@ -15,6 +15,26 @@ def print_func_run_time(count, func, **kw): count, timeit.default_timer() -b )) + +# CLOCK_FMT = '[{T:0.8f}s] {F}({A}, {K}) -> {R}' +CLOCK_FMT = '[{T:0.8f}s] {F}() -> {R}' +def clock(times=1, fmt=CLOCK_FMT, logger_func=print): + def clock_wraper(func): + def _wraper(*args, **kwargs): + t0 = timeit.default_timer() + result = None + for i in range(times): + result = func(*args, **kwargs) + T = timeit.default_timer() - t0 + F = func.__name__ + A = args + K = kwargs + R = repr(result) + logger_func(fmt.format(**locals())) + return result + return _wraper + return clock_wraper + # def print_func_run_time1(count, func, *args): # b = timeit.default_timer() # for i in range(count): diff --git a/python/office_module/json_demo/demo.py b/python/office_module/json_demo/demo.py new file mode 100644 index 0000000..5e68d68 --- /dev/null +++ b/python/office_module/json_demo/demo.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: + +from datetime import datetime + +USER_DATA = dict( + id = 1, name = 'wxnacy', create_ts = datetime.now() +) diff --git a/python/office_module/json_demo/dumps.py b/python/office_module/json_demo/dumps.py new file mode 100644 index 0000000..0755f36 --- /dev/null +++ b/python/office_module/json_demo/dumps.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: json.dumps() 函数可以将字典对象序列化为字符串 + +import json + +USER_DATA = dict( + id = 1, name = 'wxnacy' +) + +def dumps(): + ''' {"id": 1, "name": "wxnacy"} ''' + print(json.dumps(USER_DATA)) + +def dumps_indent(): + ''' + { + "id": 1, + "name": "wxnacy" + } + ''' + print(json.dumps(USER_DATA, indent=4)) + +def dumps_skipkeys(): + ''' + { + "id": 1, + "name": "wxnacy" + } + ''' + print(json.dumps(USER_DATA, skipkeys=True)) + +def dumps_skipkeys(): + ''' + { + "id": 1, + "name": "wxnacy" + } + ''' + print(json.dumps(USER_DATA, skipkeys=True)) + +if __name__ == "__main__": + dumps() + dumps_indent() + dumps_skipkeys() + diff --git a/python/simple/test.py b/python/simple/test.py index f02d762..0bfddad 100644 --- a/python/simple/test.py +++ b/python/simple/test.py @@ -7,6 +7,7 @@ import requests import os import subprocess +import bisect download_path = "/Users/wxnacy/Downloads/girls/" album_file = "/Users/wxnacy/PycharmProjects/study/python/scrapy_demo/first/album_neidi.json" @@ -54,17 +55,43 @@ def download_album(item): print(e) continue - -if __name__ == "__main__": - with open(album_file) as f : - text = f.read() - data = json.loads(text) - # data.sort() - data.reverse() - for i in data: - print(i) - download_album(i) +import bisect + +def binary_search(nums, n): + i = bisect.bisect_left(nums, n) + if i >= len(nums): + return -1 + else: + if nums[i] == n: + return i + else: + return -1 + +import unittest + +class TestMain(unittest.TestCase): + def setUp(self): + '''before each test function''' + pass + def tearDown(self): + '''after each test function''' + pass + + def do(self, func): + '''todo''' + self.assertEqual(1, 1) + pass + + def test_bs(self): + a = [1, 4, 4, 5, 6] + self.assertEqual(binary_search(a, 3), -1) + self.assertEqual(binary_search(a, 8), -1) + self.assertEqual(binary_search(a, 4), 1) + + +if __name__ == "__main__": + unittest.main() diff --git a/python/simple/walk.py b/python/simple/walk.py new file mode 100644 index 0000000..4675bf4 --- /dev/null +++ b/python/simple/walk.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: 实现类似 os.walk() 函数的功能 + +import os + +def walk(path, topdown=True, followlinks=False): + works = [path] + while works: + root = works[0] + dirs = [] + files = [] + names = os.listdir(root) + for n in names: + p = os.path.join(root, n) + if os.path.isdir(p): + dirs.append(n) + else: + files.append(n) + yield root, dirs, files + works.pop(0) + for n in dirs: + p = os.path.join(root, n) + if not os.path.islink(p): + works.append(p) + +def walk1(top, topdown=True, followlinks=False): + works = [top] + while works: + root = works[0] + dirs = [] + files = [] + names = os.listdir(root) + for n in names: + p = os.path.join(root, n) + if os.path.isdir(p): + dirs.append(n) + else: + files.append(n) + yield root, dirs, files + for n in dirs: + p = os.path.join(root, n) + if followlinks or not os.path.islink(p): + yield from walk1(top, topdown) + +# def walk1(path, topdown=True, followlinks=False): + # works = [path] + # while works: + # root = works[0] + # dirs = [] + # files = [] + # names = os.listdir(root) + # for n in names: + # p = os.path.join(root, n) + # if os.path.isdir(p): + # dirs.append(n) + # else: + # files.append(n) + # if topdown: + # yield root, dirs, files + # works.pop(0) + # for n in dirs: + # p = os.path.join(root, n) + # if followlinks or not os.path.islink(p): + # works.append(p) + # else: + # for w in works: + # yield from walk1(w, topdown, followlinks) + # yield root, dirs, files + +import unittest + +class TestMain(unittest.TestCase): + + def setUp(self): + '''before each test function''' + pass + + def tearDown(self): + '''after each test function''' + pass + + def do(self, func): + '''todo''' + for path in ("/Users/wxnacy/Projects/test/walk", + "/Users/wxnacy/Projects/test/walk/"): + ow = os.walk(path, ) + w = func(path) + for o in ow: + self.assertEqual(o, next(w)) + + def test_func(self): + self.do(walk) + self.do(walk1) + +if __name__ == "__main__": + unittest.main() + diff --git a/python/sorts/bubble_sort.py b/python/sorts/bubble_sort.py index 2cb3dcf..b31e489 100644 --- a/python/sorts/bubble_sort.py +++ b/python/sorts/bubble_sort.py @@ -1,25 +1,37 @@ #!/usr/bin/env python # -*- coding:utf-8 -*- # Author: wxnacy(wxnacy@gmail.com) -# Description: +# Description: 冒泡排序 -from random_util import rand_int_arr +import utils -def bubble_sort(arr): - leng = len(arr) +def bubble_sort(nums: list): + length = len(nums) + for i in range(length): + for j in range(i + 1, length): + if nums[i] > nums[j]: + nums[i], nums[j] = nums[j], nums[i] - def _temp(x, y): - temp = arr[x] - arr[x] = arr[y] - arr[y] = temp +import unittest - for i in range(leng): - for j in range(i + 1, leng): - if arr[i] > arr[j]: - _temp(i, j) +class TestMain(unittest.TestCase): + + def setUp(self): + '''before each test function''' + pass + + def tearDown(self): + '''after each test function''' + pass + + def do(self, func): + '''todo''' + for k, v in utils.randoms: + func(k) + self.assertEqual(k, v) + + def test_func(self): + self.do(bubble_sort) if __name__ == "__main__": - arr = rand_int_arr(10) - print(arr) - bubble_sort(arr) - print(arr) + unittest.main() diff --git a/python/sorts/bucket_sort.py b/python/sorts/bucket_sort.py new file mode 100644 index 0000000..76c2c15 --- /dev/null +++ b/python/sorts/bucket_sort.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: 桶排序,内部使用插入排序 + +import time +import random +import utils +from insertion_sort import insertion_sort + +def bucket_sort(nums: list, bucket_size = 5): + ''' + 使用字典来储存桶 + ''' + min_num, max_num = min(nums), max(nums) + bucket_count = ( max_num - min_num ) // bucket_size + 1 + buckets = {i : [] for i in range(bucket_count)} + for n in nums: + i = (n - min_num) // bucket_size + buckets[i].append(n) + res = [] + for i in range(len(buckets)): + insertion_sort(buckets[i]) + res.extend(buckets[i]) + return res + +def bucket_sort_array(nums: list, bucket_size = 5): + ''' + 使用数组来储存桶,通常比字典的方式要快一点 + bucket_size 为每个桶内的最大元素数 + ''' + min_num, max_num = min(nums), max(nums) # 获取最大、最小值 + bucket_count = ( max_num - min_num ) // bucket_size + 1 # 计算桶的大小 + buckets = [[] for i in range(bucket_count)] # 初始化空桶 + for n in nums: + i = (n - min_num) // bucket_size + buckets[i].append(n) # 将数字分配到相应的桶中 + res = [] + for b in buckets: + insertion_sort(b) # 将每个桶进行插入排序 + res.extend(b) # 将每个桶进行拼装 + return res + +import unittest + +class TestMain(unittest.TestCase): + + def setUp(self): + '''before each test function''' + pass + + def tearDown(self): + '''after each test function''' + pass + + def do(self, func): + '''todo''' + for k, v in utils.generate_randoms(10): + self.assertEqual(func(k), v) + + def test_func(self): + self.do(bucket_sort) + self.do(bucket_sort_array) + +if __name__ == "__main__": + + unittest.main() diff --git a/python/sorts/contrast_speed.py b/python/sorts/contrast_speed.py index 06f2cf9..a2ddd98 100644 --- a/python/sorts/contrast_speed.py +++ b/python/sorts/contrast_speed.py @@ -4,25 +4,70 @@ # Description: from quick_sort import quick_sort +from quick_sort import quick_sort_3partition from bubble_sort import bubble_sort -from random_util import rand_int_arr -import time - +from heap_sort import heap_sort +from merge_sort import merge_sort +from merge_sort import merge_sort_fastest +from counting_sort import counting_sort +from insertion_sort import insertion_sort +from bucket_sort import bucket_sort +from bucket_sort import bucket_sort_array +from selection_sort import selection_sort +from radix_sort import radix_sort +import utils +import os +import sys if __name__ == "__main__": - length = 1000 - print('长度为 {} 的随机数数组排序时长对比'.format(length)) - arr = rand_int_arr(length) - b = time.clock() - arr.sort() - print('arr.sort()\t', time.clock() - b) + length = 1 + n = 7000 + # print() + # for name, func in sys.modules.items(): + # print(name, func) + # # if '_sort' in name: + # # print(name, func.) + + # funcs = (bubble_sort, selection_sort, insertion_sort, quick_sort, + # quick_sort_3partition, heap_sort, merge_sort, merge_sort_fastest, + # counting_sort, bucket_sort, bucket_sort_array, radix_sort) + + times = [] + # for f in funcs: + # n, t = utils.print_func_run_time(length, f, utils.generate_random(int(n))[0]) + # # times.append((n, t)) + # # times.sort(key = lambda x: x[1]) + # # for n, t in times: + # # print(n, t) + + + times.append(utils.print_func_run_time(length, bubble_sort, + utils.generate_random(n)[0])) + times.append(utils.print_func_run_time(length, selection_sort, + utils.generate_random(n)[0])) + times.append(utils.print_func_run_time(length, insertion_sort, + utils.generate_random(n)[0])) + times.append(utils.print_func_run_time(length, quick_sort, + utils.generate_random(n)[0])) + times.append(utils.print_func_run_time(length, quick_sort_3partition, + utils.generate_random(n)[0])) + times.append(utils.print_func_run_time(length, heap_sort, + utils.generate_random(n)[0])) + times.append(utils.print_func_run_time(length, merge_sort, + utils.generate_random(n)[0])) + times.append(utils.print_func_run_time(length, merge_sort_fastest, + utils.generate_random(n)[0])) + times.append(utils.print_func_run_time(length, counting_sort, + utils.generate_random(n)[0])) + times.append(utils.print_func_run_time(length, bucket_sort, + utils.generate_random(n)[0])) + times.append(utils.print_func_run_time(length, bucket_sort_array, + utils.generate_random(n)[0])) + times.append(utils.print_func_run_time(length, radix_sort, + utils.generate_random(n)[0])) - arr = rand_int_arr(length) - b = time.clock() - quick_sort(arr) - print('quick_sort()\t', time.clock() - b) - arr = rand_int_arr(length) - b = time.clock() - bubble_sort(arr) - print('bubble_sort()\t', time.clock() - b) + print('正在排序') + times.sort(key = lambda x: x[1]) + for n, t in times: + print(n.ljust(25), t) diff --git a/python/sorts/counting_sort.py b/python/sorts/counting_sort.py new file mode 100644 index 0000000..abf583a --- /dev/null +++ b/python/sorts/counting_sort.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: + +import time +import random +import utils + +def counting_sort(nums: list, max_num=0): + if not max_num: + max_num = max(nums) + data = {} + for n in nums: + if n not in data: + data[n] = 0 + data[n] += 1 + res = [] + for i in range(max_num): + if i in data: + res.extend([i] * data[i]) + return res + +import unittest + +class TestMain(unittest.TestCase): + + def setUp(self): + '''before each test function''' + pass + + def tearDown(self): + '''after each test function''' + pass + + def do(self, func): + '''todo''' + for k, v in utils.generate_randoms(): + self.assertEqual(func(k, 100), v) + + def test_func(self): + self.do(counting_sort) + +if __name__ == "__main__": + unittest.main() diff --git a/python/sorts/heap_sort.py b/python/sorts/heap_sort.py new file mode 100644 index 0000000..24209df --- /dev/null +++ b/python/sorts/heap_sort.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: 堆排序 + +import time +import random +import utils + +def heap_sort(nums: list): + ''' + 每次都以最左边的索引当做划分点 + ''' + length = len(nums) + + def heapify(nums, i, heap_len): + k = i + left = i * 2 + 1 + right = i * 2 + 2 + + if left < heap_len and nums[left] > nums[k]: + k = left + if right < heap_len and nums[right] > nums[k]: + k = right + if k != i: + nums[i], nums[k] = nums[k], nums[i] + heapify(nums, k, heap_len) + + for i in range((length >> 1) - 1, -1, -1): + heapify(nums, i, length) + + for i in range(length - 1, 0, -1): + nums[0], nums[i] = nums[i], nums[0] + heapify(nums, 0, i) + +import unittest + +class TestMain(unittest.TestCase): + + def setUp(self): + '''before each test function''' + pass + + def tearDown(self): + '''after each test function''' + pass + + def do(self, func): + '''todo''' + for k, v in utils.randoms: + func(k) + self.assertEqual(k, v) + + def test_func(self): + self.do(heap_sort) + +if __name__ == "__main__": + unittest.main() diff --git a/python/sorts/insertion_sort.py b/python/sorts/insertion_sort.py new file mode 100644 index 0000000..c034616 --- /dev/null +++ b/python/sorts/insertion_sort.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: + +import time +import random +import utils + +def insertion_sort(nums: list): + for i in range(1, len(nums)): + current = nums[i] + prefix = i - 1 + while prefix >= 0 and nums[prefix] > current: + nums[prefix + 1] = nums[prefix] + prefix -= 1 + nums[prefix + 1] = current + +import unittest + +class TestMain(unittest.TestCase): + + def setUp(self): + '''before each test function''' + pass + + def tearDown(self): + '''after each test function''' + pass + + def do(self, func): + '''todo''' + for k, v in utils.generate_randoms(): + func(k) + self.assertEqual(k, v) + + def test_func(self): + self.do(insertion_sort) + +if __name__ == "__main__": + unittest.main() diff --git a/python/sorts/merge_sort.py b/python/sorts/merge_sort.py new file mode 100644 index 0000000..7dbfdcc --- /dev/null +++ b/python/sorts/merge_sort.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: 归并排序 + +import time +import random +import utils + +def merge_sort(nums: list): + def _merge(left, right): + res = [] + while left and right: + res.append(left.pop(0) if left[0] < right[0] else right.pop(0)) + return res + left + right + length = len(nums) + if length < 2: + return nums + mid = length // 2 + return _merge(merge_sort(nums[:mid]), merge_sort(nums[mid:])) + +def merge_sort_fastest(nums: list): + left, right = [], [] + colls = list(nums) + while len(colls) > 1: + min_num, max_num = min(colls), max(colls) + left.append(min_num) + right.append(max_num) + colls.remove(min_num) + colls.remove(max_num) + right.reverse() + return left + colls + right + +import unittest + +class TestMain(unittest.TestCase): + + def setUp(self): + '''before each test function''' + pass + + def tearDown(self): + '''after each test function''' + pass + + def do(self, func): + '''todo''' + for k, v in utils.generate_randoms(): + self.assertEqual(func(k), v) + + def test_func(self): + self.do(merge_sort) + self.do(merge_sort_fastest) + +if __name__ == "__main__": + count = 10 + tm = TestMain() + utils.print_unittest_do_run_time(count, tm.do, merge_sort) + utils.print_unittest_do_run_time(count, tm.do, merge_sort_fastest) + unittest.main() diff --git a/python/sorts/quick_sort.py b/python/sorts/quick_sort.py index 06f6f80..4c87e79 100644 --- a/python/sorts/quick_sort.py +++ b/python/sorts/quick_sort.py @@ -3,37 +3,84 @@ # Author: wxnacy(wxnacy@gmail.com) # Description: -import random_util import time +import random +import utils -def quick_sort(arr: list): - - def partition(arr, left, right): - t = arr[left] # 找出想要作为分割位的中间值 +def quick_sort(nums: list): + ''' + 每次都以最左边的索引当做划分点 + ''' + def partition(nums, left, right): + t = nums[left] # 找出想要作为分割位的中间值 x = left # 将左侧坐标重新初始化 y = right # 将右侧坐标重新初始化 while x < y: # 完成一次左右坐标相遇 - while x < y and arr[y] >= t: # 先从右侧查找一次小于中间值的数字 + while x < y and nums[y] >= t: # 先从右侧查找一次小于中间值的数字 y -= 1 - arr[x] = arr[y] # 将找到的数字赋值到左坐标的位置 - while x < y and arr[x] <= t: # 先从左侧查找一次大于中间值的数字 + nums[x] = nums[y] # 将找到的数字赋值到左坐标的位置 + while x < y and nums[x] <= t: # 先从左侧查找一次大于中间值的数字 x += 1 - arr[y] = arr[x] # 将找到的数字赋值到空出的右侧坐标位 + nums[y] = nums[x] # 将找到的数字赋值到空出的右侧坐标位 - arr[x] = t # 将中间值赋值到最后空出位置上 + nums[x] = t # 将中间值赋值到最后空出位置上 return x # 返回此次最终的中间位置 - def _sort(arr, left, right): + def _sort(nums, left, right): if left < right: - index = partition(arr, left, right) # 将数组做第一次分治 - _sort(arr, left, index - 1) # 将左侧数据做下一步分治 - _sort(arr, index + 1, right) # 将右侧数据做下一步分治 + index = partition(nums, left, right) # 将数组做第一次分治 + _sort(nums, left, index - 1) # 将左侧数据做下一步分治 + _sort(nums, index + 1, right) # 将右侧数据做下一步分治 + + _sort(nums, 0, len(nums) - 1) + +def quick_sort_3partition(nums: list): + + def _sort(nums, left, right): + if right <= left: + return + a = i = left + b = right + pivot = nums[left] + while i <= b: + if nums[i] < pivot: + nums[i], nums[a] = nums[a], nums[i] + a += 1 + i += 1 + elif nums[i] > pivot: + nums[i], nums[b] = nums[b], nums[i] + b -= 1 + else: + i += 1 + + _sort(nums, left, a - 1) + _sort(nums, b + 1, right) + + _sort(nums, 0, len(nums) - 1) + + + +import unittest + +class TestMain(unittest.TestCase): + + def setUp(self): + '''before each test function''' + pass + + def tearDown(self): + '''after each test function''' + pass + def do(self, func): + '''todo''' + for k, v in utils.randoms: + func(k) + self.assertEqual(k, v) - _sort(arr, 0, len(arr) - 1) + def test_func(self): + self.do(quick_sort) + self.do(quick_sort_3partition) if __name__ == "__main__": - arr = random_util.rand_int_arr(10) - print(arr) - quick_sort(arr) - print(arr) + unittest.main() diff --git a/python/sorts/radix_sort.py b/python/sorts/radix_sort.py new file mode 100644 index 0000000..5a7ae8a --- /dev/null +++ b/python/sorts/radix_sort.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: + +import time +import random +import utils + +def radix_sort(nums: list): + mod = 10 + div = 1 + max_num = max(nums) + while div < max_num: + + buckets = [[] for _ in range(10)] + for n in nums: + i = n % mod // div + buckets[i].append(n) + + c = 0 + for b in buckets: + for bn in b: + nums[c] = bn + c += 1 + + div *= 10 + mod *= 10 + + +import unittest + +class TestMain(unittest.TestCase): + + def setUp(self): + '''before each test function''' + pass + + def tearDown(self): + '''after each test function''' + pass + + def do(self, func): + '''todo''' + for k, v in utils.generate_randoms(): + func(k) + self.assertEqual(k, v) + + def test_func(self): + self.do(radix_sort) + +if __name__ == "__main__": + unittest.main() diff --git a/python/sorts/random_util.py b/python/sorts/random_util.py index 956da82..4802e1a 100644 --- a/python/sorts/random_util.py +++ b/python/sorts/random_util.py @@ -5,13 +5,12 @@ import random - def rand_int_arr(length): - arr = [] - for i in range(length): - r = random.randrange(1000) - arr.append(r) - return arr + # arr = [] + # for i in range(length): + # r = random.randrange(1000) + # arr.append(r) + return [random.randint(1, 1000) for i in range(length)] if __name__ == "__main__": arr = rand_int_arr(10) diff --git a/python/sorts/selection_sort.py b/python/sorts/selection_sort.py new file mode 100644 index 0000000..6dd28b2 --- /dev/null +++ b/python/sorts/selection_sort.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: + +import time +import random +import utils + +def selection_sort(nums: list): + for i in range(len(nums) - 1): + min_index = i + for j in range(i + 1, len(nums)): + if nums[j] < nums[min_index]: + min_index = j + + if min_index != i: + nums[i], nums[min_index] = nums[min_index], nums[i] + +import unittest + +class TestMain(unittest.TestCase): + + def setUp(self): + '''before each test function''' + pass + + def tearDown(self): + '''after each test function''' + pass + + def do(self, func): + '''todo''' + for k, v in utils.generate_randoms(): + func(k) + self.assertEqual(k, v) + + def test_func(self): + self.do(selection_sort) + +if __name__ == "__main__": + unittest.main() diff --git a/python/sorts/shell_sort.py b/python/sorts/shell_sort.py new file mode 100644 index 0000000..67299c1 --- /dev/null +++ b/python/sorts/shell_sort.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: 希尔排序 + +import time +import random +import utils + +def shell_sort(nums: list): + gap = 1 + while gap < len(nums) // 3: + gap = gap * 3 + 1 + + while gap > 0: + for i in range(gap, len(nums)): + tmp = nums[i] + j = i - gap + while j >= 0 and nums[j] > nums[i]: + nums[j + gap] = nums[j] + i -= 1 + nums[j + gap] = tmp + gap = gap // 3 + + +import unittest + +class TestMain(unittest.TestCase): + + def setUp(self): + '''before each test function''' + pass + + def tearDown(self): + '''after each test function''' + pass + + def do(self, func): + '''todo''' + for k, v in utils.generate_randoms(): + func(k) + self.assertEqual(k, v) + + def test_func(self): + self.do(shell_sort) + +if __name__ == "__main__": + unittest.main() diff --git a/python/sorts/test_sorts.py b/python/sorts/test_sorts.py new file mode 100644 index 0000000..51199ad --- /dev/null +++ b/python/sorts/test_sorts.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: + +import unittest +import utils +import quick_sort + +class TestMain(unittest.TestCase): + + def setUp(self): + '''before each test function''' + pass + + def tearDown(self): + '''after each test function''' + pass + + def do(self, func): + '''todo''' + for k, v in utils.randoms: + func(k) + self.assertEqual(k, v) + + def test_func(self): + self.do(quick_sort.quick_sort) + +if __name__ == "__main__": + unittest.main() + print(randoms) diff --git a/python/sorts/utils.py b/python/sorts/utils.py new file mode 100644 index 0000000..202833f --- /dev/null +++ b/python/sorts/utils.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: + +import random +import timeit + +def generate_random_ints(length: int): + return [random.randint(0, length) for i in range(length)] + +def generate_random(i=100): + nums = generate_random_ints(i) + res = list(nums) + nums.sort() + return res, nums + +randoms = [(generate_random(i)) for i in range(50, 200)] + +def generate_randoms(begin=50, end=100): + return [(generate_random(i)) for i in range(begin, end)] + + +def print_unittest_do_run_time(count, do_func, test_func): + ''' + 打印测试用例 do 方法所需的时间 + ''' + b = timeit.default_timer() + for i in range(count): + do_func(test_func) + t = timeit.default_timer() - b + print('{} run {} times used {}s'.format( + test_func.__name__.ljust(20), count, t)) + +def print_func_run_time(count, func, *args): + b = timeit.default_timer() + for i in range(count): + func(*args) + t = timeit.default_timer() - b + print('{} run {} times used {}s'.format( + func.__name__.ljust(20), count, t)) + return func.__name__, t + +if __name__ == "__main__": + arr = generate_random_ints(10) + print(arr) + arr.sort() + print(arr) diff --git a/python/test/test.py b/python/test/test.py new file mode 100644 index 0000000..284d0a4 --- /dev/null +++ b/python/test/test.py @@ -0,0 +1,6 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: + +from collections import namedtuple diff --git a/python/test/test_sorts.py b/python/test/test_sorts.py new file mode 100644 index 0000000..c37e958 --- /dev/null +++ b/python/test/test_sorts.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +# Author: wxnacy(wxnacy@gmail.com) +# Description: + +def quick_sort(nums): + + def partition(nums, left, right): + tmp = nums[left] + x = left + y = right + while x < y: + while x < y and nums[y] >= tmp: + y -= 1 + nums[x] = nums[y] + while x < y and nums[x] <= tmp: + x += 1 + nums[y] = nums[x] + nums[x] = tmp + return x + + def _sort(nums, left, right): + if left >= right: + return + + part = partition(nums, left, right) + _sort(nums, left, part - 1) + _sort(nums, part + 1, right) + + _sort(nums, 0, len(nums) - 1) + + +if __name__ == "__main__": + nums = [6, 7, 4, 5, 9, 1, 3, 2, 8] + quick_sort(nums) + print(nums) +