(1.2.5.4.1)二叉排序树的相关算法

二叉搜索树的后序遍历序列的验证

题目:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则返回true,否则返回false。假设输入的数组的任意两个数字都互不相同。

例如输入数组{5,7,6,9,11,10,8}则返回true,因为这个整数序列是下图二叉树的后序遍历的结果。如果输入的数组是{7,4,6,5},由于没有哪颗二叉搜索树的后续遍历的结果是这个序列,因此返回false。


在后序遍历得到的序列中,最后一个数字是树的根节点的值。数组中前面的数字可以分为两部分:第一部分是左子树结点的值,它们都比根节点的值小;第二部分是右子树结点的值,他们都比根节点的值大。

以数组{5,7,6,9,11,10,8}为例,后序遍历结果的最后一个数字8就是根节点的值。在这个数组中,前3个数字5,7和6都比8小,是值为8的结点的左子树结点;后3个数字9,11和10都比8 大,是值为8的结点的右子树结点。

我们接下来用同样的方法确定与数组每一部分对应的子树的结构。这其实就是一个递归的过程。对于序列5,7,6,最后一个数字6是左子树的根节点的值。数字5比6小,是值为6的结点的左子结点,而7则是它的右子节点。同样,在序列9,11,10中,最后一个数字10是右子树的根节点,数字9比10小,是值为10的结点的左子结点,而11则是它的右子节点。

我们再来分析一下另一个数组{7,4,6,5}。后序遍历的最后一个树是根节点,因此根节点的值是5.由于第一个数字7比5大,因此对应的二叉搜索树中,根节点上是没有左子树的,数字7,4,和6都是右子树结点的值。但我们发现在右子树中有一个结点的值是4,比根节点的值5小,这违背了二叉搜索树的定义。因此不存在一颗二叉搜索树,它的后序遍历的结果是7,4,6,5.

<span style="color:#555555;">
int JudegeBST(int arr[],int begin,int end)
{
    int i,result;

    if(begin >= end)
        return 1;

</span><span style="color:#ff0000;">    for(i = begin;i < end;++i){ //寻找到第一个大于“根节点”的点
        if(arr[i] > arr[end])
            break;
    }</span><span style="color:#555555;">
</span><span style="color:#ff6600;">    for(int j = i;j < end;++j){     //判断后面的数据是否都大于“根节点”,如果不是,就返回0,表示不能构建二叉搜索树
        if(arr[j] < arr[end])
            return 0;
    }</span><span style="color:#555555;">

  </span><span style="color:#ff0000;">  result = JudegeBST(arr,begin,i-1);
    if(!result)
        return 0;
    result = JudegeBST(arr,i,end-1);
    if(!result)
        return 0;</span><span style="color:#555555;">
    return 1;
}
</span>



二叉搜索树与双向链表的转换

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

比如如下图中的二叉搜索树,则输出转换之后的排序双向链表为:


在二叉树中,每个结点都有两个指向子节点的指针。在双向链表中,每个结点也有两个指针,他们分别指向前一个结点和后一个结点。由于这两种结点的结构相似,同时二叉搜索树也是一种排序的数据结构,因此在理论上有可能实现二叉搜索树和排序的双向链表的转换。在搜索二叉树中,左子结点的值总是小于父节点的值,右子节点的值总是大于父节点的值。因此我们在转换称排序的双向链表时,原先指向的左子结点的指针调整为链表中指向前一个结点的指针,原先指向右子节点的指针调整为俩表为指向后一个结点的指针。接下来我们考虑如何转化。

由于要求转换之后的链表是排好序的,我们可疑中序遍历树中的每一个结点,这是因为中序遍历算法的特点是按照从小到达的顺序遍历二叉树的每一个结点。当遍历到根节点的时候,我们把树堪称三部分:值为10的结点,根节点为6的左子树、根节点为14的右子树。根据排序链表的定义,值为10的结点将和它的左子树的最大的一个结点(即值为8的结点)链接起来,同时它还将和右子树最小的结点(即值为12的结点)链接起来,如图:


按照中序遍历的顺序,当我们遍历转换到根节点(值为10的结点)时,它的左子树已经转换成一个排序的链表了,并且处在链表中的最后一个结点是当前值的最大的结点。我们把值为8的结点根节点链接起来,此时链表中的最后一个结点是10了。接着我们去遍历转换右子树,并把根节点和右子树最小的结点链接起来。至于怎么去转换它的左子树和右子树,由于遍历和转换过程是一样的,我们自然的想到了递归。

思路:

假设已经处理了一部分(转换了左子树),则得到一个有序的双向链表,现在则需要将根结点和链表的尾结点链接,然后再转换右子树。

这样分为三步:

1.转换左子树;

2.链接根节点。设置根节点的左指针、尾结点的右指针。更新尾结点。

3.转换右子树。

代码:

复制代码
/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};*/
class Solution {
public:
    TreeNode* Convert(TreeNode* pRootOfTree)
    {
        if(pRootOfTree==NULL)  return NULL;
        
        TreeNode *pLastNodeInList=NULL;
        ConvertNode(pRootOfTree,pLastNodeInList);
        
        TreeNode *pHead=pLastNodeInList;//找到头结点
        while(pHead!=NULL && pHead->left!=NULL)
            pHead=pHead->left;
        
        return pHead;
    }
private:
    void ConvertNode(TreeNode *pCurrent, TreeNode* &pLastNodeInList)
    {
        if(pCurrent==NULL)  return ;
        
        if(pCurrent->left!=NULL)//转换左子树
            ConvertNode(pCurrent->left,pLastNodeInList);
        
        pCurrent->left=pLastNodeInList;//链接根结点  设置根节点的左指针、尾结点的右指针
        if(pLastNodeInList!=NULL)
        {
            pLastNodeInList->right=pCurrent;
        }
        
        pLastNodeInList=pCurrent;//更新尾结点
        
        ConvertNode(pCurrent->right,pLastNodeInList);//转换右子树
    }
};
复制代码

 



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值