剑指offer 面试题27—二叉搜索树与双向链表

题目:

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


基本思想:

二叉树中每个节点都有两个指向子节点的指针。在双向链表中,每个节点也有两个指针,分别指向前一个节点和后一个节点。

二叉搜索树中,左子节点的值总是小于父节点的值,右子节点的值总是大于父节点的值。

在转换成双向链表时,原先指向左子节点的指针调整为链表中指向前一个节点的指针,原先指向右子节点的指针调整为链表中指向后一个节点的指针。


中序遍历树中的每一个节点,中序遍历算法是按照从小到大的顺序遍历二叉树的。

当遍历到根节点时,树看成三部分:值为10的节点、根节点值为6的左子树,根节点值为14的右子树,

值为10的节点将和它的左子树的最大一个节点(8)连接起来,同时它还将和右子树最小的节点(12)连接起来。


按照中序遍历的特点,当遍历转换到根节点(10)时,它的左子树已经转换成一个排序的链表了,并且处在链表中的最后一个节点是8,把8和10连接起来,最后一个节点成为了10,接着我们遍历转换右子树,将10和12连接起来。

至于如何转换左右子树,用递归。

    #include <iostream> 
    using namespace std;  
      
    //二叉树结点定义  
    typedef struct BiTreeNode{  
        int data;  
        //左右孩子指针  
        struct BiTreeNode *lchild;  
        struct BiTreeNode *rchild;  
    }BiTreeNode,*BiTree;  
      
    //按先序序列创建二叉树  
    int CreateBiTree(BiTree &T)  
    {  
        int data;  
        //按先序次序输入二叉树中结点的值(一个字符),‘#’表示空树  
        cin>>data;  
        if(data == -1)  
        {  
            T = NULL;  
        }  
        else  
        {  
            T = (BiTree)malloc(sizeof(BiTreeNode));  
            T->data = data;//生成根结点         
            CreateBiTree(T->lchild);//构造左子树        
            CreateBiTree(T->rchild);//构造右子树  
        }  
        return 0;  
    }  

    void ConvertNode(BiTree pNode, BiTree * pLastNodeInList)
	{
		if(pNode == NULL)
			return;

		BiTree pCurrent = pNode;
		//进行左子树的遍历
		if (pCurrent->lchild != NULL)
			ConvertNode(pCurrent->lchild, pLastNodeInList);
		//做指针指向前面已经排好序的最后一个结点
		pCurrent->lchild = *pLastNodeInList;
		//如果最后一个结点不为空的话,那么就让排序的最后一个结点的右指针指向这棵树
		if(*pLastNodeInList != NULL)
			(*pLastNodeInList)->rchild = pCurrent;
		//此时这个结点也就加入了排好序的链表中了
		*pLastNodeInList = pCurrent;
		//最后进行右子树的遍历
		if (pCurrent->rchild != NULL)
			ConvertNode(pCurrent->rchild, pLastNodeInList);
	}

	BiTree Convert(BiTree pRootOfTree)
	{
		BiTree pLastNodeInList = NULL;
        ConvertNode(pRootOfTree, &pLastNodeInList);

        // pLastNodeInList指向双向链表的尾结点,
        // 我们需要返回头结点
        BiTree pHeadOfList = pLastNodeInList;
        while(pHeadOfList != NULL && pHeadOfList->lchild != NULL)
			pHeadOfList = pHeadOfList->lchild;

        return pHeadOfList;
	}
      
    //访问函数  
    void Visit(BiTree T)  
    {  
        if(T->data != -1)  
            cout<<T->data<<" ";  
    }  
      
    //先序遍历  
    void PreOrder(BiTree T)  
    {  
        if(T != NULL)  
        {  
            //访问根节点  
            Visit(T);  
            //访问左子结点  
            PreOrder(T->lchild);  
            //访问右子结点  
            PreOrder(T->rchild);  
        }  
    } 
    
	//输出双向链表
	void PrintList(BiTree pRoot)
	{
		BiTree pNode = pRoot;
		while(pNode != NULL)
		{
			cout<<pNode->data<<" ";
			pNode = pNode->rchild;
		}
		cout<<endl;
	}
      
    void main()  
    {  
        BiTree T;  
        CreateBiTree(T);  
          
        cout<<"原二叉树为:";  
        PreOrder(T);  
        cout<<endl;  
          
        BiTree listHead = Convert(T);
        cout<<"双向链表为:";  
        PrintList(listHead);
    }  


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值