diff --git "a/20\347\276\216\345\244\232\345\225\206\345\237\216\351\241\271\347\233\256/README.md" "b/20\345\244\251\345\244\251\347\224\237\351\262\234\351\241\271\347\233\256/README.md" similarity index 98% rename from "20\347\276\216\345\244\232\345\225\206\345\237\216\351\241\271\347\233\256/README.md" rename to "20\345\244\251\345\244\251\347\224\237\351\262\234\351\241\271\347\233\256/README.md" index c72f2b2..38a8d41 100644 --- "a/20\347\276\216\345\244\232\345\225\206\345\237\216\351\241\271\347\233\256/README.md" +++ "b/20\345\244\251\345\244\251\347\224\237\351\262\234\351\241\271\347\233\256/README.md" @@ -1,6 +1,6 @@ # 20 美多商城项目[](https://github.com/sindresorhus/awesome) -具体的请查看该篇章中的代码实现。 +具体的请查看https://github.com/HaoZhang95/dailyfresh 这个仓库的代码实现 **** |Author|白发老书生| diff --git "a/23\347\224\265\345\225\206\347\210\254\350\231\253\345\222\214Scrapy\346\241\206\346\236\266/day01/basic02.py" "b/23\347\224\265\345\225\206\347\210\254\350\231\253\345\222\214Scrapy\346\241\206\346\236\266/day01/basic02.py" index f2035d3..28d46e5 100644 --- "a/23\347\224\265\345\225\206\347\210\254\350\231\253\345\222\214Scrapy\346\241\206\346\236\266/day01/basic02.py" +++ "b/23\347\224\265\345\225\206\347\210\254\350\231\253\345\222\214Scrapy\346\241\206\346\236\266/day01/basic02.py" @@ -27,8 +27,6 @@ def test01(): """ - - def main(): test01() diff --git "a/26\346\225\260\346\215\256\347\273\223\346\236\204/day01/01basic.py" "b/26\346\225\260\346\215\256\347\273\223\346\236\204/day01/01basic.py" new file mode 100644 index 0000000..198b2fc --- /dev/null +++ "b/26\346\225\260\346\215\256\347\273\223\346\236\204/day01/01basic.py" @@ -0,0 +1,67 @@ +""" + 算法就类似于兵法, test1的执行时间为110s, 第二个执行时间为1s + 但是不能淡出的以时间来衡量,因为执行程序的机器配置不同,所以时间不能全面的反应算法的优劣 +""" +import time + + +def test1(): + start_time = time.time() + for a in range(0, 1001): + for b in range(0, 1001): + for c in range(0, 1001): + if a + b + c == 1000 and a ** 2 + b ** 2 == c ** 2: + print("a, b, c: %d, %d, %d" % (a, b, c)) + + end_time = time.time() + print("finished: %s" % (end_time - start_time)) + + +""" + 如果a+b+c=1000,且a^2+b^2=c^2的a,b,c的组合 + N是程序的规模,例子中N就是1000, a+b+c=N,描述的一类问题 + 时间复杂度:就是程序执行的步骤, T(n) = N^3 * (1+1) 也就是1000的三次方 + 大O记法:时间复杂度的简化分析,算法分析的是数量级和趋势,不计较规模函数中的常量因子,简化为O(n)=N^3,图线特征和趋势,类似于渐进函数 + + Test2中:T(n) = n * n * (1 + max(1, 0)) + = n ^2 *2 + = O(n^2) +""" + + +def test2(): + + start_time = time.time() + for a in range(0, 1001): + for b in range(0, 1001): + # 此时c就已经确立了,不需要循环1000次了 + c = 1000 - a - b + if a + b + c == 1000 and a ** 2 + b ** 2 == c ** 2: + print("a, b, c: %d, %d, %d" % (a, b, c)) + + end_time = time.time() + print("finished: %s" % (end_time - start_time)) + + +def test3(): + list1 = [1, 23, 4, 1, 4, 6] + list2 = [1, 2, 3, 4, 5, 6] + + """ + 如果排序list1和list2的话,list1的时间复杂度和N^2,最坏时间复杂度(一种保证),一般使用的就是最坏时间复杂度 + list2碰巧为有序的列表,遍历一次即可,时间复杂度为最优时间复杂度,没意义 + + 基本操作算一个时间复杂度O(1) 即只有常数项 + 顺序结构采用加法 + 循环结构使用乘法 + 分支结构采取最大值,if和else中谁的步骤多,if中的条件判断不加进去 + 只关注数量级的最高项,一般忽略常量 + + """ + + +if __name__ == '__main__': + # test1() + # test2() + # test3() + pass diff --git "a/26\346\225\260\346\215\256\347\273\223\346\236\204/day01/02basic.py" "b/26\346\225\260\346\215\256\347\273\223\346\236\204/day01/02basic.py" new file mode 100644 index 0000000..ad7653e --- /dev/null +++ "b/26\346\225\260\346\215\256\347\273\223\346\236\204/day01/02basic.py" @@ -0,0 +1,58 @@ +def test1(): + l = [] + for i in range(1000): + l = l + [i] + + +def test2(): + l = [] + for i in range(1000): + l.append(i) + + +def test3(): + l = [i for i in range(1000)] + + +def test4(): + l = list(range(1000)) + + +from timeit import Timer + +# setup中是从从__main__也就是当前文件名02basic中找到test1 +# 创建一个timer对象 +t1 = Timer(stmt="test1()", setup="from __main__ import test1") +print("concat ", t1.timeit(number=1000), "seconds") +t2 = Timer("test2()", "from __main__ import test2") +print("append ", t2.timeit(number=1000), "seconds") +t3 = Timer("test3()", "from __main__ import test3") +print("comprehension ", t3.timeit(number=1000), "seconds") +t4 = Timer("test4()", "from __main__ import test4") +print("list range ", t4.timeit(number=1000), "seconds") + +# ('concat ', 1.7890608310699463, 'seconds') +# ('append ', 0.13796091079711914, 'seconds') +# ('comprehension ', 0.05671119689941406, 'seconds') +# ('list range ', 0.014147043228149414, 'seconds') + +""" + 一个int类型占用4个字节,内存就是一系列连续的存储单元,单元是以字节表示,int a = 1,二进制就是00000000 00000000 00000000 00000001 + 顺序表就是将类型一致的变量存在连续的存储单元中,li = [1,2,3]这样的物理地址是连续的为0x01, 0x05, 0x09 c是指该类型的存储大小,int类型的话就是4 + + 顺序表中的元素外置可以解决列表中的不同数据类型,每个列表的存储都是4个字节4个字节的格子,每个格子存储的是地址指向不同的数据类型的外置元素 + 列表中的地址存储就是占用4个字节的存储单元 + + 顺序表中的表头区和数据区,表头信息包含该数据表中的整体信息,比如容量和实际元素个数都存储在表头信息中,一般使用分离式的存储表头信息 + 表头信息可以使用一体式的存储方式或者外链式的存储,具体表头存储采用哪一种方式,主要的区别就是扩容的时候,一体式的方式表头信息的地址会变化 + + 扩容的策略:固定的每次扩容增加10个位置,线性增长,不过需要频繁的进行扩容操作 + 或者倍增的方式,减少扩容的请求,空间换取时间 +""" + +""" + 链表的原理就是node节点,每个元素的存储地址不连续,使用前一个节点记录下一个元素的位置进行串起来,就像手链一样 + 单向链表LinkedList中只有数据区和下一个节点物理地址,双向链表是记录着上一个节点的位置,单向链表并没有记录上一个节点的物理地址 + + python是弱类型语言,因为a = 10中a这个变量名也占用一份内存,不像java中的int a = 10 a只是10这个物理地址的别名,a也不能赋值其他类型的值 +""" diff --git "a/26\346\225\260\346\215\256\347\273\223\346\236\204/day01/03basic.py" "b/26\346\225\260\346\215\256\347\273\223\346\236\204/day01/03basic.py" new file mode 100644 index 0000000..9719c61 --- /dev/null +++ "b/26\346\225\260\346\215\256\347\273\223\346\236\204/day01/03basic.py" @@ -0,0 +1,116 @@ +class Node(object): + """单链表的节点""" + + def __init__(self, elem): + self.elem = elem + self.next = None + + +class SingleLinkedList(object): + """单链表的结构""" + + def __init__(self, node=None): + # 头节点不需要暴露,使用私有属性 + self.__head = node + + def is_empty(self): + return self.__head is None + + def length(self): + cur = self.__head + count = 0 + + while cur is not None: + count += 1 + cur = cur.next + + return count + + def travel(self): + # 游标用来移动遍历节点 + cur = self.__head + while cur is not None: + print(cur.elem, end=" ") + cur = cur.next + print('\n') + + def add(self, item): + """头部插入元素""" + node = Node(elem=item) + # 注意下面两行的顺序 + node.next = self.__head + self.__head = node + + def append(self, item): + """尾部插入节点""" + node = Node(elem=item) + if self.is_empty(): + self.__head = node + else: + cur = self.__head + # 注意cur和cur.next的不同使用 + while cur.next is not None: + cur = cur.next + cur.next = node + + def insert(self, pos, item): + if pos <= 0: + self.add(item) + elif pos > self.length()-1: + self.append(item) + else: + pre = self.__head + count = 0 + + while count < (pos-1): + count += 1 + pre = pre.next + # 循环推出后pre指向pos-1位置 + node = Node(elem=item) + node.next = pre.next + pre.next = node + + def remove(self, item): + cur = self.__head + pre = None + + while cur is not None: + if cur.elem == item: + # 判断是不是头节点 + if cur == self.__head: + self.__head = cur.next + else: + pre.next = cur.next + break + else: + pre = cur + cur = cur.next + + + def search(self, item): + cur = self.__head + while cur is not None: + if cur.elem == item: + return True + else: + cur = cur.next + return False + + +def main(): + ll = SingleLinkedList() + print(ll.is_empty()) + print(ll.length()) + + ll.append(1) + print(ll.is_empty()) + print(ll.length()) + + ll.append(2) + ll.add(8) + ll.append(3) + ll.travel() + + +if __name__ == '__main__': + main() diff --git "a/26\346\225\260\346\215\256\347\273\223\346\236\204/day01/__init__.py" "b/26\346\225\260\346\215\256\347\273\223\346\236\204/day01/__init__.py" new file mode 100644 index 0000000..e69de29 diff --git "a/26\346\225\260\346\215\256\347\273\223\346\236\204/day02/01basic.py" "b/26\346\225\260\346\215\256\347\273\223\346\236\204/day02/01basic.py" new file mode 100644 index 0000000..d799215 --- /dev/null +++ "b/26\346\225\260\346\215\256\347\273\223\346\236\204/day02/01basic.py" @@ -0,0 +1,105 @@ +""" + 双向链表 +""" + + +class Node(object): + def __init__(self, item): + self.item = item + self.next = None + self.prev = None + + +class DoubleLinkedList(object): + def __init__(self, node=None): + # 头节点不需要暴露,使用私有属性 + self.__head = node + + def is_empty(self): + return self.__head is None + + def length(self): + cur = self.__head + count = 0 + + while cur is not None: + count += 1 + cur = cur.next + + return count + + def travel(self): + # 游标用来移动遍历节点 + cur = self.__head + while cur is not None: + print(cur.elem, end=" ") + cur = cur.next + print('\n') + + def add(self, item): + """头部插入元素""" + node = Node(elem=item) + # 注意下面两行的顺序 + node.next = self.__head + self.__head = node + node.next.prev = node + + def append(self, item): + """尾部插入节点""" + node = Node(elem=item) + if self.is_empty(): + self.__head = node + else: + cur = self.__head + # 注意cur和cur.next的不同使用 + while cur.next is not None: + cur = cur.next + cur.next = node + node.prev = cur + + def insert(self, pos, item): + if pos <= 0: + self.add(item) + elif pos > self.length() - 1: + self.append(item) + else: + cur = self.__head + count = 0 + + while count < pos: + count += 1 + cur = cur.next + # 循环推出后pre指向pos-1位置 + node = Node(item) + node.next = cur + node.prev = cur.prev + cur.prev.next = node + cur.prev = node + + def remove(self, item): + cur = self.__head + + while cur is not None: + if cur.elem == item: + # 判断是不是头节点 + if cur == self.__head: + self.__head = cur.next + if cur.next is not None: + # 如果链表不是只有一个节点 + cur.next.prev = None + else: + cur.prev.next = cur.next + if cur.next is not None: + cur.next.prev = cur.prev + break + else: + cur = cur.next + + def search(self, item): + cur = self.__head + while cur is not None: + if cur.elem == item: + return True + else: + cur = cur.next + return False diff --git "a/26\346\225\260\346\215\256\347\273\223\346\236\204/day02/02basic.py" "b/26\346\225\260\346\215\256\347\273\223\346\236\204/day02/02basic.py" new file mode 100644 index 0000000..45fe9e6 --- /dev/null +++ "b/26\346\225\260\346\215\256\347\273\223\346\236\204/day02/02basic.py" @@ -0,0 +1,157 @@ +class Node(object): + """单链表的节点""" + + def __init__(self, elem): + self.elem = elem + self.next = None + + +class SingleCycleLinkedList(object): + """单链表的结构""" + + def __init__(self, node=None): + # 头节点不需要暴露,使用私有属性 + self.__head = node + + def is_empty(self): + return self.__head is None + + def length(self): + + if self.is_empty(): + return 0 + + cur = self.__head + # while的循环条件变了,count不能从0开始,否则缺少最后一个节点 + count = 1 + while cur.next is not self.__head: + count += 1 + cur = cur.next + + return count + + def travel(self): + # 游标用来移动遍历节点 + cur = self.__head + while cur is not None: + print(cur.elem, end=" ") + cur = cur.next + + # 退出循环后,cur指向最后节点,但是最后节点没被打印 + print(cur.elem) + print('\n') + + def add(self, item): + """头部插入元素,把尾节点的next指向第一个节点""" + node = Node(elem=item) + if self.is_empty(): + self.__head = node + node.next = node + return + + cur = self.__head + while cur.next is not self.__head: + cur = cur.next + # 注意下面两行的顺序 + node.next = self.__head + self.__head = node + cur.next = self.__head + + def append(self, item): + """尾部插入节点""" + node = Node(elem=item) + if self.is_empty(): + self.__head = node + node.next = node + else: + cur = self.__head + # 注意cur和cur.next的不同使用 + while cur.next is not self.__head: + cur = cur.next + + node.next = self.__head + cur.next = node + + def insert(self, pos, item): + if pos <= 0: + self.add(item) + elif pos > self.length() - 1: + self.append(item) + else: + pre = self.__head + count = 0 + + while count < (pos - 1): + count += 1 + pre = pre.next + # 循环推出后pre指向pos-1位置 + node = Node(elem=item) + node.next = pre.next + pre.next = node + + def remove(self, item): + if self.is_empty(): + return + + cur = self.__head + pre = None + + while cur.next is not self.__head: + if cur.elem == item: + # 判断是不是头节点 + if cur == self.__head: + rear = self.__head + while rear.next is not self.__head: + rear = rear.next + self.__head = cur.next + rear.next = self.__head + + else: + pre.next = cur.next + return + else: + pre = cur + cur = cur.next + + if cur.elem == item: + if cur is self.__head: + # 链表只有一个节点 + self.__head = None + else: + pre.next = cur.next + + def search(self, item): + + if self.is_empty(): + return False + + cur = self.__head + while cur.next is not self.__head: + if cur.elem == item: + return True + else: + cur = cur.next + # 此时的cur指向最后一个元素 + if cur.elem == item: + return True + + return False + + +def main(): + ll = SingleCycleLinkedList() + print(ll.is_empty()) + print(ll.length()) + + ll.append(1) + print(ll.is_empty()) + print(ll.length()) + + ll.append(2) + ll.add(8) + ll.append(3) + ll.travel() + + +if __name__ == '__main__': + main() diff --git "a/26\346\225\260\346\215\256\347\273\223\346\236\204/day02/__init__.py" "b/26\346\225\260\346\215\256\347\273\223\346\236\204/day02/__init__.py" new file mode 100644 index 0000000..e69de29 diff --git "a/26\346\225\260\346\215\256\347\273\223\346\236\204/day03/01basic.py" "b/26\346\225\260\346\215\256\347\273\223\346\236\204/day03/01basic.py" new file mode 100644 index 0000000..3aabb92 --- /dev/null +++ "b/26\346\225\260\346\215\256\347\273\223\346\236\204/day03/01basic.py" @@ -0,0 +1,83 @@ +""" + 堆栈就像水杯一样,一种容器,类似于顺序表结构但是只有push和pop,一端进出,后进的先出去 + 队列就像排队一样,先来的先出去 +""" + + +class Stack(object): + def __init__(self): + self.__list = [] + + def push(self, item): + self.__list.append(item) + # 可以选择append和insert0的方式,不过insert的方式时间复杂度为O(n) + # self.__list.insert(0) + # self.__list.pop(0) + + def pop(self): + self.__list.pop() + + def peek(self): + if self.__list: + return self.__list[-1] + else: + return None + + def is_empty(self): + # return not self.__list + # return self.__list == [] + return self.size() == 0 + + def size(self): + return len(self.__list) + + +class Queue(object): + def __init__(self): + self.__list = [] + + def enqueue(self, item): + self.__list.append(item) + # 可以选择append和insert0的方式,不过insert的方式时间复杂度为O(n) + # self.__list.insert(0, item) + # self.__list.pop() + + def dequeue(self): + self.__list.pop(0) + + def is_empty(self): + # return not self.__list + # return self.__list == [] + return self.size() == 0 + + def size(self): + return len(self.__list) + + +class Deque(object): + """ + double-ended-queue双端队列,两端都可以进行push和pop,类似于两个堆栈底部合起来 + + """ + def __init__(self): + self.__list = [] + + def add_front(self, item): + self.__list.insert(0, item) + + def ad_rear(self, item): + self.__list.append(item) + + def remove_front(self): + self.__list.pop(0) + + def remove_rear(self): + self.__list.pop() + + def is_empty(self): + # return not self.__list + # return self.__list == [] + return self.size() == 0 + + def size(self): + return len(self.__list) \ No newline at end of file diff --git "a/26\346\225\260\346\215\256\347\273\223\346\236\204/day03/02_bubble_sort.py" "b/26\346\225\260\346\215\256\347\273\223\346\236\204/day03/02_bubble_sort.py" new file mode 100644 index 0000000..918a1e6 --- /dev/null +++ "b/26\346\225\260\346\215\256\347\273\223\346\236\204/day03/02_bubble_sort.py" @@ -0,0 +1,28 @@ + +def bubble_sort(alist): + + n = len(alist) + for j in range(0, n-1): + # j表示需要n-1次冒泡过程, i表示一次冒泡过程中的交换 + + count = 0 + for i in range(0, n-j-1): + # 只需要到列表的n-1位置,因为从0开始正好range结尾是闭区间,所以只需要-1 + # 比如总共9个元素,需要遍历到第八个位置,让其跟8+1去比较,第八个元素的索引是7,所以range(0, 8) + if alist[i] > alist[i+1]: + alist[i], alist[i+1] = alist[i+1], alist[i] + count += 1 + """ + 每次冒泡的过程count都为0来记录这次冒泡过程中是否有交换发生 + 如果只要有一次冒泡过程中没有交换发生直接结束循环,表示前面的都是有序的 + [1,2,3,9,8]第三次循环的时候发现count没变,直接return + """ + if 0 == count: + """ + break, continue, return的区别主要表现在终止循环的层数上面 + break终止的是当前循环层,因为这里正好处于最外层的for j循环中,所以下面的return可以被break替换 + return终止所有循环层,表示此函数终止 + continue跳过本次循环 + """ + return + diff --git "a/26\346\225\260\346\215\256\347\273\223\346\236\204/day03/03_select_sort.py" "b/26\346\225\260\346\215\256\347\273\223\346\236\204/day03/03_select_sort.py" new file mode 100644 index 0000000..40bc8ee --- /dev/null +++ "b/26\346\225\260\346\215\256\347\273\223\346\236\204/day03/03_select_sort.py" @@ -0,0 +1,29 @@ + +def select_sort(alist): + + """ + 选择排序:从无序队列中选择最小的放到前面去,有序部分和无序部分 + 首先认为最小的元素就是第一个元素,不断比较更新这个min的数值 + """ + for j in range(0, len(alist)-1): + + min_index = j + # 因为j要和剩余的部分作比较也就是从j+1到最后一个元素,n的索引为n-1,闭区间所以到n + for i in range(j+1, len(alist)): + if alist[min_index] > alist[i]: + min_index = i + + alist[j], alist[min_index] = alist[min_index], alist[j] + + """ + j从0开始比较到倒数第二个元素,总共9个元素,最后让8和8+1比较,所以range:9-1=8,闭区间只能到7 + 内层循环中让j和j+1比较,更新min_index和剩余无序部分的数值 + 时间复杂度为O(n^2) + """ + + """ + 排序中的稳定性,如果列表中两个元素相等,排序如果可能出现这两个相等元素的位置不固定的话,则为不稳定排序 + [1, 3, 2, 2] + """ + + diff --git "a/26\346\225\260\346\215\256\347\273\223\346\236\204/day03/04_insert_sort.py" "b/26\346\225\260\346\215\256\347\273\223\346\236\204/day03/04_insert_sort.py" new file mode 100644 index 0000000..379881a --- /dev/null +++ "b/26\346\225\260\346\215\256\347\273\223\346\236\204/day03/04_insert_sort.py" @@ -0,0 +1,23 @@ + +def insert_sort(alist): + + """ + 插入排序:认为第一个元素是最小的,从第二个依次取出去放到前面合适的位置,如果比第一个小,就插到第一个前面,再去取第三个元素比较 + 和选择排序不同,选择排序是遍历一遍寻找最小的,放在前面,再比较剩下最小的,放在第二个位置 + """ + + for j in range(1, len(alist)): + """ + j 表示拿第二个元素到最后一个元素去跟前一个去比较的循环 + 最优时间复杂度O(n),进去就break的情况 + 最坏时间复杂度O(n^2) + """ + i = j + + while i > 0: + if alist[i] < alist[i-1]: + alist[i], alist[i-1] = alist[i-1], alist[i] + i -= 1 + else: + # 表示当前元素所移动的位置前面正好合适,结束当前元素的移动 + break diff --git "a/26\346\225\260\346\215\256\347\273\223\346\236\204/day03/04_shell_sort.py" "b/26\346\225\260\346\215\256\347\273\223\346\236\204/day03/04_shell_sort.py" new file mode 100644 index 0000000..8b1b0f0 --- /dev/null +++ "b/26\346\225\260\346\215\256\347\273\223\346\236\204/day03/04_shell_sort.py" @@ -0,0 +1,36 @@ + +def shell_sort(alist): + + """ + 希尔排序:是插入排序的增改版 + 通过GAP增量来分组进行插入排序,排序好的小组进行到一起进行下一次排序 + 下一次排序的时候GAP=2进行再次插入排序,GAP=1的时候就是纯粹的插入排序 + """ + n = len(alist) + gap = n // 2 # 取整数 + + # gap变化到0之前,插入算法执行的次数 + while gap >= 1: + + for j in range(gap, n): + """ + 通过一个for循环把几个分组都遍历到,从gap开始,类似于列表中间的一条竖线,gap,gap+1,gap+2...gap+n-1 + 通过for j 中间后面的元素结合i-gap来插入排序中间线前面的元素 + 时间复杂度O(n^2),为不稳定排序,另一个分组的相同元素可能排到前面去 + """ + i = j + + while i > 0: + if alist[i] < alist[i-gap]: + alist[i], alist[i-gap] = alist[i-gap], alist[i] + i -= gap + else: + break + # 缩短gap接着计算 + gap //= 2 + + # n = 9 + # i1 = n / 2 + # i2 = n // 2 + # print(i1) # 浮点数触发 4.5 + # print(i2) # 整数除法 4 diff --git "a/26\346\225\260\346\215\256\347\273\223\346\236\204/day03/05_quick_sort.py" "b/26\346\225\260\346\215\256\347\273\223\346\236\204/day03/05_quick_sort.py" new file mode 100644 index 0000000..00299e4 --- /dev/null +++ "b/26\346\225\260\346\215\256\347\273\223\346\236\204/day03/05_quick_sort.py" @@ -0,0 +1,44 @@ + +def quick_sort(alist, first, last): + + """ + 快速排序不像之前的那样把序列分成两部分 + 而是第一个元素通过一个low一个high游标相夹, low的左边都比第一个元素小,high的右边都比第一个元素大 + 以此来确定第一个元素在序列中的位置 + 时间复杂度O(nlogn) 第一次分成2部分,2部分分成4部分,也就是 2*2*2*...=n 也就是logn次才能变成一个个单独元素的数组推出递归 + 如果9个元素的话,n = log2为底9,结果为3,横向为n,纵向为logn总体最优复杂度为O(nlogn),最坏为O(n^2) + """ + + # 递归终止条件,如果递归的数组只有一个元素的时候 + if first >= last: + return + + low = first + high = last + mid_value = alist[first] + + while low < high: + """遇到相等元素,等号放在随便的一遍,这里放在了high移动的一边""" + while low < high and alist[high] >= mid_value: + """如果low和high在向中间走的过程中没有相遇,并且high的元素大于当前mid_value就继续向左移动""" + high -= 1 + # 移动完发现不大于,那么就交换一下位置,high暂停移动,low开始移动 + alist[low] = alist[high] + # low += 1 + + while low < high and alist[low] < mid_value: + """如果low和high在向中间走的过程中没有相遇,并且low的元素小于当前mid_value就继续向右移动""" + low += 1 + alist[high] = alist[low] + # high -= 1 + + alist[low] = mid_value + + # 把一个元素放在正确的位置之后,递归左边和右边的部分 + # 但是切片返回的是一个新的数组,不合适,需要手动更新low,high的位置 + # quick_sort(alist[:low]) + # quick_sort(alist[low:]) + + # 对low左边和右边的数组递归 + quick_sort(alist, first, low-1) + quick_sort(alist, low+1, last) \ No newline at end of file diff --git "a/26\346\225\260\346\215\256\347\273\223\346\236\204/day03/06_merge_sort.py" "b/26\346\225\260\346\215\256\347\273\223\346\236\204/day03/06_merge_sort.py" new file mode 100644 index 0000000..ded9ca0 --- /dev/null +++ "b/26\346\225\260\346\215\256\347\273\223\346\236\204/day03/06_merge_sort.py" @@ -0,0 +1,30 @@ + +def merge_sort(alist): + + """ + 归并排序:对数组进行对半拆分,直到每个只有一个元素,然后进行合并 + 合并中 + """ + n = len(alist) + if n <= 1: + return alist + + mid = n // 2 + left_li = merge_sort(alist[:mid]) + right_li = merge_sort(alist[mid:]) + + left_pointer, right_pointer = 0, 0 + result = [] + + while left_pointer < len(left_li) and right_pointer < len(right_li): + + if left_li[left_pointer] < right_li[right_pointer]: + result.append(left_li[left_pointer]) + left_pointer += 1 + else: + result.append(right_li[right_pointer]) + right_pointer += 1 + + result += left_li[left_pointer:] + result += right_li[right_pointer:] + return result diff --git "a/26\346\225\260\346\215\256\347\273\223\346\236\204/day03/__init__.py" "b/26\346\225\260\346\215\256\347\273\223\346\236\204/day03/__init__.py" new file mode 100644 index 0000000..e69de29 diff --git "a/26\346\225\260\346\215\256\347\273\223\346\236\204/day04/01_binary_search.py" "b/26\346\225\260\346\215\256\347\273\223\346\236\204/day04/01_binary_search.py" new file mode 100644 index 0000000..28ffdc7 --- /dev/null +++ "b/26\346\225\260\346\215\256\347\273\223\346\236\204/day04/01_binary_search.py" @@ -0,0 +1,43 @@ +def binary_search(alist, item): + """二分法查找,递归方法""" + + n = len(alist) + mid = n // 2 + + if n > 0: + + if alist[mid] == item: + return True + elif item < alist[mid]: + # 产生新的列表进行递归 + return binary_search(alist[:mid], item) + else: + return binary_search(alist[mid:], item) + + return False + + +""" + 二分法查找的折半查找,操作的对象必须有序,其次计算mid需要index需要顺序表才行 + 时间复杂度为 折半2的几次方等于n,最坏所以为 O(logn),最好就是O(1) +""" + + +def binary_search_2(alist, item): + """二分法查找,非递归方法""" + + n = len(alist) + first = 0 + last = n - 1 + + while first <= last: + + mid = (first + last) // 2 + + if item == alist[mid]: + return True + elif item < alist[mid]: + last = mid - 1 + else: + first = mid + 1 + return False diff --git "a/26\346\225\260\346\215\256\347\273\223\346\236\204/day04/02_tree.py" "b/26\346\225\260\346\215\256\347\273\223\346\236\204/day04/02_tree.py" new file mode 100644 index 0000000..8aebcb4 --- /dev/null +++ "b/26\346\225\260\346\215\256\347\273\223\346\236\204/day04/02_tree.py" @@ -0,0 +1,98 @@ +""" + 树分为好多种,二叉树就是一个父节点最多只能包含两个子节点,树的度最多为2 + + 完全二叉树:如果有n层,那么除了最底层之外的节点都挂满了子节点,父节点都达到了最大的度 + 满二叉树:所有节点都达到最大的度,包含最底层 + 平衡二叉树:当且仅当任意一个节点的**两颗子树**的高度差不大于1的二叉树 + 有序二叉树:树的每一个节点都是有序的,根节点左边的节点都比根节点小,右边的都比根节点大 +""" + +""" + 树的存储: + 如果采用顺序存储的话,那么以数组的方式,装完一层之后去装下一层的节点,虽然遍历上有优势,但是占用空间大,非主流的存储方式 + 一般采用的就是链式的存储方式,树常用在xml,html的解析中,mysql的索引,路由协议,文件系统的目录结构 +""" + + +class Node(object): + """树的结构类似于链表的扩充,也需要节点""" + + def __init__(self, elem=None, lchild=None, rchild=None): + self.elem = elem + self.lchild = lchild + self.rchild = rchild + + +class Tree(object): + + def __init__(self, root): + self.root = root + + def add(self, item): + """完全二叉树的添加,那一层缺元素的话那么就直接添加到该层的节点,那一层的节点没满就添加到此处""" + node = Node(item) + if self.root is None: + self.root = node + return + + queue = [self.root] + while queue: + # 只要队列存在元素,就pop判断 + cur_node = queue.pop(0) + if cur_node.lchild is None: + cur_node.lchild = node + return + else: + queue.append(cur_node.lchild) + + if cur_node.rchild is None: + cur_node.rchild = node + return + else: + queue.append(cur_node.rchild) + + def breadth_travel(self): + """广度遍历""" + if self.root is None: + return + + queue = [self.root] + while queue: + + cur_node = queue.pop(0) + print(cur_node) + + if cur_node.lchild is not None: + queue.append(cur_node.lchild) + if cur_node.rchild is not None: + queue.append(cur_node.rchild) + + def pre_order(self, node): + """深度遍历中的先序便利,根节点先, 根 -> 左 -> 右""" + + if node is None: + return + + print(node.elem) + self.pre_order(node.lchild) + self.pre_order(node.rchild) + + def in_order(self, node): + """深度遍历中的中序便利,根节点在中, 左 -> 根 -> 右""" + + if node is None: + return + + self.in_order(node.lchild) + print(node.elem) + self.in_order(node.rchild) + + def post_order(self, node): + """深度遍历中的后序便利,根节点在后, 左 -> 右 -> 后""" + + if node is None: + return + + self.post_order(node.lchild) + self.post_order(node.rchild) + print(node.elem) diff --git "a/26\346\225\260\346\215\256\347\273\223\346\236\204/day04/__init__.py" "b/26\346\225\260\346\215\256\347\273\223\346\236\204/day04/__init__.py" new file mode 100644 index 0000000..e69de29 diff --git a/README.md b/README.md index 1e61618..03db3e4 100644 --- a/README.md +++ b/README.md @@ -2,29 +2,47 @@ -传智播客&黑马出品的Python24期人工智能整套代码和讲义集合,仓库主要为了学习Python和机器学习基础,每一章的具体知识点可以在下面的目录中详细查看课程大纲,具体的讲义文档,提供在线阅读和下载,大部分的章节讲义使用了Gitbook进行整章的阅读,同样的,在学习的过程中,我在代码中都每行进行了注释,基本上不用看文档也能理解,方便进行阅读和理解,希望能够帮助大家。资源搜集劳神费力,望大家多多支持,喜欢本仓库的话,记得Star哦。 +仓库主要为了学习Python和机器学习基础,每一章的具体知识点可以在下面的目录中详细查看课程大纲,具体的讲义文档,提供在线阅读和下载,大部分的章节讲义使用了Gitbook进行整章的阅读,同样的,在学习的过程中,我在代码中都每行进行了注释,基本上不用看文档也能理解,方便进行阅读和理解,**望大家多多支持,喜欢本仓库的话,记得Star哦,希望能够帮助大家。** **** |Author|白发老书生| |---|--- -|E-mail|Github联系 -> 最近更新至第23章节(共30章节):2019-05-08 +|E-mail|请提交issue方便其他人查看 +> 最近更新至第30章节(共30章节):2026-03-05 +**** +### 失效链接已更新(开放下载链接) 2026-03-05 + +链接: +**** +24期:链接: https://pan.baidu.com/s/1Q9ZFKk81P42T6CVyJzp9dA?pwd=b7ju 提取码: b7ju + +37期:链接: https://pan.baidu.com/s/1hKF6ZSiFQk79-BDb6b7TFA?pwd=8wb1 提取码: 8wb1 + +**** + + +**以第二套的为准,第一套结构胡乱,讲义不全,第二套讲义的内容可以点击下面的章节图片进行在线预览。链接设置为永久有效,如果百度云链接失效,请在issue联系我,我会及时回复。** ****  具体更详细的Python学习路线图可以在[此处](http://bbs.itheima.com/forum.php?mod=viewthread&tid=414606&page=1)中查看 -> 讲义文档,在线阅读 +> 讲义文档,在线阅读,点击即可 [](https://haozhang95.github.io/Python24/) > 讲义文档,百度云下载 -前往百度云(提取码:nhja),点击[这里](https://pan.baidu.com/s/1stzmPEMGMo3W1g_CnlZ_bA) +链接: +**** +24期:链接: https://pan.baidu.com/s/1Q9ZFKk81P42T6CVyJzp9dA?pwd=b7ju 提取码: b7ju + +37期:链接: https://pan.baidu.com/s/1hKF6ZSiFQk79-BDb6b7TFA?pwd=8wb1 提取码: 8wb1 +****