本文是学习陆老师的《python全栈工程师 - 数据结构与算法》课程的笔记,欢迎学习交流。同时感谢陆老师的精彩传授!
一、课程目标
- 树结构定义
- 二叉树结构
- 遍历与搜索
二、详情解读
01.什么是树:
术语 | 定义 |
---|---|
节点 | 树中分叉处,用来存储项 |
根 | 没有父节点的节点,即最顶端的节点 |
子节点 | 一个节点的直接相邻的后一个节点,可以拥有多个子节点,子节点顺序从左到右 |
父节点 | 一个节点的直接相邻的前一个节点 |
兄弟节点 | 拥有共同父节点的节点 |
叶子节点 | 没有子节点的节点称为叶子节点 |
内部节点 | 至少拥有一个子节点的节点 |
边/分支链接 | 节点的连接线 |
后代 | 一个节点的所有的子节点、子子节点 |
祖先 | 一个节点之前的父节点、父节点的父节点,一直到根节点 |
路径 | 一个节点到某一个后代节点的序列 |
深度/层级 | 一个节点的深度等于将其连接到根节点的路径的长度,因此,根节点深度为0,根节点的子节点深度是1,以此类推 |
高度 | 树中最长的路径的长度 |
子树 | 将一个节点及其所有后代节点包括在内所形成的树 |
树结构的应用:
1.文件路径,就是一种树状结构
2.商品分类的菜单实现,也是树状结构
3.网页中的文档树
4.机器学习中的决策树,随机森林
5.数据库中的B树
6…很多,不一而足
二叉雄起的形状:
普通树:
二叉树:
一个节点最多拥有2个子节点
两个子节点分别称为左节点与右节点
如果只有一个子节点,该子节点可以看作是左节点或者右节点,
并且因此带来的树结构不同
02.二叉树:
二叉树的形状:
十世单传,树的高度=树的节点树-1
这种情况下,就好像一个链表
对这棵树的访问插入删除的时间复杂度都是线性的O(n)
满二叉树:
除了叶子节点,每个节点都包含了二个节点
满二叉树的高度H = log2(N+1)-1
03.二叉树的遍历与搜索
二叉树的查找:
代码实现:
# 文件linkedstack.py内容
# -*- coding: utf-8 -*-
class Node(object):
def __init__(self, data, next = None):
self.data = data
self.next = next
class LinkedStack:
# Constructor
def __init__(self, sourceCollection = None):
self._items = None
self._size = 0
if sourceCollection:
for item in sourceCollection:
self.add(item)
# Accessor methods
def isEmpty(self):
return len(self) == 0
def __len__(self):
return self._size
def __str__(self):
return "[" + ", ".join(map(str, self)) + "]"
def __add__(self, other):
result = type(self)(self)
for item in other:
result.add(item)
return result
def __eq__(self, other):
if self is other: return True
if type(self) != type(other) or \
len(self) != len(other):
return False
otherIter = iter(other)
for item in self:
if item != next(otherIter):
return False
return True
def __iter__(self):
def visitNodes(node):
if not node is None:
visitNodes(node.next)
tempList.append(node.data)
tempList = list()
visitNodes(self._items)
return iter(tempList)
def add(self, item):
self.push(item)
def peek(self):
if self.isEmpty():
raise KeyError("The stack is empty.")
return self._items.data
def clear(self):
self._size = 0
self._items = None
def push(self, item):
self._items = Node(item, self._items)
self._size += 1
def pop(self):
if self.isEmpty():
raise KeyError("The stack is empty.")
data = self._items.data
self._items = self._items.next
self._size -= 1
return data
# 文件linkedbst.py内容
# -*- coding: utf-8 -*-
class BSTNode(object):
def __init__(self, data, left = None, right = None):
self.data = data
self.left = left
self.right = right
from linkedstack import LinkedStack
class LinkedBST:
def __init__(self, sourceCollection = None):
self._root = None
self._size = 0
if sourceCollection:
for item in sourceCollection:
self.add(item)
def __len__(self):
return self._size
def __str__(self):
def recurse(node, level):
s = ""
if node != None:
s += recurse(node.right, level + 1)
s += "| " * level
s += str(node.data) + "\n"
s += recurse(node.left, level + 1)
return s
return recurse(self._root, 0)
def __iter__(self):
if not self.isEmpty():
stack = LinkedStack()
stack.push(self._root)
while not stack.isEmpty():
node = stack.pop()
yield node.data
if node.right != None:
stack.push(node.right)
if node.left != None:
stack.push(node.left)
def isEmpty(self):
return len(self) == 0
def inorder(self):
lists = list()
def recurse(node):
if node != None:
recurse(node.left)
lists.append(node.data)
recurse(node.right)
recurse(self._root)
return iter(lists)
def postorder(self):
return None
def levelorder(self):
return None
def __contains__(self, item):
return self.find(item) != None
def find(self, item):
def recurse(node):
if node is None:
return None
elif item == node.data:
return node.data
elif item < node.data:
return recurse(node.left)
else:
return recurse(node.right)
return recurse(self._root)
def clear(self):
self._root = None
self._size = 0
def add(self, item):
def recurse(node):
if item < node.data:
print("item=", item, "node.data=", node.data)
if node.left == None:
node.left = BSTNode(item)
else:
recurse(node.left)
elif node.right == None:
node.right = BSTNode(item)
else:
recurse(node.right)
if self.isEmpty():
self._root = BSTNode(item)
else:
recurse(self._root)
self._size += 1
def remove(self, item):
if not item in self:
raise KeyError("Item not in tree.""")
def liftMaxInLeftSubtreeToTop(top):
parent = top
currentNode = top.left
while not currentNode.right == None:
parent = currentNode
currentNode = currentNode.right
top.data = currentNode.data
if parent == top:
top.left = currentNode.left
else:
parent.right = currentNode.left
if self.isEmpty(): return None
itemRemoved = None
preRoot = BSTNode(None)
preRoot.left = self._root
parent = preRoot
direction = 'L'
currentNode = self._root
while not currentNode == None:
if currentNode.data == item:
itemRemoved = currentNode.data
break
parent = currentNode
if currentNode.data > item:
direction = 'L'
currentNode = currentNode.left
else:
direction = 'R'
currentNode = currentNode.right
if itemRemoved == None: return None
if not currentNode.left == None \
and not currentNode.right == None:
liftMaxInLeftSubtreeToTop(currentNode)
else:
if currentNode.left == None:
newChild = currentNode.right
else:
newChild = currentNode.left
if direction == 'L':
parent.left = newChild
else:
parent.right = newChild
self._size -= 1
if self.isEmpty():
self._root = None
else:
self._root = preRoot.left
return itemRemoved
def replace(self, item, newItem):
probe = self._root
while probe != None:
if probe.data == item:
oldData = probe.data
probe.data = newItem
return oldData
elif probe.data > item:
probe = probe.left
else:
probe = probe.right
return None
# 文件testbst.py内容
"""
File: testbst.py
A tester program for binary search trees.
"""
#%%
from linkedbst import LinkedBST
#%%
tree = LinkedBST()
lists = ["D", "B", "A", "C","F", "E", "G"]
for i, word in enumerate(lists):
tree.add(word)
print("\n\n","*"*10, "--",i,"--","*"*10)
print("\nString:\n" + str(tree))
#%%
tree = LinkedBST()
lists = ["H","D", "B", "A", "C", "L", "F", "E", "G", "J", "K", "I", "N", "M", "O"]
for i, word in enumerate(lists):
tree.add(word)
print("\n\n","*"*10, "--",i,"--","*"*10)
print("String:\n" + str(tree))
#%%
print("\n\n前序遍历: ", end="")
for item in tree:
print(item, end = " ")
#%%
print("\n\n中序遍历: ", end="")
for item in tree.inorder():
print(item, end = " ")
运行结果:
#%%
print("\n\n移除:", end = " ")
for item in "ACDF":
print(tree.remove(item), end=" ")
print("\n\n: ", len(tree))
#%%
tree = LinkedBST(range(1, 16))
print("\nAdded 1..15:\n" + str(tree))
运行结果:
#%%
lists = list(range(1, 16))
import random
random.shuffle(lists)
tree = LinkedBST(lists)
print("\nAdded ", lists, "\n" + str(tree))
运行结果:
三、课程小结
- 学习了树的结构定义
- 学习了二叉树
- 学习了二叉树遍历