二叉搜索树转化为双向链表

题意:给定一棵二叉搜索树,将该二叉搜索树转化为一个排序的双向链表,要求只能调整树中节点指针的指向

分析:对二叉搜索树进行中序遍历,得到的序列就是有序的,如果在中序遍历的同时改变指针的指向,当中序遍历完成之后,就可以得到一个有序的双向链表。

            按照上面的分析,将一棵二叉搜索树分为三部分,根节点(root),左子树(lchild),右子树(rchild),根据所需链表的需求,root节点应该跟lchild中节点最大的值相连,同时root节点还需要跟rchild中节点最小的值相连。当root节点跟lchild中节点的最大值相连时,lchild已被转化为一个有序的双向链表,然后再将root节点跟lchild连接起来,此时新的有序链表的长度就增加1了,之后再去遍历转换rchild,再将root节点和rchild中的最小值节点连接起来,对lchild、rchild的转换采用递归的方法。

核心:由于所采用的是中序遍历的方式,即采用下面的这种模式

void InOrder(BiTree pNode)
{
    if(NULL == pNode)
        return;

    InOrder(pNode->lchild);
    //.....processing
    InOrder(pNode->rchild);
}

那么processing这部分应该怎么处理,从上面的分析可知这一步用来将root节点跟已经得到的有序双向链表连接起来,即有序双向链表的最后一个节点和root连接要互联,之后root节点就成为了有序双向链表的最后一个节点,然后在继续递归处理。

二叉树的定义参加二叉树的定义

具体的实现参见下面的代码:

#include "Binary.h"
void BiTreeToDLinkList(BiTree pRoot, BiTree *pLastNodeInList)
{
    if(NULL == pRoot)
        return;

    //递归左子树
    if(pRoot->lchild)
        BiTreeToDLinkList(pRoot->lchild, pLastNodeInList);

    //假设左子树已递归完成,左子树此时已是一个双向链表,*pLastNodeInList指向链表的最后一个节点,现在就需要完成当前节点和链接最后一个节点的链接工作,即pRoot与*pLastNodeInList的链接,在链接完成后不要忘记改当前链表的最后一个节点
    pRoot->lchild = (*pLastNodeInList);
    if((*pLastNodeInList) != NULL)
        (*pLastNodeInList)->rchild = pRoot;
    (*pLastNodeInList) = pRoot;

    //递归右子树
    if(pRoot->rchild)
        BiTreeToDLinkList(pRoot->rchild, pLastNodeInList);
}

void ConvertTreeToLinkList(BiTree *pRoot)
{
    if(NULL == *pRoot)
        return;

    BiTree pLastNodeInList = NULL;
    BiTreeToDLinkList(*pRoot, &pLastNodeInList);
    //完成转换之后得到的是链表的最后一个节点,现在通过最后一个节点,得到链表的头节点
    (*pRoot) = pLastNodeInList;
    while((*pRoot)->lchild != NULL)
    {
        *pRoot = (*pRoot)->lchild;
    }
}
void PrintDLinkList(BiTree pRoot)
{
    if(NULL == pRoot)
    {
        cout << "根节点为空,请输入有效数据" << endl;
        return;
    }

    BiTree p = pRoot;
    cout << "The nodes from left to right are:" << endl;
    while(p)
    {
        cout << p->data << "\t";
        if(NULL == p->rchild)
            break;
        p = p->rchild;
    }
    cout << endl;
    //上面的循环跳出时,p指向链表的最后一个节点
    cout << "The nodes from right to left are:" << endl;
    while(p)
    {
        cout << p->data << "\t";
        if(NULL == p->lchild)
            break;
        p = p->lchild;
    }
    cout << endl;
}

void Test(BiTree pRoot)
{
    ConvertTreeToLinkList(&pRoot);
    PrintDLinkList(pRoot);
}
void Test1()
{
    BiTree pNode10 = NULL;
    CreateBinaryTreeNode(&pNode10,10);
    BiTree pNode6 = NULL;
    CreateBinaryTreeNode(&pNode6,6);
    BiTree pNode14 = NULL;
    CreateBinaryTreeNode(&pNode14,14);
    BiTree pNode4 = NULL;
    CreateBinaryTreeNode(&pNode4,4);
    BiTree pNode8 = NULL;
    CreateBinaryTreeNode(&pNode8,8);
    BiTree pNode12 = NULL;
    CreateBinaryTreeNode(&pNode12,12);
    BiTree pNode16 = NULL;
    CreateBinaryTreeNode(&pNode16,16);

    ConnectTreeNodes(pNode10, pNode6, pNode14);
    ConnectTreeNodes(pNode6, pNode4, pNode8);
    ConnectTreeNodes(pNode14, pNode12, pNode16);

    Test(pNode10);
}
int main()
{
    Test1();
    return 0;
}


   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值