题目:输入一颗二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能建立新的结点,只能调整树中结点指针的指向。node
好比以下图中的二叉搜索树,则输出转换以后的排序双向链表为:算法
在二叉树中,每一个结点都有两个指向子节点的指针。在双向链表中,每一个 结点也有两个指针,他们分别指向前一个结点和后一个结点。因为这两种结点的结构类似,同时二叉搜索树也是一种排序的数据结构,所以在理论上有可能实现二叉 搜索树和排序的双向链表的转换。在搜索二叉树中,左子结点的值老是小于父节点的值,右子节点的值老是大于父节点的值。所以咱们在转换称排序的双向链表时, 原先指向的左子结点的指针调整为链表中指向前一个结点的指针,原先指向右子节点的指针调整为俩表为指向后一个结点的指针。接下来咱们考虑如何转化。数组
因为要求转换以后的链表是排好序的,咱们可疑中序遍历树中的每个结 点,这是由于中序遍历算法的特色是按照从小到达的顺序遍历二叉树的每个结点。当遍历到根节点的时候,咱们把树堪称三部分:值为10的结点,根节点为6的 左子树、根节点为14的右子树。根据排序链表的定义,值为10的结点将和它的左子树的最大的一个结点(即值为8的结点)连接起来,同时它还将和右子树最小 的结点(即值为12的结点)连接起来,如图:数据结构
按照中序遍历的顺序,当咱们遍历转换到根节点(值为10的结点)时, 它的左子树已经转换成一个排序的链表了,而且处在链表中的最后一个结点是当前值的最大的结点。咱们把值为8的结点根节点连接起来,此时链表中的最后一个结 点是10了。接着咱们去遍历转换右子树,并把根节点和右子树最小的结点连接起来。至于怎么去转换它的左子树和右子树,因为遍历和转换过程是同样的,咱们自 然的想到了递归。spa
Java代码实现:.net
package cglib;指针
class BinaryTreeNode
{排序
int value;递归
BinaryTreeNode left ;get
BinaryTreeNode right ;
}
public class DeleteNode{
/**
* 题目:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。
* 要求不能建立任何新的结点,只能调整树中结点指针的指向。
*
* @param root 二叉树的根结点
* @return 双向链表的头结点
*/
public static BinaryTreeNode convert(BinaryTreeNode root) {
// 用于保存处理过程当中的双向链表的尾结点
BinaryTreeNode[] lastNode = new BinaryTreeNode[1];
convertNode(root, lastNode);
// 找到双向链表的头结点
BinaryTreeNode head = lastNode[0];
System.out.println("lastNode[0]="+lastNode[0]);
while (head != null && head.left != null) {
head = head.left;
}
return head;
}
/**
* 链表转换操做
*
* @param node 当前的根结点
* @param lastNode 已经处理好的双向链表的尾结点,使用一个长度为1的数组,相似C++中的二级指针
*/
public static void convertNode(BinaryTreeNode node, BinaryTreeNode[] lastNode) {
// 结点不为空
if (node != null) {
// 若是有左子树就先处理左子树
if (node.left != null) {
convertNode(node.left, lastNode);
}
//原先指向左子结点的指针调整为链表中指向前一个结点的指针,原先指向右子结点的指针调整为链表中指向下一个结点的指针
// 将当前结点的前驱指向已经处理好的双向链表(由当前结点的左子树构成)的尾结点
node.left = lastNode[0];//4<->6<->8<->10<->12<->14<->16,10的前指针是6,后指针是10,6的前指针是4,后指针是8
// 若是左子树转换成的双向链表不为空,设置尾结点的后继
if (lastNode[0] != null) {
lastNode[0].right = node;// 将根节点和左子树转换后的双向有序链表的最后一个节点链接
}
// 记录当前结点为尾结点
lastNode[0] = node;
// 处理右子树
if (node.right != null) {
convertNode(node.right, lastNode);
}
}
}
public static void main(String[] args) {
test01();
test02();
test03();
test04();
test05();
}
private static void printList(BinaryTreeNode head) {
while (head != null) {
System.out.print(head.value + "->");
head = head.right;
}
System.out.println("null");
}
private static void printTree(BinaryTreeNode root) {
if (root != null) {//递归中序遍历先左子树,而后根节点,最后右子树
printTree(root.left);
System.out.print(root.value + "->");
printTree(root.right);
}
}
// 10
// / \
// 6 14
// /\ /\
// 4 8 12 16
private static void test01() {
BinaryTreeNode node10 = new BinaryTreeNode();
node10.value = 10;
BinaryTreeNode node6 = new BinaryTreeNode();
node6.value = 6;
BinaryTreeNode node14 = new BinaryTreeNode();
node14.value = 14;
BinaryTreeNode node4 = new BinaryTreeNode();
node4.value = 4;
BinaryTreeNode node8 = new BinaryTreeNode();
node8.value = 8;
BinaryTreeNode node12 = new BinaryTreeNode();
node12.value = 12;
BinaryTreeNode node16 = new BinaryTreeNode();
node16.value = 16;
node10.left = node6;
node10.right = node14;
node6.left = node4;
node6.right = node8;
node14.left = node12;
node14.right = node16;
System.out.print("Before convert中序遍历: ");
printTree(node10);
System.out.println("null");
BinaryTreeNode head = convert(node10);
System.out.print("After convert : ");
printList(head);
System.out.println();
}
// 5
// /
// 4
// /
// 3
// /
// 2
// /
// 1
private static void test02() {
BinaryTreeNode node1 = new BinaryTreeNode();
node1.value = 1;
BinaryTreeNode node2 = new BinaryTreeNode();
node2.value = 2;
BinaryTreeNode node3 = new BinaryTreeNode();
node3.value = 3;
BinaryTreeNode node4 = new BinaryTreeNode();
node4.value = 4;
BinaryTreeNode node5 = new BinaryTreeNode();
node5.value = 5;
node5.left = node4;
node4.left = node3;
node3.left = node2;
node2.left = node1;
System.out.print("Before convert: ");
printTree(node5);
System.out.println("null");
BinaryTreeNode head = convert(node5);
System.out.print("After convert : ");
printList(head);
System.out.println();
}
// 1
// \
// 2
// \
// 3
// \
// 4
// \
// 5
private static void test03() {
BinaryTreeNode node1 = new BinaryTreeNode();
node1.value = 1;
BinaryTreeNode node2 = new BinaryTreeNode();
node2.value = 2;
BinaryTreeNode node3 = new BinaryTreeNode();
node3.value = 3;
BinaryTreeNode node4 = new BinaryTreeNode();
node4.value = 4;
BinaryTreeNode node5 = new BinaryTreeNode();
node5.value = 5;
node1.right = node2;
node2.right = node3;
node3.right = node4;
node4.right = node5;
System.out.print("Before convert: ");
printTree(node1);
System.out.println("null");
BinaryTreeNode head = convert(node1);
System.out.print("After convert : ");
printList(head);
System.out.println();
}
// 只有一个结点
private static void test04() {
BinaryTreeNode node1 = new BinaryTreeNode();
node1.value = 1;
System.out.print("Before convert: ");
printTree(node1);
System.out.println("null");
BinaryTreeNode head = convert(node1);
System.out.print("After convert : ");
printList(head);
System.out.println();
}
// 没有结点
private static void test05() {
System.out.print("Before convert: ");
printTree(null);
System.out.println("null");
BinaryTreeNode head = convert(null);
System.out.print("After convert : ");
printList(head);
System.out.println();
}
}
输出:
Before convert中序遍历: 4->6->8->10->12->14->16->null
lastNode[0]=cglib.BinaryTreeNode@139a55
After convert : 4->6->8->10->12->14->16->null
Before convert: 1->2->3->4->5->null
lastNode[0]=cglib.BinaryTreeNode@1db9742
After convert : 1->2->3->4->5->null
Before convert: 1->2->3->4->5->null
lastNode[0]=cglib.BinaryTreeNode@106d69c
After convert : 1->2->3->4->5->null
Before convert: 1->null
lastNode[0]=cglib.BinaryTreeNode@52e922
After convert : 1->null
Before convert: null
lastNode[0]=null
After convert : null
--------------------------------------------------------
思路更清晰的:
若是左子树为空,对应双向有序链表的第一个节点是根节点,左边不须要其余操做;
若是左子树不为空,转换左子树,二叉查找树对应双向有序链表的第一个节点就是左子树转换后双向有序链表的第一个节点,同时将根节点和左子树转换后的双向有序链 表的最后一个节点链接;
若是右子树为空,对应双向有序链表的最后一个节点是根节点,右边不须要其余操做;
若是右子树不为空,对应双向有序链表的最后一个节点就是右子树转换后双向有序链表的最后一个节点,同时将根节点和右子树转换后的双向有序链表的第一个节点连 接。
/****************************************************************************** 参数: pRoot: 二叉查找树根节点指针 pFirstNode: 转换后双向有序链表的第一个节点指针 pLastNode: 转换后双向有序链表的最后一个节点指针 ******************************************************************************/ void Convert(BinaryTreeNode * pRoot, BinaryTreeNode * & pFirstNode, BinaryTreeNode * & pLastNode) { BinaryTreeNode *pFirstLeft, *pLastLeft, * pFirstRight, *pLastRight; if(pRoot == NULL) { pFirstNode = NULL; pLastNode = NULL; return; } if(pRoot->m_pLeft == NULL) { // 若是左子树为空,对应双向有序链表的第一个节点是根节点 pFirstNode = pRoot; } else { Convert(pRoot->m_pLeft, pFirstLeft, pLastLeft); // 二叉查找树对应双向有序链表的第一个节点就是左子树转换后双向有序链表的第一个节点 pFirstNode = pFirstLeft; // 将根节点和左子树转换后的双向有序链表的最后一个节点链接 pRoot->m_pLeft = pLastLeft; pLastLeft->m_pRight = pRoot; } if(pRoot->m_pRight == NULL) { // 对应双向有序链表的最后一个节点是根节点 pLastNode = pRoot; } else { Convert(pRoot->m_pRight, pFirstRight, pLastRight); // 对应双向有序链表的最后一个节点就是右子树转换后双向有序链表的最后一个节点 pLastNode = pLastRight; // 将根节点和右子树转换后的双向有序链表的第一个节点链接 pRoot->m_pRight = pFirstRight; pFirstRight->m_pRight = pRoot; } return; }