Datawhale编程学习之二叉树和堆(5)

本文深入讲解了二叉树与堆两种数据结构的定义、特性及实现方法,包括二叉查找树的插入、删除、查找操作,以及前、中、后序和按层遍历;同时介绍了堆的定义、小顶堆、大顶堆的实现,以及如何利用优先级队列解决实际问题。文章还提供了LeetCode上的实践题目,帮助读者巩固理解。


任务5: 9~10天

1.学习目标

1.1 二叉树

实现一个二叉查找树,并且支持插入、删除、查找操作
实现查找二叉查找树中某个节点的后继、前驱节点
实现二叉树前、中、后序以及按层遍历

1.2 堆

实现一个小顶堆、大顶堆、优先级队列
实现堆排序
利用优先级队列合并 K 个有序数组
求一组动态数据集合的最大 Top K

1.3 对应的 LeetCode 练习题

Invert Binary Tree(翻转二叉树)
英文版:Loading…
中文版:力扣

Maximum Depth of Binary Tree(二叉树的最大深度)
英文版:Loading…
中文版:力扣

Validate Binary Search Tree(验证二叉查找树)
英文版:Loading…
中文版:力扣

Path Sum(路径总和)
英文版:Loading…
中文版:力扣

2. 学习内容

2.1 二叉树

定义:
左子树不为空的时候,左子树的节点值小于根结点
右子树不为空的时候,右子树的节点值大于根结点
左右子数据分别为二叉查找树
二叉查找树最左边的节点即为最小值,要查找最小值,仅需遍历左子树的节点值到空为止
二叉查找树的插入/查找/删除操作都是通过递归方式实现的。删除一个节点:
先找到这个节点S,假设节点左右孩子都不为空
在其右子树找到后继(最小)节点,将后继节点的值给S
删除该后继节点

实现一个二叉查找树,并且支持插入、删除、查找操作
实现查找二叉查找树中某个节点的后继、前驱节点
实现二叉树前、中、后序以及按层遍历

class Node:
    def __init__(self, data):
        self.data = data
        self.lchild = None
        self.rchild = None


class BST:
    def __init__(self, node_list):
        self.root = Node(node_list[0])
        for data in node_list[1:]:
            self.insert(data)

    def search(self, node, parent, data):  # 搜索
        if node is None:
            return False, node, parent
        if node.data == data:
            return True, node, parent
        if node.data > data:
            return self.search(node.lchild, node, data)
        else:
            return self.search(node.rchild, node, data)

    def insert(self, data):  # 插入
        flag, n, p = self.search(self.root, self.root, data)
        if not flag:
            new_node = Node(data)
            if data > p.data:
                p.rchild = new_node
            else:
                p.lchild = new_node

    def delete(self, root, data):  # 删除
        flag, n, p = self.search(root, root, data)  # n待删除节点,p节点n的父节点
        if flag is False:
            print("无该关键字,删除失败")
        else:
            if n.lchild is None:  # n的左子树为空(仅存在右子树)
                if n == p.lchild:  # n为p的左孩子
                    p.lchild = n.rchild
                else:  # n为p的右孩子
                    p.rchild = n.rchild
                del n
            elif n.rchild is None:  # 右子树为空
                if n == p.lchild:
                    p.lchild = n.lchild
                else:
                    p.rchild = n.lchild
                del n
            else:  # n的左右子树均不为空,将右子树的最小数据代替此节点的数据
                pre = n.rchild
                if pre.lchild is None:  # 左子树,则该节点为最小节点
                    n.data = pre.data
                    n.rchild = pre.rchild
                    del pre
                else:
                    next = pre.lchild
                    while next.lchild is not None:
                        pre = next
                        next = next.lchild
                    n.data = next.data
                    pre.lchild = next.rchild
                    del next

    def preOrderTraverse(self, node):  # 先序遍历
        if node is not None:
            print(node.data)
            self.preOrderTraverse(node.lchild)
            self.preOrderTraverse(node.rchild)

    def inOrderTraverse(self, node):  # 中序遍历
        if node is not None:
            self.inOrderTraverse(node.lchild)
            print(node.data)
            self.inOrderTraverse(node.rchild)

    def postOrderTraverse(self, node):  # 后序遍历
        if node is not None:
            self.postOrderTraverse(node.lchild)
            self.postOrderTraverse(node.rchild)
            print(node.data)

层次遍历

将二叉树的节点加入队列,出队的同时,将其非空左右孩子依次入队
出队至队列为空则完成遍历

def PrintFromTopToBottom(self, root):
    outList=[]
    queue=[root]
    while queue!=[] and root:
        outList.append(queue[0].val)
        if queue[0].left!=None:
            queue.append(queue[0].left)
        if queue[0].right!=None:
            queue.append(queue[0].right)
        queue.pop(0)
    return outList
def printFromTopToBottom(self, root):
    if not root:
        return[]
    currentStack = [root]
    outList = []
    while currentStack:
        nextStack = []
        for point in currentStack:
            if point.lchild:
                nextStack.append(point.lchild)
            if point.rchild:
                nextStack.append(point.rchild)
            outList.append(point.data)
        currentStack = nextStack
    return outList

2.2 堆

堆树的定义
完全二叉树
堆树中某个节点的值总是不大于或者不小于其孩子节点的值
堆树中的每个节点的子树都是堆树

实现一个小顶堆、大顶堆、优先级队列

实现堆排序

def heap_sort(lists):
    # 堆排序(交换堆顶元素和末尾元素,逐步得到最终结果)
    size = len(lists)
    build_heap(lists, size)
    for i in range(0, size)[::-1]:
        lists[0], lists[i] = lists[i], lists[0]
        adjust_heap(lists, 0, i)
    return lists
    
def adjust_heap(lists, i, size):
    # 调整堆(根结点 < 孩子结点,和最大的孩子结点交换位置)
    lchild = 2 * i + 1
    rchild = 2 * i + 2
    maxi = i
    if lchild < size and lists[maxi] < lists[lchild]:
        maxi = lchild
    if rchild < size and lists[maxi] < lists[rchild]:
        maxi = rchild
    if maxi != i:
        # 如果做了堆调整则maxi的值等于左节点或者右节点的,这个时候做对调值操作
        lists[maxi], lists[i] = lists[i], lists[maxi]
        adjust_heap(lists, maxi, size)

def build_heap(lists, size):
    # 堆的构建
    for i in range(int(size / 2), 0, -1):
        adjust_heap(lists, i, size)

利用优先级队列合并 K 个有序数组

求一组动态数据集合的最大 Top K

2.3 对应的 LeetCode 练习题

翻转二叉树

class Solution:
    def invertTree(self, root):
        if not root:
            return root

        self.invertTree(root.left)
        self.invertTree(root.right)
        root.left, root.right = root.right, root.left
        return root

二叉树的最大深度

class Solution(object):
    def maxDepth(self, root):
        depth = 0
        level = [root] if root else []
        while level:
            depth += 1
            queue = []
            for el in level:
                if el.left:
                    queue.append(el.left)
                if el.right:
                    queue.append(el.right)
            level = queue
            
        return depth

验证二叉查找树

class Solution:
    def isValidBST(self, root, left=None, right=None):
        if not root:
            return True

        if left and left.val >= root.val:
            return False

        if right and right.val <= root.val:
            return False

        return self._isValidBST(root.left, left, root) and self._isValidBST(root.right, root, right)

路径总和

class Solution:
    def hasPathSum(self, root, sum):
        """
        :type root: TreeNode
        :type sum: int
        :rtype: bool
        """
        if root is None:
            return False
        if sum == root.val and root.left is None and root.right is None:
            return True
        return self.hasPathSum(root.left, sum-root.val) or self.hasPathSum(root.right, sum-root.val)

3. 参考链接

https://shimo.im/docs/g9fwoinJO8cHWgUr/read

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值