9.剑指offer-二叉搜索树与双向链表

1.题目描述

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。

二叉搜索树的结构如下:

struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};

2.基本思路

中序遍历二叉排序树会得到一个有序的序列。因此这道题考察的是中序遍历

如果使用递归来做,那么因为在一个递归中,当前节点p仅能访问到其左子树节点和右子树节点,而p在双向链表中的直接前驱节点不一定是其左子节点,因此需要一个全局变量来记录在访问一个节点p时,前一个访问的节点的指针是谁。

Note:

    1. 假设已经转化完毕,那么你如何确定双向链表的头节点?
      • 再遍历一遍 or 更为节省时间的做法? 访问节点p时,如果前一个访问的节点是NULL, 则说明该节点是双向链表的头节点。
    2. 假设前驱节点是pre,当前访问节点是p,在转化成双向链表时,一定要注意你是用p的左指针指向pre还是右指针指向pre?这个顺序很重要,它直接关系到最外层的中序遍历能否进行下去。正确顺序如下:
      • p->left=pre; // 这样才能保证在左子树访问完毕后,还能接着访问右子树,如果你这里使用是p->right=pre,则遍历就会失败。
      • pre->right=p;

3.代码如下

  • 递归代码

      void  middleVisited(TreeNode *pHead,TreeNode **head,TreeNode **pre){
          if(pHead){
              middleVisited(pHead->left,head,pre);
              if( (*pre)==NULL ){ // 如果前一个节点为NULL,则其为头节点
                  (*head)=pHead;
                  (*pre)=pHead; 
              }else{// 如果前一个访问的节点不是NULL,则该节点为双向链表中p节点的直接前驱节点
                  pHead->left=(*pre);
                  (*pre)->right=pHead;
                  (*pre)=pHead;
    
              }
               middleVisited(pHead->right,head,pre);
    
          }
    
      }
      TreeNode* Convert(TreeNode* pRootOfTree)
      {
           if(pRootOfTree==NULL)
               return NULL;
          TreeNode *head,*pre,*pHead;
          pHead=pRootOfTree;
          head=NULL;
          pre=NULL;
          middleVisited(pHead,&head,&pre);
          return head;
      }
  • 循环代码

      TreeNode* Convert(TreeNode* pRootOfTree)
      {
          if(pRootOfTree==NULL)
              return NULL;
          TreeNode *p,*pre,*head;
          p=pRootOfTree;
          pre=NULL;
          head=NULL;
          stack<TreeNode*> S;
          while(p!=NULL || S.size() ){
              while(p!=NULL){
                  S.push(p);
                  p=p->left;
              }
              p=S.top();
              S.pop();
              if(pre==NULL){
                  head=p;
                  pre=p;
              }else{
                  p->left=pre;
                  pre->right=p;
                  pre=p;
              }
              p=p->right;
          }
          return head;
      }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值