【问题标题】:Covert Binary Tree to Doubly Linked List (Microsoft Interview)将二叉树转换为双向链表(微软采访)
【发布时间】:2021-04-26 21:51:27
【问题描述】:

我们正在将一棵二叉树转换为一个 DLL,我们也正在使用它来进行遍历。

在此处了解更多信息 - Link

我的代码:

class BinaryTree():
    def __init__(self,data):
        self.data = data
        self.left = None
        self.right = None

def btToDll(node,head):

    prev = None
    return getbtToDll(node,head,prev)

def getbtToDll(node,head,prev):

    if node is None:
        return
    getbtToDll(node.left,head,prev)

    if prev is None:
        head = node
    else:
        node.left = prev
        prev.right = node
    prev = node

    getbtToDll(node.right,head,prev)


def printList(head):
    if head is None:
        print("NO LL FOUND AT THIS NODE")
    else:
        temp = head
        while(temp):
            print(temp.data)
            temp = temp.right


root = BinaryTree(10)
root.left = BinaryTree(12)
root.right = BinaryTree(15)
root.left.left = BinaryTree(25)
root.left.right = BinaryTree(30)
root.right.left = BinaryTree(36)

head = None
head1 = btToDll(root,head)

printList(head1)

我的问题: 头部始终为无,因此我无法打印转换后的列表。这段代码或我的逻辑有什么问题?

【问题讨论】:

  • 调用btToDll(root,head)并没有修改变量head,所以最后还是None。您可能需要 return 函数中的某些内容。
  • def btToDll(node,head): prev = None return getbtToDll(node,head,prev) 头部仍然是 None

标签: python python-3.x linked-list binary-tree


【解决方案1】:

你的代码有很多陷阱,它返回none的主要原因是因为btToDll什么都不返回,也没有改变head的值,它仍然是None。

与其尝试修复您的代码,我更愿意一次性采用不同的方法。

基本上,我找到了一个获得结果的技巧:

  1. 下到最左边的节点,成为 HEAD
  2. 检查是否可以从头部向上移动,然后向左移动。或上一右等。如果可以向左,则将当前节点设置为左下节点。这样做直到没有任何节点。在 DLL 列表中添加上一个节点
  3. 从 Previoys 计算当前节点、它的前一个节点和 Right 节点。
  4. 从二叉树返回,到达根节点 (10),重复相同的模式。

你会看到,基本上,如果在任何给定的子节点中,有一个左节点,那么你计算整个三角形,最重要的节点总是左边,成为当前节点。如果左节点不存在,则父节点成为当前节点,则需要检查父节点是否有右节点。

我准备了一些图片,形象化比解释要好得多。

取这棵二叉树:

第一步 |尽可能去最左边的节点

第二步 |计算第一个三角形

注意:如果右下节点(30)有左子节点,则不添加30,本例就是这样,而是进入下一步。

第 3 步 |转到Child的子节点的下一个Triangle步骤##

第 4 步 |现在上到根节点计算BT的左边

注意:看这个算法的完整路径,我又想像那么多小三角形是分开计算的。

源代码

注意:已经很长了,但我是即时完成的,可以改进。

class BinaryTree():
    def __init__(self, data):
        self.data = data
        self.left = None
        self.right = None
        self.prev = None
        self.visited = False

    def create_tree(self, show_tree=False):
        """Creating the Tree with a Depth-First Search Algorithm"""
            
        root = self # Set Current Node        
        stack = [root]

        while True:

            if not stack:
                break

            current = stack.pop() # Remove Current From Stack

            if current.right:
                current.right.prev = current
                stack.append(current.right)            
            if current.left:
                current.left.prev = current
                stack.append(current.left)

            if show_tree:
                print(f'{current.data} --> ', end='')


def create_dll(root_head):
    """Algorithm to Conver Binary Tree to Doubly Linked List"""

    doubly_linked_list = []

    # --- Find DLL Head NOTE: Just need to go left from Binary Tree till hit NONE
    head = None
    current = root_head 
    while True:
        if current.left:
            current = current.left
        else:
            head = current       
            break
    
    stack = [head]
    visited = set()

    def add_node(*args, add_dll=None):
        """Helper Function, Add Node to the Visited Set."""
        for item in args:
            visited.add(item)
        if add_dll:
            for node in add_dll:
                doubly_linked_list.append(node)

    # --- Crawls back up, following each Triangle Shape from left Vertices to Right
    while True:

        try:
            current = stack.pop()
        except IndexError:
            pass

        if current in doubly_linked_list:
            break
        
   
        if current.left and current.left not in visited: # NOTE: Goes Down to Next Triangle Shape        
            stack.append(current.left)
            continue
        elif current.prev: # NOTE: Goes Up one Node
            add_node(add_dll=[current])

            # ---------------  Check if we can go to the left.
            if current.prev.right.left and current.prev.right.left not in visited: # NOTE: Goes deeper 
                add_node(current.prev, current.prev.right, add_dll=[current.prev])

                if current.prev.prev: # NOTE: Backtracking
                    stack.append(current.prev.prev)
                stack.append(current.prev.right.left)    
                continue

            # ------------- Here We Handle in case previous Node Has ONLY Right path
            elif current.prev.right.right:  
                if current.prev.right.right.left:  # If has Left Node we go deeper
                    stack.append(current.right.right.left)    
                    continue
                add_node(add_dll=[current.prev.right.right])              
            else:     
                add_node(current.prev, add_dll=[current.prev])

                if current.prev.right: # DOES the Prev node have a Right node?
                    add_node(current.prev.right, add_dll=[current.prev.right])
                
        
                if current.prev.prev and current.prev.prev not in visited: # NOTE: BackTrackin
                    stack.append(current.prev.prev)
        #  -------------- >N OTE: Here Handle The 'Root node' (i.e. 10), only option is to go to right
        elif current.right: 
            add_node(current, add_dll=[current])
            if current.right.left: # Going Deeper
                stack.append(current.right.left)    
                continue
            elif current.right.right:   
                if current.right.right.left:
                    stack.append(current.right.right.left)    
                    continue
                add_node(current.right, current.right.right, add_dll=[current.right, current.right.right])                
            else:    
                add_node(current.right, add_dll=[current.right])  
    
    return doubly_linked_list

    
def show_ddl(ddl):
    """Helper function, used to print the Doubly Linked List"""
    for node in ddl:
        print(f'{node.data} --> ', end='')


# --------->  Creating The Binary Tree >

root = BinaryTree(10)
root.left = BinaryTree(12)
root.right = BinaryTree(15)
root.left.left = BinaryTree(25)
root.left.right = BinaryTree(30)
root.left.right.left = BinaryTree(60)           
root.left.right.right = BinaryTree(77)
root.right.right = BinaryTree(40)
root.right.left = BinaryTree(36)
root.right.left.left = BinaryTree(50)
root.right.left.right = BinaryTree(13)

print('\nBynary Tree:\n')
root.create_tree(show_tree=True)
print()
print('==='*15)
print()
# --------->  Creating The Doubly Linked List >
print('Doubly Linked List:\n')
dll = create_dll(root)
show_ddl(dll)

输出

Bynary Tree:

10 --> 12 --> 25 --> 30 --> 60 --> 77 --> 15 --> 36 --> 50 --> 13 --> 40 -->
=============================================

Doubly Linked List:

25 --> 12 --> 60 --> 30 --> 77 --> 10 --> 50 --> 36 --> 13 --> 15 --> 40 -->

【讨论】:

  • 当然谢谢!我会通过你的代码,理解逻辑并尝试自己编写它!
  • @ShubhamPrashar 看我添加了一个解释并改进了代码,我昨天匆忙做了,有一些不必要的步骤。我想解释一下我现在是怎么做的,还有图片等等。看代码似乎一团糟,似乎没有看到,但是`create_dll`函数所做的正是我在那些图片中解释的。这就是为什么许多 if -elif 语句的原因。希望这对人有所帮助
  • 非常感谢您的帮助,伙计!祝你有一个超级美好的一天,干杯!
猜你喜欢
  • 2012-07-15
  • 2011-04-14
  • 2012-02-28
  • 2015-09-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多