(1)Python所有方向的学习路线(新版)
这是我花了几天的时间去把Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。
最近我才对这些路线做了一下新的更新,知识体系更全面了。
(2)Python学习视频
包含了Python入门、爬虫、数据分析和web开发的学习视频,总共100多个,虽然没有那么全面,但是对于入门来说是没问题的,学完这些之后,你可以按照我上面的学习路线去网上找其他的知识资源进行进阶。
(3)100多个练手项目
我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了,只是里面的项目比较多,水平也是参差不齐,大家可以挑自己能做的项目去练练。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
raise IndexError(‘Stack Underflow!’)
else:
result = self.stack[self.top]
self.top -= 1
return result
2.1.7 求栈顶元素
若栈不空,则只需返回栈顶元素:
def peek(self):
if self.isempty():
raise IndexError(‘Stack Underflow!’)
else:
return self.stack[self.top]
2.2 链栈的实现
栈的另一种存储表示方式是使用链式存储结构,因此也常称为链栈,其中 push
操作是通过在链表头部插入元素来实现的,pop
操作是通过从头部删除节点来实现的。
2.2.1 栈结点
栈的结点实现与链表并无差别:
class Node:
def init(self, data):
self.data = data
self.next = None
def str(self):
return str(self.data)
2.2.2 栈的初始化
栈的初始化函数中,使栈顶指针指向 None
,并初始化栈长:
class Stack:
def init(self):
self.top = None
栈中元素数
self.length = 0
2.2.3 求栈长
返回 length
的值用于求取栈的长度,如果没有 length
属性,则需要遍历整个链表才能得到栈长:
def size(self):
return self.length
2.2.4 判栈空
根据栈的长度可以很容易的判断栈是否为空栈:
def isempty(self):
if self.length == 0:
return True
else:
return False
2.2.5 入栈
入栈时,在栈顶插入新元素即可:
def push(self, data):
p = Node(data)
p.next = self.top
self.top = p
self.length += 1
由于插入元素是在链表头部进行的,因此入栈的时间复杂度为 O ( 1 ) O(1) O(1),在这种情况下链尾作为栈底 。
2.2.5 出栈
若栈不空,则删除并返回栈顶元素:
def pop(self):
if self.isempty():
raise IndexError(“Stack Underflow!”)
ele = self.top.data
self.top = self.top.next
self.length -= 1
return ele
由于删除元素仅需修改头指针指向其 next
域,因此出栈的时间复杂度同样为 O ( 1 ) O(1) O(1)。
2.2.6 求栈顶元素
若栈不空,返回栈顶元素即可,但栈顶元素并不会被删除:
def peek(self):
if self.isempty():
raise IndexError(“Stack Underflow!”)
return self.top.data
2.3 栈的不同实现对比
本节我们将对比栈的不同实现之间的异同:
-
顺序栈
-
操作的时间复杂度均为 O ( 1 ) O(1) O(1),列表的尾部作为栈顶
-
栈满时需要进行动态的扩展,复制原栈元素到新栈中
-
链栈
-
操作的时间复杂度均为 O ( 1 ) O(1) O(1),链表的头部作为栈顶
-
优雅的扩展,无需考虑栈满,需要额外的空间存储指针
接下来,我们首先测试上述实现的链表,以验证操作的有效性,然后利用实现的基本操作来解决实际算法问题。
3.1 顺序栈的应用
首先初始化一个顺序栈 stack
,然后测试相关操作:
初始化一个最大长度为4的栈
s = Stack(4)
print(‘栈空?’, s.isempty())
for i in range(4):
print(‘入栈元素:’, i)
s.push(i)
print(‘栈满?’, s.isfully())
print(‘栈顶元素:’, s.peek())
print(‘栈长度为:’, s.size())
while not s.isempty():
print(‘出栈元素:’, s.pop())
测试程序输出结果如下:
栈空? True
入栈元素: 0
入栈元素: 1
入栈元素: 2
入栈元素: 3
栈满? True
栈顶元素: 3
栈长度为: 4
出栈元素: 3
出栈元素: 2
出栈元素: 1
出栈元素: 0
3.2 链栈的应用
首先初始化一个链栈 stack
,然后测试相关操作:
初始化新栈
s = Stack()
print(‘栈空?’, s.isempty())
for i in range(4):
print(‘入栈元素:’, i)
s.push(i)
print(‘栈顶元素:’, s.peek())
print(‘栈长度为:’, s.size())
while not s.isempty():
print(‘出栈元素:’, s.pop())
测试程序输出结果如下:
栈空? True
入栈元素: 0
入栈元素: 1
入栈元素: 2
入栈元素: 3
栈顶元素: 3
栈长度为: 4
出栈元素: 3
出栈元素: 2
出栈元素: 1
出栈元素: 0
3.3 利用栈基本操作实现复杂算法
[1] 匹配符号是指正确地匹配左右对应的符号(符号允许进行嵌套),不仅每一个左符号都有一个右符号与之对应,而且两个符号的类型也是一致的,下表展示了一些符号串的匹配情况:
| 符号串 | 是否匹配 |
| — | — |
| []()() | 匹配 |
| [(())() | 不匹配 |
| {([]())} | 匹配 |
| (())[]} | 不匹配 |
为了检查符号串的匹配情况,需要遍历符号串,如果字符是 (
、[
或 {
之类的开始分隔符,则将其写入栈中;当遇到诸如 )
、]
或 }
等结束分隔符时,则栈顶元素出栈,并将其与当前遍历元素进行比较,如果它们匹配,则继续解析符号串,否则表示不匹配。当遍历完成后,如果栈不为空,则同样表示不匹配:
def isvalid_expression(expression):
stack = Stack()
symbols = {‘)’:‘(’, ‘]’:‘[’, ‘}’:‘{’}
for s in expression:
if s in symbols:
if stack:
top_element = stack.pop()
else:
top_element = ‘#’
if symbols[s] != top_element:
return False
else:
stack.push(s)
return not stack
由于我们只需要遍历符号串一边,因此算法的时间复杂度为 O ( n ) O(n) O(n),算法的空间复杂度同样为 O ( n ) O(n) O(n)。
[2] 给定一链表(带有头结点) L : L 0 → L 1 → … → L n L: L_0 \rightarrow L_1 \rightarrow … \rightarrow L_n L:L0→L1→…→Ln,将其重排为: L 0 → L n → L 1 → L n − 1 … L_0 \rightarrow L_n \rightarrow L_1 \rightarrow L_{n-1}… L0→Ln→L1→Ln−1…。
例如链表中包含 9 个元素,则下图现实了重排前后的链表元素情况:
由于栈的先进后出原则,可以利用栈与原链表的配合进行重排,首次按遍历链表,将每个结点入栈;栈中元素的出栈顺序为原链表结点的逆序,然后交替遍历链表和栈,构建新链表。
def reorder_list(L):
p = L.head.next
if p == None:
return L
stack = Stack()
while p!= None:
stack.push§
p = p.next
l = L.head.next
from_head = L.head.next
from_stack = True
while (from_stack and l != stack.peek() or (not from_stack and l != from_head)):
if from_stack:
from_head = from_head.next
l.next = stack.pop()
from_stack = False
else:
l.next = from_head
from_stack = True
l = l.next
l.next = None
该算法的时间复杂度和空间复杂度均为 O ( n ) O(n) O(n)。
如果你也是看准了Python,想自学Python,在这里为大家准备了丰厚的免费学习大礼包,带大家一起学习,给大家剖析Python兼职、就业行情前景的这些事儿。
一、Python所有方向的学习路线
Python所有方向路线就是把Python常用的技术点做整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。
二、学习软件
工欲善其必先利其器。学习Python常用的开发软件都在这里了,给大家节省了很多时间。
三、全套PDF电子书
书籍的好处就在于权威和体系健全,刚开始学习的时候你可以只看视频或者听某个人讲课,但等你学完之后,你觉得你掌握了,这时候建议还是得去看一下书籍,看权威技术书籍也是每个程序员必经之路。
四、入门学习视频
我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了。
四、实战案例
光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。
五、面试资料
我们学习Python必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。
成为一个Python程序员专家或许需要花费数年时间,但是打下坚实的基础只要几周就可以,如果你按照我提供的学习路线以及资料有意识地去实践,你就有很大可能成功!
最后祝你好运!!!
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!