如何让 PreOrder、InOrder、PostOrder 正常工作?

2024-04-14

如何让 PreOrder、InOrder、PostOrder 正常工作?

这是我当前的代码和实现,请参阅 InOrder()、PreOrder()、PostOrder()。我有来自 Geek4Geek 的参考(https://www.geeksforgeeks.org/tree-traversals-inorder-preorder-and-postorder/ https://www.geeksforgeeks.org/tree-traversals-inorder-preorder-and-postorder/).

当我执行 print(bst.InOrder()) 时,它返回 None ?

import os
import pygraphviz as pgv
from collections import deque
from IPython.display import Image, display

class BST:
    root=None

    def get(self,key):
        p = self.root
        while p is not None:
            if p.key == key:
                return p.val
            elif p.key > key: #if the key is smaller than current node, then go left (since left are all the small ones)
                p = p.left
            else:   # else if key is bigger than current node, go to right (since right are all the big ones)
                p = p.right 
        return None
        
    def put(self, key, val):
        self.root = self.put2(self.root, key, val)

    def put2(self, node, key, val):
        if node is None:
            #key is not in tree, create node and return node to parent
            return Node(key, val)
        if key < node.key:
            # key is in left subtree
            node.left = self.put2(node.left, key, val)
        elif key > node.key:
            # key is in right subtree
            node.right = self.put2(node.right, key, val)
        else:
            node.val = val
        return node

    # draw the graph
    def drawTree(self, filename):
        # create an empty undirected graph
        G=pgv.AGraph('graph myGraph {}')

        # create queue for breadth first search
        q = deque([self.root])
        # breadth first search traversal of the tree
        while len(q) != 0:
            node = q.popleft()
            G.add_node(node, label=node.key+":"+str(node.val))
            if node.left is not None:
                # draw the left node and edge
                G.add_node(node.left, label=node.left.key+":"+str(node.left.val))
                G.add_edge(node, node.left)
                q.append(node.left)
            if node.right is not None:
                # draw the right node and edge
                G.add_node(node.right, label=node.right.key+":"+str(node.right.val))
                G.add_edge(node, node.right)
                q.append(node.right)

        # render graph into PNG file
        G.draw(filename,prog='dot')
        display(Image(filename))

    def createTree(self):
        self.put("F",6)
        self.put('I',9)
        self.put("J",10)
        self.put("G",7)
        self.put("H",8)
        # left side of F:6
        self.put("D",4)
        self.put("C",3)
        self.put("B",2)
        self.put("A",1)
        self.put("E",5)

   

    def createBalancedTree(self):
      self.put("F",6)
      self.put("A",1)
      self.put("B",2)
      self.put("C",3)
      self.put("D",4)
      self.put("E",5)
      self.put("G",7)
      self.put("H",8)
      self.put('I',9)
      self.put("J",10)
    
    def find(self, key):
        p = self.root
        while p is not None:
            if p.key == key:
                return p
            elif p.key > key:
                p = p.left
            else:
                p = p.right
        return

    def size(self,key): 
      return self.size2(self.find(key)) #using the find function which gives the node instead
    
    def size2(self, subtree):
      if not subtree: #if given key is not found in entire tree (means not a node in this tree)
        return 0
      else:
        return 1 + self.size2(subtree.left) + self.size2(subtree.right)
    

    def depth(self,key):
      p = self.root                         # set the default node as Root, since we start from Root then top-bottom approach. 
      if p is not None:
        if p.key == key:                    # if key is root, then return 0 (cus at Root, there is no depth)
          return 0
        elif p.key > key:                   # if Key is smaller than current node, then search in the left side 
          return self.depth2(p.left,key,0)
        else:                               # if key is bigger than current node, search the right side 
          return self.depth2(p.right,key,0)
    
    def depth2(self,node,key,counter):
      # lets say you put a depth(Z), at depth(), it wouldt know Z exits or not, so it will call depth2() to find out. In depth2(), It will check 'Z' throughtout node.key>key and node.key<key..
      # still cannot find after all the iteration, then it will return None
      if node is not None:                 
        if node.key > key:        
          return self.depth2(node.left,key,counter+1)
        elif node.key < key:                     
          return self.depth2(node.right,key,counter+1)
        elif node.key == key:   
          return counter + 1  # this code will only run when you find your key. So example you do depth(E), it will start from F, then D, then found E. In total 2
      else:
        return None
    

 
    def height(self,key):
      x = self.root
      if x == key:
        return 0
      else:
        return self.height2(self.find(key))
    
    def height2(self,subtree):
        if not subtree:
          return -1 #Key is not a node in the tree
        else:
          return max(self.height2(subtree.left), self.height2(subtree.right)) + 1
    

    def InOrder(self):
      if self == self.root:
        InOrder(self.left)
        print(self.key)
        InOrder(self.right)
    
    #def PreOrder(self):
    #def PostOrder(self):
        
      
class Node:
    left = None
    right = None
    key = 0
    val = 0

    def __init__(self, key, val):
        self.key = key
        self.val = val

我应该怎么做才能让打印正常工作?


代码审查和修复

第一个问题是size uses get它返回一个value树的,不是node。为了解决这个问题,我们重写了你的get充当find,但这次它返回一个节点 -

class BST:
    root=None
    
    def put(self, key, val): # ...
    def put2(self, node, key, val): # ...
    def createTree(self): # ...
    def createBalancedTree(self): # ...

    def find(self,key):
        p = self.root
        while p is not None:
            if p.key == key:
                return p       # return p
            elif p.key > key:
                p = p.left
            else:
                p = p.right 

        return None            # return None, not "None"

我们不需要重复这个逻辑get。相反,我们打电话给find获取节点。如果节点存在,那么我们返回值 -

class BST:
    # ...

    def get(self, key):
      p = self.find(key)       # call to find
      if not p:
        return None
      else:
        return p.val           # return p.val

接下来,在size函数,我们将使用find来获取节点。类似于你写的put2帮手,我们可以写size2它处理循环 -

class BST:
    # ...

    def size(self,key):
      return self.size2(self.find(key)) # find, not get

    def size2(self, subtree):           # define size2 like you did put2
      if not subtree:
        return 0
      else:
        return 1 + self.size2(subtree.left) + self.size2(subtree.right)

这意味着我们没有定义size in the Node class -

class Node:
    left = None
    right = None
    key = 0
    val = 0

    def __init__(self, key, val):
        self.key = key
        self.val = val

    # do not define "size" on the Node class

让我们用你的来测试一下createBalancedTree() -

bst = BST()
bst.createBalancedTree()

#   F
#  / \
# A   G
#  \   \
#   B   H
#    \   \
#     C   I
#      \   \
#       D   J
#        \
#         E
print(bst.size('F')) # 10
print(bst.size('A')) # 5
print(bst.size('H')) # 3
print(bst.size('D')) # 2

height

在您的帮助下也进行了更新,我尝试了相同的方法来查找 height(),但它返回了错误的答案。

我们可以写height如同size -

class BST:
    # ...
    def height(self,key):
      return self.height2(self.find(key))
    
    def height2(self,subtree):
        if not subtree:
            return 0 
        else:
            return max(self.height2(subtree.left), self.height2(subtree.right)) + 1

depth

因此,如果我执行深度('B'),它应该返回 3。由于 B 到 F,深度级别为 3。如果我执行深度('F'),它应该返回 0。因为没有深度在根 F

我们可以写depth和我们写的非常相似find -

class BST:
    # ...
    def depth(self,key):
        p = self.root
        d = 0
        while p is not None:
            if p.key == key:
                return d
            elif p.key > key:
                p = p.left
            else:
                p = p.right
            d = d + 1 
        return None

你做得很好!您的代码没有问题,如下所示 -

bst2 = BST()
bst2.createTree()

#          F
#        /   \
#       D     I
#      / \   / \
#     C   E G   J
#    /       \
#   B         H
#  /
# A 

print(bst2.depth("F")) # 5
print(bst2.depth("I")) # 3
print(bst2.depth("B")) # 2
print(bst2.depth("Z")) # 0

改进

你能解释一下为什么需要put2以及需要size2?抱歉,我没有带出来put2...这是我的作业的给定代码

你实际上并不需要put2 or size2我想说这是一种不好的做法。问题是所有的树逻辑都在类中纠缠在一起。在答案的这一部分中,我将向您展示您的总体修订版bst module.

首先我们从一个基本的开始node界面。我们不需要分配属性,只需要一个简单的__init__构造函数。key and val是必要的。left and right是可选的,默认为None如果没有指定 -

# bst.py

class node:
  def __init__(self, key, val, left = None, right = None):
    self.key = key
    self.val = val
    self.left = left
    self.right = right

现在我们写一个简单的put功能。请注意,没有引用特殊变量,例如self。另一件至关重要的事情是,我们永远不会通过重新分配节点来改变(覆盖)节点left or right特性。取而代之的是一个新的node被建造 -

# bst.py (continued)

def put(t, k, v):
  if not t:
    return node(k, v)
  elif k < t.key:
    return node(t.key, t.val, put(t.left, k, v), t.right)
  elif k > t.key:
    return node(t.key, t.val, t.left, put(t.right, k, v))
  else:
    return node(t.key, v, t.left, t.right)

我们将继续以这种方式编写简单的函数。接下来我们定义get这是一个专业find -

# bst.py (continued)

def get(t, k):
  r = find(t, k)
  if not r:
    return None
  else:
    return r.val

def find(t, k):
  if not t:
    return None
  elif k < t.key:
    return find(t.left, k)
  elif k > t.key:
    return find(t.right, k)
  else:
    return t

这里我们将偏离size一点点。这次将不再需要key争论。相反,调用者将能够调用size在任何节点上。下面将演示用法 -

# bst.py (continued)

def size(t):
  if not t:
    return 0
  else:
    return 1 + size(t.left) + size(t.right)

如果我们可以从节点列表构建树,那就很方便了。这是一个改进createBalancedTree哪个调用.put一遍又一遍。我们可以称之为from_list -

# main.py

nodes = \
  [("F",6), ("A",1), ("B",2), ("C",3), ("D",4), ("E",5), ("G",7), ("H",8), ('I',9), ("J",10)]

t = bst.from_list(nodes)

我们可以实施from_list轻松地在我们的bst模块 -

# bst.py (continued)

def from_list(l):
  t = None
  for (k,v) in l:
    t = put(t, k, v)
  return t

这是该模块最大的区别。我们写的是bst类,但它是普通函数的简单包装,put, find, get, size, and from_list。类中复杂逻辑为零——

# bst.py (continued)

class bst:
  def __init__(self, t): self.t = t
  def put(self, k, v): return bst(put(self.t, k, v))
  def find(self, k): return bst(find(self.t, k))
  def get(self, k): return get(self.t, k)
  def size(self): return size(self.t)
  def from_list(l): return bst(from_list(l))

我们都完成了。我们将写下我们的main从我们导入的程序bst模块 -

# main.py

from bst import bst

nodes = \
  [("F",6), ("A",1), ("B",2), ("C",3), ("D",4), ("E",5), ("G",7), ("H",8), ('I',9), ("J",10)]

t = bst.from_list(nodes)
#   F
#  / \
# A   G
#  \   \
#   B   H
#    \   \
#     C   I
#      \   \
#       D   J
#        \
#         E

记住我是怎么说的size不需key争论?那是因为它可以在任何节点上调用。所以为了find the size对于一个特定的节点,我们首先find它,那么size它!这是编写可重用函数的核心原则:每个函数应该只做one thing -

print(t.find('F').size()) # 10
print(t.find('A').size()) # 5
print(t.find('H').size()) # 3
print(t.find('D').size()) # 2

功能性的

我们使用的技术的一个低调的优点是我们的bst模块可以以面向对象的方式(上图)或函数式的方式(下图)使用。这种双接口使我们的模块极其灵活,因为它可以用于多种风格 -

# functional.py

from bst import from_list, find, size

nodes = \
  [("F",6), ("A",1), ("B",2), ("C",3), ("D",4), ("E",5), ("G",7), ("H",8), ('I',9), ("J",10)]

t = from_list(nodes)

print(size(find(t, 'F'))) # 10
print(size(find(t, 'A'))) # 5
print(size(find(t, 'H'))) # 3
print(size(find(t, 'D'))) # 2

补充阅读

我已经写了大量关于这个答案中使用的技术的文章。点击链接查看它们在其他上下文中的使用情况,并提供附加说明 -

  • 在 BST Python 中删除节点 https://stackoverflow.com/a/66340109/633183

  • 我想反转堆栈,但我不知道如何使用递归来反转堆栈...如何在不使用递归的情况下反转堆栈 https://stackoverflow.com/a/65532663/633183

  • 用Python找到所有迷宫的解决方案 https://stackoverflow.com/a/65512563/633183

  • 递归返回链表的中间节点 https://stackoverflow.com/a/61963040/633183

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何让 PreOrder、InOrder、PostOrder 正常工作? 的相关文章

随机推荐

  • 战舰人工智能在一定规则下沉没部分[关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 我在寻找在某些规则下是否可以为战舰沉
  • 使用 msbuild 扩展包验证文件夹是否存在?

    如何使用 msbuild 扩展包任务可靠地验证文件夹是否存在 我怎样才能做到这一点而不引发错误并停止构建 您可以在目标上使用 Exists 条件吗 仅当与 msbuild 文件位于同一目录中存在名为 Testing 的目录或文件时 才会执行
  • 如何循环访问类的属性?

    C 有没有办法循环遍历类的属性 基本上我有一个包含大量属性的类 它基本上保存大型数据库查询的结果 我需要将这些结果输出为 CSV 文件 因此需要将每个值附加到一个字符串中 最明显的方法是将每个值手动附加到字符串中 但是有没有一种方法可以有效
  • 如何对一组和进行求和? SQL Server 2008

    我有一个查询sum像这样 SELECT Table1 ID SUM Table2 Number1 Table2 Number2 AS SumColumn FROM Table1 INNER JOIN Table3 ON Table1 ID
  • 如何在 Spring Hibernate 运行时设置数据库名称

    问题描述 Spring中有一个类叫做AbstractRoutingDataSource这将适合您的要求 浏览文档 您将找到一些有关如何实现具体类的帮助 您需要更改 或添加 现有代码的某些部分才能配置动态Data source 这个博客 ht
  • 在数据库中实施审查标志;最佳实践

    我需要存储一些与某些实体相关的评论标志 每个审核标志只能与单个实体属性组相关 例如表Parents has a ParentsStatus旗帜和桌子Children有一组ChildrenStatus flags 在当前的设计方案中 我有三个
  • 保留大小相等的分割视图

    我在非最大化窗口模式下启动 GVIM 并水平分割其窗口 确保窗口大小相等 当我最大化主 GVIM 窗口时 如何保留这个大小相等的分割视图 每当我最大化 GVIM 时 都会忘记窗口已被平均分割 Thanks 均衡分割的命令是 W ctrl W
  • 使自定义图像尊重tintColor属性iOS

    我必须想象这个问题已经被问过好几次了 但我的问题措辞一定不正确 我有自己在 Photoshop 中制作的自定义图像 并将其设置为按钮的图像属性 这里正常显示 背景是透明的 但它是 44x44 其中三个点是 88x88 像素的 png 文件
  • 使用 CSS 时链接不起作用

    我遇到了一个无法通过谷歌搜索解决的问题 我有一个静态 HTML
  • 一个关于二分查找的问题

    为什么人们通常使用二分搜索而不是三重搜索 将 每次分成三份 或者甚至每次分成十份 因为二分查找会产生最少数量的比较和查找 为了简单直观 请考虑每次分为 4 部分 v1 v2 v3 您现在已经完成了 3 次查找 并且必须将您正在搜索的最坏值与
  • 使用实体框架代码优先的 FSharp 记录类型

    我正在一个业务应用程序中进行概念验证 我想用 F 替换当前的 C 代码优先实体框架实现 我正在关注this http blogs msdn com b visualstudio archive 2011 04 04 f code first
  • 干净的架构,用例依赖关系

    最近 我找到了方法干净的架构 https 8thlight com blog uncle bob 2012 08 13 the clean architecture html鲍勃叔叔的帖子 但是 当我尝试将其应用到当前项目时 当一个用例需要
  • 更改 SQL Server 2012 数据库的排序规则

    更改排序规则 我需要更改特定服务器上的一个数据库的排序规则Latin1 General CI AS to SQL Latin1 General CP1 CI AI以便它与我们数据库的其余部分相匹配 问题 但是 当我尝试执行此操作时 出现以下
  • 以最小的质量损失调整大小

    我需要调整图像大小 但图像质量不会受此影响 图像将从 10x10 到 1000x1000 它会有一些严重的拥塞和一些空白时间 它必须同时放大和缩小 可能会损失一些图像质量 可以 但必须至少是 所有东西都确实带有光栅图形 请不要使用库或其他外
  • MyPy 不允许受约束的 TypeVar 是协变的?使用受约束但协变的键值类型定义通用字典

    我正在尝试定义一个自定义通用字典 其键的类型T key并且值的类型T val 我也想限制一下T key and T val 使得T key只能是类型A or B或其子类 我该如何实现这个目标 from typing import TypeV
  • 在不改变我的位置的情况下获取当前位置的经度和纬度

    我可以找到当前位置的纬度和经度 但是这些数据在更改我的当前位置之前不会显示 我想在不更改我的位置的情况下获取当前位置的经度和纬度 package com example gps import android app Activity imp
  • 如何对 HashMap 键进行排序[重复]

    这个问题在这里已经有答案了 我有一个问题 HashMap
  • Google 地图 (Android) 中的位置更新率

    我正在编写一个简单的基于 GPS 的应用程序 用于位置感知 每当启用 GPS 时 应用程序都会请求位置更新并以格式打印纬度和经度 TextView 如果 GPS 被禁用 位置提供商会回退到LocationManager NETWORK PR
  • 两个托管对象上下文可以共享一个持久存储协调器吗?

    示例 我有一个持久存储协调器 它使用一个持久存储 现在有两个托管对象上下文 并且都希望使用相同的持久存储 两者都可以简单地使用相同的持久存储协调器 还是我必须创建 NSPersistentStoreCoordinator 的两个实例 如果我
  • 如何让 PreOrder、InOrder、PostOrder 正常工作?

    如何让 PreOrder InOrder PostOrder 正常工作 这是我当前的代码和实现 请参阅 InOrder PreOrder PostOrder 我有来自 Geek4Geek 的参考 https www geeksforgeek