剑指offer-二叉搜索树与双向链表(递归和非递归)-java实现

56 篇文章 4 订阅
5 篇文章 0 订阅

题目:

输入一颗二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向,比如输入下图中左边的二叉搜索树,则输出转换之后的排序双向链表。


 
 
  1. struct BinaryTreeNode{
  2. int m_nValue;
  3. BinaryTreeNode* m_pLeft;
  4. BinaryTreeNode* m_pRight;
  5. }
思路1:

在二叉树中,每个结点都有两个指向子结点的指针。在双向链表中,每个结点也有两个指针,它们分别指向前一个结点和后一个结点。故链表和二叉搜索树的结构是相似的。在二叉搜索树中,左子结点的值总是小于父结点的值,右子结点的值总是大于父结点的值。因此在转换成排序双向链表时,原先指向左子结点的指针调整为链表中指向前一个结点的指针,原先指向右子结点的指针调整为链表中指向后一个结点的指针。

要求转换之后是有序的,我们知道二叉搜索树的中序遍历结果也是有序的。当中序遍历到根结点的时候,我们把二叉搜索树看成3部分:值为10的结点,根结点为6的左子树,根结点为14的右子树。根据排序链表的定义,值为10的结点将和它的左子树的最大一个结点值为8的结点链接起来,同时它还将和右子树中最小的结点值为12的结点链接起来。如下图:

注:根结点、左子树、右子树。在把左右子树都转换成排序的双向链表之后再和根结点链接起来,整颗二叉搜索树也就转换成了排序的双向链表

按照中序递归遍历中,当我们遍历转换到根结点时,它的左子树已经转换成了一个排序的链表,并且此时链表尾部的值为左子树中值最大的结点的值(8)。我们将它(8)和根结点(10)链接起来,此时根结点(10)变成了链表尾部,接着去遍历右子树,我们知道中序遍历根结点(10)后的一个结点此时为右子树值最小的结点(12),我们将它和根结点链接起来。左右子树再用这样的办法,即递归即可解决问题。

代码实现:


 
 
  1. public class BinaryTreeNode {
  2. public int m_nValue;
  3. public BinaryTreeNode m_pLeft;
  4. public BinaryTreeNode m_pRight;
  5. }

 
 
  1. public class Main2 {
  2. BinaryTreeNode head = null; //定义链表当前结点
  3. BinaryTreeNode realHead = null; //定义链表头部的结点
  4. //中序递归遍历修改链表指针即可实现
  5. public BinaryTreeNode convert(BinaryTreeNode pRootOfTree){
  6. if(pRootOfTree == null){
  7. return null;
  8. }
  9. convert(pRootOfTree.m_pLeft); //左
  10. if(head == null){ //根
  11. head = pRootOfTree;
  12. realHead = pRootOfTree;
  13. } else{
  14. head.m_pRight = pRootOfTree;
  15. pRootOfTree.m_pLeft = head;
  16. head = pRootOfTree;
  17. }
  18. convert(pRootOfTree.m_pRight); //右
  19. return realHead;
  20. }
  21. //main方法测试
  22. public static void main(String[] args) {
  23. Main2 m2 = new Main2();
  24. BinaryTreeNode node1 = new BinaryTreeNode();
  25. node1.m_nValue = 1;
  26. BinaryTreeNode node2= new BinaryTreeNode();
  27. node2.m_nValue = 2;
  28. BinaryTreeNode node3 = new BinaryTreeNode();
  29. node3.m_nValue = 3;
  30. node2.m_pLeft = node1;
  31. node2.m_pRight = node3;
  32. BinaryTreeNode head = m2.convert(node2);
  33. System.out.println(head.m_nValue);
  34. System.out.println(head.m_pRight.m_nValue);
  35. System.out.println(head.m_pRight.m_pRight.m_nValue);
  36. }
  37. }

思路2:非递归借助栈实现

我们借助一个栈实现二叉树非递归的中序遍历,并修改其结点的指针实现双向排序的链表。

代码实现:


 
 
  1. public BinaryTreeNode convert(BinaryTreeNode pRootOfTree){
  2. if(pRootOfTree == null){
  3. return null;
  4. }
  5. BinaryTreeNode list = null;
  6. Stack<BinaryTreeNode> stack = new Stack<BinaryTreeNode>();
  7. while(pRootOfTree != null || !stack.isEmpty()){
  8. if(pRootOfTree!= null){
  9. stack.push(pRootOfTree);
  10. pRootOfTree = pRootOfTree.m_pRight;
  11. } else{
  12. pRootOfTree = stack.pop();
  13. if(list == null){
  14. list = pRootOfTree;
  15. } else{
  16. list.m_pLeft = pRootOfTree;
  17. pRootOfTree.m_pRight = list;
  18. list = pRootOfTree;
  19. }
  20. pRootOfTree = pRootOfTree.m_pLeft;
  21. }
  22. }
  23. return list;
  24. }

小思:

感觉在考查我们二叉搜索树中序遍历和双向排序的链表之间的关系,以及怎么去修改二叉搜索树的指针。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值