本作品采用知识共享署名-非商业性使用-相同方式共享 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