天天看點

二叉查找樹轉變為有序雙向連結清單

題目:輸入一棵二進制查找樹,将該二進制查找樹轉換成一個排序的雙向連結清單。要求不能建立任何新的結點,隻調整指針的指向。

  比如将二進制查找樹

                                         10

                                        /    \

                                      6       14

                                    /  \     /  \

                                 4     8  12   16

轉換成雙向連結清單

4=6=8=10=12=14=16。

一道微軟的面試題。

二叉查找樹的每個節點都有兩個指針,雙向連結清單的節點也是兩個指針,不建立新節點隻調整指針是可以完成轉變的。

對于二叉查找樹的每個節點Node,它的左子樹中所有的關鍵字都小于Node的關鍵字,而右子樹中的所有關鍵字都大于Node的關鍵字。

采用遞歸的思維可以很友善的完成轉變,将節點的左右子樹分别轉變成有序連結清單,然後将節點的指針分别指向這兩個連結清單。

import random
class Node(object):
    def __init__(self,key):
        self.key=key
        self.left=None
        self.right=None
class BSTree(object):
    def __init__(self):
        self.root=None
    def put(self,key):
        if not self.root:
            self.root=Node(key)
        else:
            self.root=self._put(self.root,key)
    def _put(self,node,key):
        if node is None:
            node=Node(key)
        elif key<node.key:
            node.left=self._put(node.left,key)
        elif key>node.key:
            node.right=self._put(node.right,key)
        return node  
    def convert(self):
        if self.root:
            return self._convert(self.root)
    def _convert(self,node,asright=True):
        if not node:
            return None
        else:
            left=self._convert(node.left,False)
            if left:
                left.right=node
                node.left=left
            right=self._convert(node.right)
            if right:
                right.left=node
                node.right=right
            cur=node
            if asright:
                while cur.left:
                    cur=cur.left
            if not asright:
                while cur.right:
                    cur=cur.right
            return cur
                
            
if __name__=='__main__':
    t=BSTree()   
    for i in range(10):
        t.put(random.randint(0,100))    
    cur=t.convert()
    if cur:
        print cur.key
        while cur.right:
            cur=cur.right
            print cur.key
        while cur.left:
            cur=cur.left
            print cur.key      

  另一種思路是采用中序周遊的方法。二叉查找樹中序周遊的話就是從小到大排列。将周遊過的節點轉為有序連結清單,然後将下一個要周遊的節點加到連結清單結尾。

import random
class Node(object):
    def __init__(self,key):
        self.key=key
        self.left=None
        self.right=None
class Sorted_LinkedList(object):
    def __init__(self):
        self.head=None
    def travel(self):
        node=self.head
        while node:
            print node.key
            node=node.right
class BSTree(object):
    def __init__(self):
        self.root=None
        self.list=Sorted_LinkedList()
        self.curNode=None
    def put(self,key):
        if not self.root:
            self.root=Node(key)
        else:
            self.root=self._put(self.root,key)
    def _put(self,node,key):
        if node is None:
            node=Node(key)
        elif key<node.key:
            node.left=self._put(node.left,key)
        elif key>node.key:
            node.right=self._put(node.right,key)
        return node  
    def convert(self):
        self._travel(self.root)
        return self.list
    def _travel(self,node):
        if node:
             self._travel(node.left)
             if self.curNode:
                 self.curNode.right=node
                 node.left=self.curNode
             else:
                 self.list.head=node
             self.curNode=node
             self._travel(node.right)
                        
if __name__=='__main__':
    t=BSTree()   
    for i in range(100):
        t.put(random.randint(0,100))
    l=t.convert()
    l.travel()