首页 > 试题广场 >

二叉搜索树与双向链表

[编程题]二叉搜索树与双向链表
  • 热度指数:626299 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。如下图所示


数据范围:输入二叉树的节点数 ,二叉树中每个节点的值
要求:空间复杂度(即在原树上操作),时间复杂度

注意:
1.要求不能创建任何新的结点,只能调整树中结点指针的指向。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继
2.返回链表中的第一个节点的指针
3.函数返回的TreeNode,有左右指针,其实可以看成一个双向链表的数据结构
4.你不用输出双向链表,程序会根据你的返回值自动打印输出

输入描述:
二叉树的根节点


输出描述:
双向链表的其中一个头节点。
示例1

输入

{10,6,14,4,8,12,16}

输出

From left to right are:4,6,8,10,12,14,16;From right to left are:16,14,12,10,8,6,4;

说明

输入题面图中二叉树,输出的时候将双向链表的头节点返回即可。     
示例2

输入

{5,4,#,3,#,2,#,1}

输出

From left to right are:1,2,3,4,5;From right to left are:5,4,3,2,1;

说明

                    5
                  /
                4
              /
            3
          /
        2
      /
    1
树的形状如上图       

说明:本题目包含复杂数据结构TreeNode,点此查看相关信息
推荐
方法一:非递归版
解题思路:
1.核心是中序遍历的非递归算法。
2.修改当前遍历节点与前一遍历节点的指针指向。
    import java.util.Stack;
    public TreeNode ConvertBSTToBiList(TreeNode root) {
    	if(root==null)
    		return null;
    	Stack<TreeNode> stack = new Stack<TreeNode>();
    	TreeNode p = root;
    	TreeNode pre = null;// 用于保存中序遍历序列的上一节点
    	boolean isFirst = true;
    	while(p!=null||!stack.isEmpty()){
    		while(p!=null){
    			stack.push(p);
    			p = p.left;
    		}
    		p = stack.pop();
    		if(isFirst){
    			root = p;// 将中序遍历序列中的第一个节点记为root
    			pre = root;
    			isFirst = false;
    		}else{
    			pre.right = p;
    			p.left = pre;
    			pre = p;
    		}		
    		p = p.right;
    	}
    	return root;
    }
方法二:递归版
解题思路:
1.将左子树构造成双链表,并返回链表头节点。
2.定位至左子树双链表最后一个节点。
3.如果左子树链表不为空的话,将当前root追加到左子树链表。
4.将右子树构造成双链表,并返回链表头节点。
5.如果右子树链表不为空的话,将该链表追加到root节点之后。
6.根据左子树链表是否为空确定返回的节点。
    public TreeNode Convert(TreeNode root) {
    	if(root==null)
    		return null;
    	if(root.left==null&&root.right==null)
    		return root;
    	// 1.将左子树构造成双链表,并返回链表头节点
    	TreeNode left = Convert(root.left);
    	TreeNode p = left;
    	// 2.定位至左子树双链表最后一个节点
    	while(p!=null&&p.right!=null){
    		p = p.right;
    	}
    	// 3.如果左子树链表不为空的话,将当前root追加到左子树链表
    	if(left!=null){
    		p.right = root;
    		root.left = p;
    	}
    	// 4.将右子树构造成双链表,并返回链表头节点
    	TreeNode right = Convert(root.right);
    	// 5.如果右子树链表不为空的话,将该链表追加到root节点之后
    	if(right!=null){
    		right.left = root;
    		root.right = right;
    	}
		return left!=null?left:root;        
    }
方法三:改进递归版
解题思路:
思路与方法二中的递归版一致,仅对第2点中的定位作了修改,新增一个全局变量记录左子树的最后一个节点。
    // 记录子树链表的最后一个节点,终结点只可能为只含左子树的非叶节点与叶节点
    protected TreeNode leftLast = null;
    public TreeNode Convert(TreeNode root) {
    	if(root==null)
    		return null;
    	if(root.left==null&&root.right==null){
    		leftLast = root;// 最后的一个节点可能为最右侧的叶节点
    		return root;
    	}
    	// 1.将左子树构造成双链表,并返回链表头节点
    	TreeNode left = Convert(root.left);
    	// 3.如果左子树链表不为空的话,将当前root追加到左子树链表
    	if(left!=null){
    		leftLast.right = root;
    		root.left = leftLast;
    	}
    	leftLast = root;// 当根节点只含左子树时,则该根节点为最后一个节点
    	// 4.将右子树构造成双链表,并返回链表头节点
    	TreeNode right = Convert(root.right);
    	// 5.如果右子树链表不为空的话,将该链表追加到root节点之后
    	if(right!=null){
    		right.left = root;
    		root.right = right;
    	}
		return left!=null?left:root;        
    }

编辑于 2015-08-18 23:36:07 回复(111)
struct TreeNode* Convert(struct TreeNode* pRootOfTree ) {
    struct TreeNode *LeftTreeNode, *RootTreeNode, *RightTreeNode, *res;
    if(pRootOfTree==NULL)
        return NULL;
    RootTreeNode = (struct TreeNode*)malloc(sizeof(struct TreeNode));
    RootTreeNode->val = pRootOfTree->val;
    RootTreeNode->left = NULL;
    RootTreeNode->right = NULL;
    res = RootTreeNode;

    if(pRootOfTree->left) {
        struct TreeNode *p;
        LeftTreeNode = Convert(pRootOfTree->left);
        p = LeftTreeNode;
        while(p->right!=NULL)
            p = p->right;
        p->right = RootTreeNode;
        RootTreeNode->left = p;
        res = LeftTreeNode;
    }

    if(pRootOfTree->right) {
        RightTreeNode = Convert(pRootOfTree->right);
        RightTreeNode->left = RootTreeNode;
        RootTreeNode->right = RightTreeNode;
    }

    return res;
}

编辑于 2024-03-16 16:46:57 回复(0)
/**
 * struct TreeNode {
 *  int val;
 *  struct TreeNode *left;
 *  struct TreeNode *right;
 * };
 */

/**
 *
 * @param pRootOfTree TreeNode类
 * @return TreeNode类
 */
// struct TreeNode* Convert(struct TreeNode* pRootOfTree ) {
//     // write code here
//     if (pRootOfTree == NULL) {
//         return pRootOfTree;
//     }
//     struct TreeNode *left_front = NULL, *right_front = NULL;
//     if (pRootOfTree->left != NULL) {
//         left_front = Convert(pRootOfTree->left);
//         struct TreeNode *temp = left_front;
//         while (temp->right != NULL) {
//             temp = temp->right;
//         }
//         temp->right = pRootOfTree;
//         pRootOfTree->left = temp;
//     }
//     if (pRootOfTree->right != NULL) {
//         right_front = Convert(pRootOfTree->right);
//         pRootOfTree->right = right_front;
//         right_front->left = pRootOfTree;
//     }
//     return left_front == NULL ? pRootOfTree : left_front;
// }

#include <stdio.h>
// morris algorithm
struct TreeNode* Convert(struct TreeNode* pRootOfTree ) {
    // write code here
    struct TreeNode *result = pRootOfTree;
    while (result != NULL && result->left != NULL) {
        result = result->left;
    }

    struct TreeNode* prev = NULL, *curr = pRootOfTree;
    while (curr != NULL) {
        if (curr->left != NULL) {
            struct TreeNode *temp = curr->left;
            while (temp->right != NULL && temp->right != curr) {
                temp = temp->right;
            }
            if (temp->right == NULL) {
                temp->right = curr;
                curr = curr->left;
            } else {
                curr->left = prev;
                struct TreeNode *next = curr->right, *temp = curr->right;
                if (temp != NULL) {
                    while (temp->left != NULL && temp->left != curr) {
                        temp = temp->left;
                    }
                    if (temp->left == NULL) {
                        curr->right = temp;
                    }
                }
                prev = curr;
                curr = next;
            }
        } else {
            curr->left = prev;
            prev = curr;
            curr = curr->right;
        }
    }
    return result;
}
编辑于 2023-12-31 00:21:24 回复(0)
递归
本来在想一棵小树一棵小树展平了连起来
但是还要考虑最左最右怎么连。。
能过但是感觉不太好
struct TreeNode* deep(struct TreeNode* root, struct TreeNode* now){
    if(now==NULL){
        return NULL;
    }
    now->left = deep(now,now->left);
    now->right = deep(now,now->right);

    struct TreeNode* tmp;
    tmp = now;
    if(root==NULL){
        while(tmp->left!=NULL){
            tmp = tmp->left;
        }
        return tmp;
    }

    if(now->val < root->val){
        while(tmp->right!=NULL){
            tmp = tmp->right;
        }
        tmp->right = root;
    }else{
        while(tmp->left!=NULL){
            tmp = tmp->left;
        }
        tmp->left = root;
    }
    return tmp;
}

struct TreeNode* Convert(struct TreeNode* root ) {
    return deep(NULL,root);
}


发表于 2023-09-21 21:17:01 回复(1)
struct TreeNode* Convert(struct TreeNode* pRootOfTree )
{
    // write code here
    static struct TreeNode*head=NULL;
    static struct TreeNode*left=NULL;
    static struct TreeNode*right=NULL;
    static struct TreeNode*f=NULL;

    if(pRootOfTree)
    {
        struct TreeNode*front=NULL;
        struct TreeNode*rear=NULL;
        if(!right&&!left)
        {
            left=pRootOfTree->left;
            right=pRootOfTree->right;
        }

        front=Convert(pRootOfTree->left);
        if(!head&&NULL==front)
        {
            head=pRootOfTree;
        }
        if(f)
        {
            f->right=pRootOfTree;
        }
        pRootOfTree->left=f;
        f=pRootOfTree;
        rear=Convert(pRootOfTree->right);
       
        if(left==front&&right==rear)
        {
            return head;
        }
        return pRootOfTree;
    }
   
    return NULL;
}
发表于 2023-06-29 01:38:28 回复(0)
struct TreeNode* Convert(struct TreeNode* pRootOfTree ) {

    if (NULL == pRootOfTree) {
        return  NULL;
    }
    /*递归左右分开处理*/
    Convert(pRootOfTree->left);
    Convert(pRootOfTree->right);

    struct TreeNode* pL = NULL;
    pL = pRootOfTree->left;
    /*找到左子树的最右面的节点*/
    if(NULL != pL)
    {
        while (NULL != pL->right) {
            pL = pL->right;
        }
        pRootOfTree->left = pL;
        pL->right = pRootOfTree;
    }
   
    struct TreeNode* pR = NULL;
    pR = pRootOfTree->right;;
    /*找到右子树的最左面的节点*/
    if (NULL != pR) {
        while (NULL != pR->left) {
            pR = pR->left;
        }
        pRootOfTree->right = pR;
        pR->left = pRootOfTree;
    }
   
    /*找到链表的头*/
    struct TreeNode* pHead = NULL;
    pHead = pRootOfTree;
    while (NULL != pHead->left) {
            pHead = pHead->left;
        }
    return pHead;
}
发表于 2023-04-07 15:14:03 回复(0)

static struct TreeNode *pre;
void InOrder(struct TreeNode *t){
    if(t==NULL)return ;
    InOrder(t->left);
    //调整指向
    t->left=pre;
    if(pre!=NULL){
        pre->right=t;
    }
    pre=t;
    InOrder(t->right);
}
struct TreeNode* Convert(struct TreeNode* pRootOfTree ) {
    // write code here
    if(pRootOfTree==NULL)return pRootOfTree;
    struct TreeNode *p=pRootOfTree,*pre=NULL;
    while(p->left!=NULL) p=p->left;//起点
    InOrder(pRootOfTree);
    return p;
}

发表于 2022-11-02 17:00:59 回复(0)
typedef struct TreeNode* tLink;
tLink solve(struct TreeNode* root, int flag){
    if(root){
        tLink pre = solve(root->left, 0);
        tLink suc = solve(root->right, 1);
        // 把修改的结点的任务交给parent
        if(pre)
            root->left = pre, pre->right = root;
        if(suc)
            root->right = suc, suc->left = root;
        if(flag == 0){
            while(root->right)
                root = root->right;
        }else{
            while(root->left)
                root = root->left;
        }
        return root;
    }
    return NULL;
}
struct TreeNode* Convert(struct TreeNode* pRootOfTree ) {
    // write code here
    return solve(pRootOfTree, 1);
}
发表于 2022-08-05 05:11:05 回复(0)
typedef struct TreeNode* PTreeNode;

void traverse(PTreeNode root, PTreeNode* pre) {
  if (!root) return;
  traverse(root->right, pre);
  root->right = *pre;
  *pre = *pre ? (*pre)->left = root : root;
  traverse(root->left, pre);
}

/**
 * 
 * @param pRootOfTree TreeNode类 
 * @return TreeNode类
 */
PTreeNode Convert(PTreeNode pRootOfTree) {
  PTreeNode pre = NULL;
  traverse(pRootOfTree, &pre);
  return pre;
}

发表于 2021-07-24 08:36:12 回复(0)