美文网首页
二叉查找(排序)树的剑指Offer算法

二叉查找(排序)树的剑指Offer算法

作者: HungerDeng | 来源:发表于2018-10-10 17:30 被阅读0次

特性:

  • 如左子树不空,则左子树上所有结点均小于根结点的值
  • 如右子树不空,则右子树上所有结点均大于根结点的值
  • 左右子树也分别是二叉查找树

由上面3个特性可知:二叉查找树中结点的值不允许重复,它的中序遍历序列是有序的。

1. 判别二叉树T是否为二叉排序树

二叉排序树的类型BSTree定义如下:

typedef struct {
    KeyType key;  
    ... ...   // 其他数据域
} TElemType;
typedef struct BSTNode {
  TElemType  data;
  struct BSTNode  *lchild,*rchild;
}BSTNode, *BSTree;

根据二叉排序树特性,写出算法

// 若是二叉排序树,则返回TRUE,否则FALSE 
Status IsBSTree(BSTree T)
{
    if(T==NULL) return TRUE;
    
    //左子树,右子树,左孩子,右孩子
    Status bLeft,bRight,bChildL,bChildR;
    bLeft=bRight=bChildL=bChildR=FALSE;
    
    if(T->lchild==NULL || T->lchild->data.key<T->data.key){
        bChildL=TRUE;
    }

    if(T->rchild==NULL || T->rchild->data.key>T->data.key){
        bChildL=TRUE;
    }
    
    bLeft=IsBSTree(T->lchild);
    bRight=IsBSTree(T->rchild);
    
    return bLeft && bRight && bChildL && bChildR;
}

2. 递归算法,从大到小输出给定二叉排序树

二叉排序树的类型BSTree定义如下:

typedef struct {
    KeyType key;  
    ... ...   // 其他数据域
} TElemType;
typedef struct BSTNode {
  TElemType  data;
  struct BSTNode  *lchild,*rchild;
}BSTNode, *BSTree;

分析:因为二叉排序树的中序遍历是从小到大排列的,所以只需要中序排序逆过来就是从大到小排序的(右->根->左)

// 调用visit(T->data)输出 
void OrderOut(BSTree T, KeyType k, void(*visit)(TElemType))
{
     if(T==NULL) return;
     OrderOut(T->rchild,k,visit);
     visit(T->data);
     else return;
     OrderOut(T->lchild,k,visit);     
}

3. 输入一个整数数组,判断该数组是否是一棵二叉查找树的后序遍历序列

二叉排序树的定义如下:

class TreeNode {
    int value;
    TreeNode left;
    TreeNode right;
}

分析:

from: 玉刚说
由特性知:左子树结点< 根结点 < 右子树结点,所以后续遍历根结点肯定在最后
  1. 数组中最后一个元素10是根结点
  2. 10之前,比10小的元素都是10的左子树(3~8)
  3. 10之前,比10大的元素都是10的右子树(12~13)
  4. 左子树与5同理(右子树比较短,比较容易分析哈哈),一直递归遍历下去
  5. 右子树(12~13)中13排最后,那么13是根结点;12<13,是13的左子树;15>13是右子树

由分析可知:根结点之前的数组元素,分为两部分:连续的元素比根结点小是左子树,连续的元素比根结点大是右子树。
那么从array[0]开始往后遍历,当数组元素开始大于根结点时(array[x]大于根结点),可以把根结点(array[root])之前元素分为两部分:array[0] ~ array[x-1]为左子树,array[x]~array[root-1]为右子树,它们都必须大于array[root]。如果满足条件,证明:对于这个结点来说,它的左右子树是满足二叉查找树特性的。接下来就递归遍历左子树和右子树,当所有的非叶子结点都满足以上条件时,证明这个二叉树是二叉查找树。

算法:

boolean isPostOrderArrayOfBST(int[] array, int start, int end) {
    if (array == null || start < 0 || end > array.length || start >= end) {
        return false;
    }

    int root = array[end - 1];

    int i = start;
    for (; i < end - 1; i++) {
        if(array[i] > root) {
           break;
        }
    }

    int j = i; // j开始就是右子树了
    for (; j < end - 1; j++) {
        if (array[j] < root) {
            return false;
        }
    }

    boolean left = true;
    if (i > 0) {
        left = isPostOrderArrayBST(array, start, i);
    }

    boolean right = true;
    if (i < end - 1) {
        right = isPostOrderArrayBST(array, i, end - 1);
    }

    return left && right;
}

对于这道题目,如果改为判断是否为一棵二叉查找树的先序遍历序列,我们也可以用同样的思路去解,只不过如果是先序遍历序列,则数组的第一个元素为根节点的值,但后面的数组仍可分为两部分并分别代表左右子树。

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

二叉排序树的定义如下:

class TreeNode {
    int value;
    TreeNode left;
    TreeNode right;
}

该算法内容均来自 FutureFlyme 的CSDN 博客 ,全文地址请点击:
https://blog.csdn.net/FutureFlyme/article/details/69937007?utm_source=copy

分析:

1. 将左子树构成双链表,并返回该链表的头节点(左子树最左边的节点) 
2. 定位到左链表的最后一个节点(左子树最右边的节点)
3. 如果左子树链表不为空,则将当前root追加到左子树链表后
4. 将右子树构造成双向链表,并返回链表头结点(右子树最左边的节点)
5. 如果右子树链表不为空,将右子树链表追加到当前root后
6. 根据左子树链表是否为空返回的整体双向链表的头节点

4.1 递归实现

//Convert函数把一个二叉搜索树变成一个有序的双向链表,返回双向链表的头结点,参数root为二叉搜索树的根节点
public TreeNode Convert(TreeNode root){
    if(root==null){//假如根节点为空,返回空
        return null;
    }
    if(root.left==null&&root.right==null){//假如只有一个根节点,则返回根节点
        return root;
    }
    //1、将左子树构造成双链表,并返回该链表头结点left
    TreeNode left=Convert(root.left);

    //2、定位到左子树链表的最后一个节点(左子树最右边的节点)
    TreeNode p=left;//创建一个临时节点P,用来遍历找到左链表的最后一个节点(左子树最右边的节点),p初始化指向做左子树的根节点,
    while(p!=null&&p.right!=null){
        p=p.right;//最终p为左子树最右边的节点
    }
    //3、如果左子树链表不为空,将当前root追加到左子树链表后
    if(left!=null){//左子树链表不为空
        p.right=root;//左子树链表的最后一个节点p(左子树最右边节点)的右指针指向当前root节点
        root.left=p;//当前root节点的左指针指向左子树链表的最后一个节点p(左子树最右边节点)
    }
    //4、将右子树构造成双链表,并返回该链表的头结点right
    TreeNode right=Convert(root.right);

    //5、如果右子树链表不为空,将右子树链表追加到当前root后
    if(right!=null){//右子树链表不为空
        right.left=root;//右子树链表的头结点right的左指针指向当前root
        root.right=right;//当前root的右指针指向右子树链表的头结点right
    }
    return left!=null?left:root;//根据左子树链表是否为空返回整个双向链表的头指针。  
}

4.2 借助Stack,非递归实现

import java.util.Stack;
public TreeNode ConvertBSTToBiList(TreeNode root){
    if(root==null){
        return null;
    }
    Stack<TreeNode> stack=new Stack<TreeNode>();
    TreeNode p=root;//p为临时节点用来遍历树的节点,初始值为根节点root
    TreeNode rootList=null;//用于记录双向链表的头结点
    TreeNode pre=null;//用于保存中序遍历序列的上一个节点,即p的上一个节点
    boolean isFirst=true;//判断是否为左子树链表的第一个节点
    while(p!=null||!stack.isEmpty()){
        while(p!=null){
            stack.push(p);
            p=p.left;
        }
        p=stack.pop();//此时的p为左子树最左边的节点,
        if(isFirst){//假如是左子树链表的第一个节点
            rootList=p;//将p赋值给root节点
            pre=rootList;
            isFirst=false;
        }else{
            pre.right=p;
            p.left=pre;
            pre=p;
        }
        p=p.right;
    }
    return rootList;
}

5. 找出二叉查找树中第K大的值

二叉排序树的定义如下:

class TreeNode {
    int value;
    TreeNode left;
    TreeNode right;
}

分析:因为二叉排序树的中序遍历是从小到大排列的,所以只需要中序排序逆过来就是从大到小排序的(右->根->左)

算法如下:

public TreeNode findKthBigNode(TreeNode root ,int k){
       if(root==null) { return null;}
       if(root.right!=null){ findKthBigNode(root.right,k); }
       k--; //减一表示访问了这个点
       if(k==0) return root; //当k==0时,说明已经访问了k个点,剩余0个点。该Node为第k大
       if(root.right!=null){ findKthBigNode(root.left,k); }
}

6. 非递归往二叉排序树插入元素

/**********
【题目】试写一非递归算法,在二叉查找树T中插入元素e。
二叉查找树的类型BSTree定义如下:
typedef struct {
  KeyType key;  
    ... ...   // 其他数据域
} TElemType;
typedef struct BSTNode {
  TElemType data;
  struct BSTNode  *lchild,*rchild;
} BSTNode, *BSTree;
**********/
BSTree SearchInsertPosition(BSTree T, TElemType k)
{  
    BSTNode *pos, *p;
    p = T;
  
    while (p)
    {
        pos = p;
        if (p->data.key == k.key)
            return NULL;  
        p = (k.key < p->data.key) ? p->lchild : p->rchild;
    }  
  
    return pos;  
}

Status InsertBST_I(BSTree &T, TElemType k)
/* 在二叉查找树T中插入元素e的非递归算法 */
{
    BSTNode *new, *p;  
    new = (BSTNode*)malloc(sizeof(BSTNode));
    if (!new)
        return OVERFLOW;  
    new->data = k;
    new->lchild = new->rchild = NULL;
  
    if (!T)
        T = new;
    else
    {
        p = SearchInsertPosition(T, k);
        if (!p)
        {
            free(new);
            return FALSE;
        }
        if (k.key < p->data.key)
            p->lchild = new;
        else  
            p->rchild = new;
    }
    
    return TRUE; 
}

----------------------------------------------------------------------
/* 这个方法没实现功能
Status InsertBST_I(BSTree &T, TElemType k)
{
    BSTree p=T;
    while(1){        
        if(NULL==p){
            BSTree s;
            s=(BSTNode*)malloc(sizeof(BSTNode));
            if(NULL==s) return OVERFLOW;
            s->data=k; s->lchild=NULL; s->rchild=NULL;
            p=s;            
            return TRUE;            
        }
        if(k.key < p->data.key) {p=p->lchild ; continue;}
        else if(k.key > p->data.key) {p=p->rchild; continue;}
        else return FALSE;//k.key==p->data.key
    }        
} */

参考:据说能读懂这篇文章的都是聪明人!

相关文章

  • 二叉查找(排序)树的剑指Offer算法

    特性: 如左子树不空,则左子树上所有结点均小于根结点的值 如右子树不空,则右子树上所有结点均大于根结点的值 左右子...

  • 算法刷题总结

    参考资料:[1]. 二叉搜索树转化为排序的二叉链表(《剑指offer》27题)[2]. 快速排序的基本思想[3]....

  • 剑指Offer--(5)重建二叉树

    title: 剑指Offer--(5)重建二叉树 categories: 算法与数据结构 tags: 数据结构 题...

  • [刷题记录] 剑指 Offer 27. 二叉树的镜像

    2021.11.29算法笔记 剑指 Offer 27. 二叉树的镜像 请完成一个函数,输入一个二叉树,该函数输出它...

  • 剑指offer第二版-排序算法

    本系列导航:剑指offer(第二版)java实现导航帖 查找和排序是经常用到的基本算法。查找相对而言较简单,不外乎...

  • 复习准备知识点

    先上路线图 (来自LeetCode)路线图.jpg 排序算法排序算法.png 规划 <剑指offer> LeetC...

  • Binary Search Tree | 二叉查找树

    参考书:胡凡、曾磊《算法笔记》 二叉查找树BST 又称为排序二叉树、二叉搜索树、二叉排序树 BST 是数据域有序的...

  • 算法

    1.算法 链表 二叉树 排序 查找 递归、迭代 位操作 概率 排列组合 1.1 链表 1.1 二叉树 1.3 排序...

  • Schedule

    WeekComputer Science算法图解剑指offer神经网络1Data Manipulation选择排序...

  • 查找

    静态查找顺序查找 折半查找 散列查找 动态查找二叉排序树 散列查找 ASL(平均查找长度) - 衡量查找算法效率的...

网友评论

      本文标题:二叉查找(排序)树的剑指Offer算法

      本文链接:https://www.haomeiwen.com/subject/aafmoftx.html