python数据结构教程_python数据结构教程 Day14

本章内容

平衡二叉树定义

AVL树实现

一、平衡二叉树(AVL树定义)

能够在key插入时一直保持平衡的二叉查找树,AVL树的实现中,需要对每个节点跟踪 “平衡因子balance factor”参数。

平衡因子:

平衡因子是根据节点的左右子树的高度来定义的,确切地说,是左右子树高度差:

如果平衡因子大于0,称为“左重left-heavy” , 小于零称为“右重right-heavy” 平衡因子等于0,则称作平衡。

如果一个二叉查找树中每个节点的平衡因 子都在-1,0,1之间,则把这个二叉搜索树称为平衡树。在平衡树操作过程中,有节点的平衡因子超出此范围,则需要一个重新平衡的过程,同时要保持BST的性质。

二、AVL树的实现

首先,作为BST,插入新key必定以叶节点形式插入到AVL树中。

会引起什么反应?

叶节点的平衡因子:

其本身无需重新平衡。

父节点的平衡因子:

作为左子节点插入,则父节点平衡因子会增加1;

作为右子节点插入,则父节点平衡因子会减少1。

这种影响可能随着其父节点到根节点的路径一直传递上去,直到: 传递到根节点为止; 或者某个父节点平衡因子被调整到0,不再影响上层节点的平衡因子为止。

主要手段:将不平衡的子树进行旋转rotation

视“左重”或者“右重”进行不同方向的旋转,同时更新相关父节点引用,更新旋转后被影响节点的平衡因子。

最简单情况

如图,是一个“右重”子树A的左旋转 (并保持BST性质) 将右子节点B提升为子树的根,将旧根节点A作为新根节点B的左子节点,如果新根节点B原来有左子节点,则将此节点设 置为A的右子节点(A的右子节点一定有空)

稍微复杂情况:

旋转后,新根节点将旧根节点作为右子节点,但是新根节点原来已有右子节点,需要将原有的右子节点重新定位。 原有的右子节点D改到旧根节点E的左子节点同样,E的左子节点在旋转后一定有空

最复杂的情况:

下图的“右重”子树,单纯的左旋转无法实现平衡 左旋转后变成“左重”了 “左重”再右旋转,还回到“右重”。

所以,在左旋转之前检查右子节点的因子 如果右子节点“左重”的话,先对它进行右旋转 再实施原来的左旋转。同样,在右旋转之前检查左子节点的因子 如果左子节点“右重”的话,先对它进行左旋转 再实施原来的右旋转。

如何调整平衡因子:

A、C、E三个的平衡因子没有变化

新B= hA- hC

旧B= hA- 旧hD

而:

旧hD= 1+ max(hC, hE),所以旧B= hA- (1+ max(hC, hE))

新B- 旧B= 1+ max(hC, hE)- hC

新B= 旧B+ 1+ max(hC, hE)- hC;把hC移进max函数里就有

新B= 旧B+ 1+ max(0, -旧D) <==> 新B= 旧B+ 1- min(0, 旧D)

代码实现:

class AVLTree(BinarySearchTree):

def __init__(self):

'''

继承于BST,重写方法并在此基础上添加方法修改

'''

super().__init__()

def _put(self, key, val, currentNode):

'''

子类重写的父类的方法

'''

if key < currentNode.key:

if currentNode.hasLeftChild():

self._put(key, val, currentNode.leftChild)

else:

currentNode.leftChild = TreeNode(key,val,parent = currentNode)

self.updateBalance(currentNode.leftChild) # 调整平衡因子

else:

if currentNode.hasRightChild():

self._put(key, val, currentNode.ritghchild)

else:

currentNode.ritghchild = TreeNode(key, val, parent=currentNode)

self.updateBalance(currentNode.ritghchild)

def updateBalance(self, node):

if node.balanceFactor > 1 or node.balanceFactor < -1:

self.rebalance(node)

return

if node.parent != None:

if node.isLeftChild():

node.parent.balanceFactor += 1

elif node.isRightChild():

node.parent.balanceFactor -= 1

if node.parent.balanceFactor !=0 :

self.updateBalance(node.parent)

def rotateLeft(self,rotRoot):

'''

左旋代码

右旋代码参考同样的流程

'''

newRoot = rotRoot.ritghchild

rotRoot.ritghchild = newRoot.leftChild

if newRoot.leftChild != None:

newRoot.leftChild.parent = rotRoot

newRoot.parent = rotRoot.parent

if rotRoot.isRoot():

self.root = newRoot

else:

if rotRoot.isLeftChild():

rotRoot.parent.leftChild = newRoot

else:

rotRoot.parent.ritghchild = newRoot

newRoot.leftChild = rotRoot

rotRoot.parent = newRoot

# 平衡因子更新的顺序不可调换

rotRoot.balanceFactor = rotRoot.balanceFactor + 1 - min(newRoot.balanceFactor,0)

newRoot.balanceFactor = newRoot.balanceFactor + 1 + max(rotRoot.balanceFactor, 0)

def rotateRight(self, rotnode):

pass

def rebalance(self, node):

'''

1、在左旋转之前检查右子节点的因子

如果右子节点“左重”的话,先对它进行右旋转

再实施原来的左旋转

2、在右旋转之前检查左子节点的因子

如果左子节点“右重”的话,先对它进行左旋转

再实施原来的右旋转

'''

# 右重需要左旋

if node.balanceFactor < 0:

if node.ritghchild.balanceFactor > 0:

# RL

self.rotateRight(node.ritghchild)

self.rotateLeft(node)

else:

self.rotateLeft(node)

elif node.balanceFactor > 0:

if node.leftChild.balanceFactor < 0:

self.rotateLeft(node.leftChild)

self.rotateRight(node)

else:

self.rotateRight(node)

AVL树总结:

需要插入的新节点是叶节点,更新其所有父节点 和祖先节点的代价最多为O(log n) 如果插入的新节点引发了不平衡,重新平衡最多 需要2次旋转,但旋转的代价与问题规模无关, 是常数O(1) 所以整个put方法的时间复杂度还是O(log n)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Python爬虫可以很方便地爬取天气数据。以下是一个简单的示例,可以获取北京市最近7天的天气数据: ```python import requests from bs4 import BeautifulSoup url = 'http://www.weather.com.cn/weather/101010100.shtml' headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'} response = requests.get(url, headers=headers) soup = BeautifulSoup(response.content, 'html.parser') weather_list = soup.select('.t .clearfix') for weather in weather_list: date = weather.select('.day')[0].text.strip() condition = weather.select('.wea')[0].text.strip() high_temp = weather.select('.tem .high')[0].text.strip() low_temp = weather.select('.tem .low')[0].text.strip() print(date, condition, high_temp, low_temp) ``` 解释一下代码: 1. 首先,我们需要找到天气数据的来源网站。这里我选择了中国天气网(http://www.weather.com.cn/)。 2. 我们使用 requests 库来向该网站发送 HTTP 请求,并使用 BeautifulSoup 库对返回的 HTML 页面进行解析。 3. 通过分析 HTML 页面,我们可以找到所需的天气数据在 class 为 “t clearfix” 的 div 元素下。我们使用 select 方法选择该元素,并遍历所有天气信息。 4. 对于每一个天气信息,我们可以从 HTML 中找到日期、天气状况、最高温度和最低温度等信息,并进行提取和打印。 以上代码只是一个简单的示例,实际爬取天气数据可能会涉及到更多的数据处理和异常处理。 ### 回答2: Python爬虫可以用来爬取天气数据,通过抓取天气网站上的信息,获取实时或历史天气数据,并进行进一步的分析和处理。 首先,我们需要了解要爬取的天气网站的结构和数据的位置。通常,天气网站会提供API接口或者发布天气数据的HTML页面。我们可以通过分析网页结构,确定需要爬取的数据在源代码中的位置。 接下来,我们可以使用Python中的第三方库,例如requests和BeautifulSoup来实现爬虫功能。使用requests库可以发送HTTP请求,获取网页源代码,而使用BeautifulSoup库可以方便地解析HTML页面,提取需要的数据。 如果网站提供API接口,我们可以直接使用requests库发送GET请求,获取到JSON格式的数据。然后,我们可以使用Python的json库对数据进行解析,并提取出所需的天气信息。 如果网站提供天气数据的HTML页面,我们可以使用requests库获取到页面的源代码,然后使用BeautifulSoup库解析HTML,提取出对应的天气数据。我们可以通过标签名称、CSS选择器或XPath来定位需要的数据。 在获取到天气数据之后,我们可以进一步处理和分析这些数据。例如,我们可以提取温度、湿度、风力等关键信息,并进行数据可视化、统计分析或者机器学习预测。Python中的matplotlib、pandas和scikit-learn等库可以帮助我们进行这些进一步的处理和分析。 总而言之,使用Python爬虫爬取天气数据可以帮助我们获取到所需的天气信息,并进行进一步的分析和应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值