程序员面试题精选100题(01)-把二元查找树转变成排序的双向链表—python实现

本作品采用知识共享署名-非商业性使用-相同方式共享 3.0 Unported许可协议进行许可。允许非商业转载,但应注明作者及出处。


作者:liuyuan_jq

2011-07-13




题目:输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。要求不能创建任何新的结点,只调整指针的指向。

  比如将二元查找树
    
                                        10
                                          /    \
                                        6       14
                                      /  \     /  \
                                    4     8  12    16
转换成双向链表

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

  分析:本题是微软的面试题。很多与树相关的题目都是用递归的思路来解决,本题也不例外。下面我们用两种不同的递归思路来分析。

  思路一:当我们到达某一结点准备调整以该结点为根结点的子树时,先调整其左子树将左子树转换成一个排好序的左子链表,再调整其右子树转换右子链表。最近链接左子链表的最右结点(左子树的最大结点)、当前结点和右子链表的最左结点(右子树的最小结点)。从树的根结点开始递归调整所有结点。

  思路二:我们可以中序遍历整棵树。按照这个方式遍历树,比较小的结点先访问。如果我们每访问一个结点,假设之前访问过的结点已经调整成一个排序双向链表,我们再把调整当前结点的指针将其链接到链表的末尾。当所有结点都访问过之后,整棵树也就转换成一个排序双向链表了。

参考代码:

首先我们定义二元查找树结点的数据结构如下:
    struct BSTreeNode // a node in the binary search tree
    {
        int          m_nValue; // value of node
        BSTreeNode  *m_pLeft;  // left child of node
        BSTreeNode  *m_pRight; // right child of node
    };


#!/usr/bin/env python
# -*- coding:utf-8 -*-


"""
把二元查找树转变成排序的双向链表
 题目:
输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。
要求不能创建任何新的结点,只调整指针的指向。
    
  10
  / \
 6   14
 / \ / \
4 8 12 16
    
 转换成双向链表
4=6=8=10=12=14=16。


 首先我们定义的二元查找树 节点的数据结构如下:
 struct BSTreeNode
{
  int m_nValue; // value of node
  BSTreeNode *m_pLeft; // left child of node
  BSTreeNode *m_pRight; // right child of node
};


"""


class BSTreeNode(object):
    def __init__(self, value, leftNode = None, rightNode = None):
        self.m_nValue = value
        self.m_pLeft  = leftNode
        self.m_pRight = rightNode


    def __cmp__(self, other):
        if self.m_nValue == other.m_nValue:
            return 0
        elif self.m_nValue < other.m_nValue:
            return -1
        else:
            return 1


    def __lt__(self, other):
        if self.m_nValue < other.m_nValue:
            return True
        else:
            return False


    def __gt__(self, other):
        if self.m_nValue > other.m_nValue:
            return True
        else:
            return False
         
    def __eq__(self, other):
        if self.m_nValue == other.m_nValue:
            return True
        else:
            return False


    def __le__(self, other):
        if self.m_nValue <= other.m_nValue:
            return True
        else:
            return False


    def __ge__(self, other):
        if self.m_nValue >= other.m_nValue:
            return True
        else:
            return False




class BSTree(object):
    
    BSTREE_TYPE_TREE   = 1
    BSTREE_TYPE_DBLIST = 2
    
    def __init__(self, values = None):
        self.rootNode = None
        self.type     = self.BSTREE_TYPE_TREE
        self.values = values
        if values:
            self._sort()
        self.head = self.getHead()
        self.tail = self.getTail()


     
    def _sort(self):
        self.rootNode = BSTreeNode(values[0])
        for value in self.values[1:]:
            lastNode = self.rootNode
            newNode  = BSTreeNode(value)
            while True:
                if lastNode.m_pLeft is None and newNode <= lastNode:
                    lastNode.m_pLeft = newNode
                    break
                elif lastNode.m_pRight is None and newNode > lastNode:
                    lastNode.m_pRight = newNode
                    break
                else:
                    lastNode = lastNode.m_pLeft if newNode <= lastNode else lastNode.m_pRight


    def insert(self, value):
        newNode = BSTreeNode(value)
        if self.rootNode is None:
            self.rootNode = newNode
        else:
            lastNode = self.rootNode
            while True:
                if newNode <= lastNode:
                    
                    if lastNode.m_pLeft is None:
                        lastNode.m_pLeft = newNode
                        break
                    lastNode = lastNode.m_pLeft
                elif newNode > lastNode:
                    if lastNode.m_pRight is None:
                        lastNode.m_pRight = newNode
                        break
                    lastNode = lastNode.m_pRight


        
    def _dump(self, node):
        if node:
            self._dump(node.m_pLeft)
            print node.m_nValue
            self._dump(node.m_pRight)


    def dump(self):
        if self.type == self.BSTREE_TYPE_TREE:
            self._dump(self.rootNode)
        elif self.type == self.BSTREE_TYPE_DBLIST:
            self._dumpDoubleList()


    def _dumpDoubleList(self):
        print "Head -> Tail"
        curNode = self.head
        while curNode:
            print curNode.m_nValue
            curNode = curNode.m_pRight
        
        print "Tail -> Head"
        curNode = self.tail
        while curNode:
            print curNode.m_nValue
            curNode = curNode.m_pLeft


    def getHead(self):
        node = None
        if self.rootNode:
            node = self.rootNode
            while node.m_pLeft:
                node = node.m_pLeft
        return node
        


    def getTail(self):
        node = None
        if self.rootNode:
            node = self.rootNode
            while node.m_pRight:
                node = node.m_pRight
        return node
    
    def _convertToDoubleList(self, node, flag = False):
        # 递归结束
        if node is None:
            return None
        
        # 获得左右子树
        leftNode  = self._convertToDoubleList(node.m_pLeft, False)
        rightNode = self._convertToDoubleList(node.m_pRight, True)
        if leftNode is not None:
            leftNode.m_pRight = node
        node.m_pLeft = leftNode
        if rightNode is not None:
            rightNode.m_pLeft = node
        node.m_pRight = rightNode
        
        # 获得最小的节点
        if flag:
            while node.m_pLeft:
                node = node.m_pLeft
        # 获得最大的节点
        else:
            while node.m_pRight:
                node = node.m_pRight
                
        return node
    
    def convertToDoubleList(self, flag = False):
        """ 
        分析:可以采用递归的思想,先将左子树转成双向列表,再将右子树转成双向列表,
        最后将这两个双向列表及根结点组首尾相接,组合成一个双向列表。
        
        当我们到达某一结点准备调整以该结点为根结点的子树时,
        先调整其左子树将左子树转换成一个排好序的左子链表,
        再调整其右子树转换右子链表。
        最近链接左子链表的最右结点(左子树的最大结点)、当前结点和右子链表的最左结点(右子树的最小结点)。
        从树的根结点开始递归调整所有结点。
        """
        self.type = self.BSTREE_TYPE_DBLIST
        return self._convertToDoubleList(self.rootNode, flag)
    
    def _convertToDoubleList2(self, node):
        if node is None:
            return


        global lastNodeInList


        if node.m_pLeft:
            self._convertToDoubleList2(node.m_pLeft)
            
        node.m_pLeft = lastNodeInList
        if lastNodeInList:
            lastNodeInList.m_pRight = node
        lastNodeInList = node
        
        if node.m_pRight:
            self._convertToDoubleList2(node.m_pRight)
        
    def convertToDoubleList2(self):
        """
        二叉查找树的中序遍历结果是升序排列的,与题目要求相符。
        因此,考虑用中序遍历来给出结果。
        
        我们可以中序遍历整棵树。按照这个方式遍历树,比较小的结点先访问。
        如果我们每访问一个结点,假设之前访问过的结点已经调整成一个排序双向链表,
        我们再把调整当前结点的指针将其链接到链表的末尾。
        当所有结点都访问过之后,整棵树也就转换成一个排序双向链表了。
        """
        self.type = self.BSTREE_TYPE_DBLIST
        self._convertToDoubleList2(self.rootNode)
        
    


if __name__ == '__main__':


    values = [10, 6, 14, 4, 8, 12, 16]
    tree = BSTree(values)
    print "BSTreeNode test"
    tree.dump()
    tree.convertToDoubleList()
    print "BSTreeNode DoubleList test"
    tree.dump()
    
    print "BSTreeNode DoubleList convertToDoubleList test"    
    tree = BSTree(values)
    tail = tree.convertToDoubleList(False)


    print "Tail -> Head"
    while tail:
        print tail.m_nValue
        tail = tail.m_pLeft 


    tree = BSTree(values)
    head = tree.convertToDoubleList(True)
    print "Head -> Tail"
    while head:
        print head.m_nValue
        head = head.m_pRight


    print "BSTreeNode DoubleList convertToDoubleList2 test"
    tree = BSTree(values)
    lastNodeInList = None
    tree.convertToDoubleList2()
    tail = lastNodeInList
    print "Tail -> Head"
    while tail:
        print tail.m_nValue
        tail = tail.m_pLeft


你可能感兴趣的:(算法,面试题,python)