题目:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能建立任何新的结点,只能调整树中结点指针的指向。好比输入下图中左边的二叉搜索树,则输出转换以后的排序双向链表。node
二叉搜索树的节点定义以下,这里使用C#语言描述:算法
public class BinaryTreeNode { public int Data { get; set; } public BinaryTreeNode leftChild { get; set; } public BinaryTreeNode rightChild { get; set; } public BinaryTreeNode(int data) { this.Data = data; } public BinaryTreeNode(int data, BinaryTreeNode left, BinaryTreeNode right) { this.Data = data; this.leftChild = left; this.rightChild = right; } }
首先,咱们知道:在二叉树中,每一个结点都有两个指向子结点的指针。在双向链表中,每一个结点也有两个指针,它们分别指向前一个结点和后一个结点。ide
其次,因为要求转换以后的链表是排好序的,咱们能够中序遍历树中的每个结点,这是由于中序遍历算法的特色是按照从小到大的顺序遍历二叉树的每个结点。单元测试
最后,按照中序遍历的顺序,当咱们遍历转换到根结点(值为10的结点)时,它的左子树已经转换成一个排序的链表了,而且处在链表中的最后一个结点是当前值最大的结点。咱们把值为8的结点和根结点连接起来,此时链表中的最后一个结点就是10了。接着咱们去遍历转换右子树,并把根结点和右子树中最小的结点连接起来。测试
很明显,转换它的左子树和右子树,因为遍历和转换过程是同样的,很天然地想到能够用递归。this
public BinaryTreeNode Convert(BinaryTreeNode root) { BinaryTreeNode lastNodeInList = null; ConvertNode(root, ref lastNodeInList); // lastNodeInList指向双向链表的尾结点, // 咱们须要返回头结点 BinaryTreeNode headInList = lastNodeInList; while (headInList != null && headInList.leftChild != null) { headInList = headInList.leftChild; } return headInList; } private void ConvertNode(BinaryTreeNode node, ref BinaryTreeNode lastNodeInList) { if (node == null) { return; } BinaryTreeNode currentNode = node; // 转换左子树 if (currentNode.leftChild != null) { ConvertNode(currentNode.leftChild, ref lastNodeInList); } // 与根节点的衔接 currentNode.leftChild = lastNodeInList; if (lastNodeInList != null) { lastNodeInList.rightChild = currentNode; } lastNodeInList = currentNode; // 转换右子树 if (currentNode.rightChild != null) { ConvertNode(currentNode.rightChild, ref lastNodeInList); } }
(1)辅助方法的封装spa
private void SetSubTreeNode(BinaryTreeNode root, BinaryTreeNode lChild, BinaryTreeNode rChild) { if (root == null) { return; } root.leftChild = lChild; root.rightChild = rChild; } private BSTConverter converter; [TestInitialize] public void Initialize() { converter = new BSTConverter(); } [TestCleanup] public void CleanUp() { converter = null; }
(2)功能测试、特殊输入测试指针
// 10 // / \ // 6 14 // /\ /\ // 4 8 12 16 [TestMethod] public void ConvertTest1() { BinaryTreeNode node10 = new BinaryTreeNode(10); BinaryTreeNode node6 = new BinaryTreeNode(6); BinaryTreeNode node4 = new BinaryTreeNode(4); BinaryTreeNode node8 = new BinaryTreeNode(8); BinaryTreeNode node14 = new BinaryTreeNode(14); BinaryTreeNode node12 = new BinaryTreeNode(12); BinaryTreeNode node16 = new BinaryTreeNode(16); SetSubTreeNode(node10, node6, node14); SetSubTreeNode(node6, node4, node8); SetSubTreeNode(node14, node12, node16); BinaryTreeNode result = converter.Convert(node10); Assert.AreEqual(result, node4); } // 5 // / // 4 // / // 3 // / // 2 // / // 1 [TestMethod] public void ConvertTest2() { BinaryTreeNode node5 = new BinaryTreeNode(5); BinaryTreeNode node4 = new BinaryTreeNode(4); BinaryTreeNode node3 = new BinaryTreeNode(3); BinaryTreeNode node2 = new BinaryTreeNode(2); BinaryTreeNode node1 = new BinaryTreeNode(1); node5.leftChild = node4; node4.leftChild = node3; node3.leftChild = node2; node2.leftChild = node1; BinaryTreeNode result = converter.Convert(node5); Assert.AreEqual(result, node1); } // 1 // \ // 2 // \ // 3 // \ // 4 // \ // 5 [TestMethod] public void ConvertTest3() { BinaryTreeNode node5 = new BinaryTreeNode(5); BinaryTreeNode node4 = new BinaryTreeNode(4); BinaryTreeNode node3 = new BinaryTreeNode(3); BinaryTreeNode node2 = new BinaryTreeNode(2); BinaryTreeNode node1 = new BinaryTreeNode(1); node1.rightChild = node2; node2.rightChild = node3; node3.rightChild = node4; node4.rightChild = node5; BinaryTreeNode result = converter.Convert(node1); Assert.AreEqual(result, node1); } // 树中只有1个结点 [TestMethod] public void ConvertTest4() { BinaryTreeNode node1 = new BinaryTreeNode(1); BinaryTreeNode result = converter.Convert(node1); Assert.AreEqual(result, node1); } // 空指针 [TestMethod] public void ConvertTest5() { BinaryTreeNode result = converter.Convert(null); Assert.AreEqual(result, null); }
(1)测试经过状况code
(2)代码覆盖率blog