广告
返回顶部
首页 > 资讯 > 后端开发 > Python >Java实现Treap树的示例代码
  • 648
分享到

Java实现Treap树的示例代码

2024-04-02 19:04:59 648人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

目录Treap树数据结构遍历查询增加删除完整代码Treap树 Treap树是平衡二叉搜索树的一种实现方式,但它不是完全平衡的。平衡二叉搜索树的实现方式还有AVL树、红黑树、替罪羊树、

Treap树

Treap树是平衡二叉搜索树的一种实现方式,但它不是完全平衡的。平衡二叉搜索树的实现方式还有AVL树、红黑树、替罪羊树、伸展树

数据结构

Treap树的节点除了有二叉搜索树的必须有的值,还有一个随机生成的优先级priority,供构造小顶堆使用,小顶堆的特性就是父节点、左右子结点中永远是父节点的优先级最小,最多和子结点的相等。而大顶堆则是父节点的最大。堆中左右子结点的优先级并没有特定要求

class Treenode {
    int value;
    int priority;
    TreeNode left;
    TreeNode right;

    public TreeNode(int value, int priority) {
        this.value = value;
        this.priority = priority;
    }
}

遍历

Treap树虽然是不完全平衡树,但是其完全满足二叉搜索树的特征,即中序遍历得到的是有序数组

public void printTree(TreeNode root) {
   if (root != null) {
        printTree(root.left);
        System.out.println(root.value);
        printTree(root.right);
    }
}  

查询

Treap树满足二叉搜索树的特征,则直接根据其特征查询

// 查询
// 根据二叉搜索树性质查询
public TreeNode query(TreeNode root, int value) {
    //这里的root才是真root,上面的方法只是局部变量
    //所以不能在查询中改变根节点
    TreeNode temp = root;
    while (temp != null) {
        if (temp.value > value) {
            temp = temp.left;
        } else if (temp.value < value) {
            temp = temp.right;
        } else {
            return temp;
        }
    }
    return null;
}

增加

步骤

  • 按照二叉搜索树的插入方式,将节点插入到叶子节点,如果在查找的过程找到要插入的值,则不会进行插入,具有去重效果
  • 插入节点后,根据随机生成的priority优先级,按照小顶堆,即priority较小的成为父节点,来进行左旋右旋
//增加
//  1.按照二叉查找树的插入方式,将节点插入到树叶中
//  2.再根据priority优先级的小顶堆性质进行左旋右旋
public TreeNode insert(int value, TreeNode root) {
     // 如果父节点为空,则创建一个父节点并返回
     // 第一次父节点为根节点
     if (root == null) {
         return new TreeNode(value, random.nextInt());
     }

     // 如果要根节点的值大于要插入结点的值,则应该插入到根节点的左边
     if (root.value > value) {
         // 递归进行插入,一直递归到叶子节点才会插入
         // 如果递归到一个相等的节点,则不会创建一个新节点,会直接返回
         root.left = insert(value, root.left);

         // 插入完成后,根据堆的优先级进行旋转操作
         // 左子结点的优先级值小于根结点的优先级,
         // 根据小顶堆的规则,需要进行右旋操作
         if (root.left.priority < root.priority) {
             // 传入root根结点,返回的是左子结点,
             // 但此时左子结点已经旋转成为根结点所以赋值给根结点
             root = rightRotate(root);
         }
     }
     // 如果根节点的值小于要插入结点的值大于,则应该插入到根节点的右边
     else if (root.value < value) {
         // 递归插入
         root.right = insert(value, root.right);
         // 右子结点的优先级值小于根结点的优先级,
         // 根据小顶堆的规则,需要进行左旋操作
         if (root.right.priority < root.priority) {
             root = leftRotate(root);
         }
     }
     // 如果已经有该值,则无须插入,什么都不动
     else {

     }
     // 返回根结点
     return root;
 }

删除

步骤

  • 按照二叉搜索树的特点,先找到对应的节点
  • 若该结点为叶子结点,则直接删除,若该结点为非叶子节点, 则进行相应的旋转,直到该结点为叶子节点,然后进行删除
 //删除、
//     1.根据二叉搜索树的性质找到相应的结点
//     2.若该结点为叶子结点,则直接删除,若该结点为非叶子节点,
//       则进行相应的旋转,直到该结点为叶子节点,然后进行删除。
public TreeNode delete(int value, TreeNode root) {
    // 当树不为空才进行删除
    if (root != null) {
        // 先进行查找
        // 往左找
        if (root.value > value) {
            // 因为可能找到了后会进行左旋右旋,
            // 所以其实左子结点会改变
            root.left = delete(value, root.left);
        }
        // 往右找
        else if (root.value < value) {
            root.right = delete(value, root.right);
        }
        //找到了
        else {
            // 首先找到这里,root已经变为目标结点,如果root是叶子结点删去即可
            if (root.left == null && root.right == null) {
                // 返回当前节点,即删除后的样子 null
                // 会递归到其父节点的root.right = delete(value, root.right);
                // 即指向了root.right = null 或 root.left = null,即删除了我们要删除的节点
                return null;
            } else if (root.left != null && root.right != null) {
                // 如果root左右子结点健在
                // 此时就是想把目标结点旋转到底层去,
                // 然后需要选择一个优先级值比较小的结点放在目标结点位置
                // 如果左子结点优先级较小
                if (root.left.priority < root.right. priority) {
                    // 旋转root已经变为左子结点,原来的根结点变为右子节点
                    root = rightRotate(root);
                    // 去找那被换下去的节点,将它删除掉
                    root.right = delete(value, root.right);
                } else {
                    root = leftRotate(root);
                    // 去找那被换下去的节点,将它删除掉
                    root.left = delete(value, root.left);
                }
            }
           else if (root.left != null) {
                // 没有右子节点,只能右旋了
                root = rightRotate(root);
                // 去找那被换下去的节点,将它删除掉
                root.right = delete(value, root.right);
            }

            else if (root.right != null) {
                // 没有左子节点,只能左旋了
                root = leftRotate(root);
                // 去找那被换下去的节点,将它删除掉
                root.left = delete(value, root.left);
            }
        }
    }

    return root;
}

完整代码

public class Treap {
    // 优先级随机数发生器
    private static final Random random = new Random();

    //增加
//  1.按照二叉查找树的插入方式,将节点插入到树叶中
//  2.再根据priority优先级的小顶堆性质进行左旋右旋
    public TreeNode insert(int value, TreeNode root) {
        // 如果父节点为空,则创建一个父节点并返回
        // 第一次父节点为根节点
        if (root == null) {
            return new TreeNode(value, random.nextInt());
        }

        // 如果要根节点的值大于要插入结点的值,则应该插入到根节点的左边
        if (root.value > value) {
            // 递归进行插入,一直递归到叶子节点才会插入
            // 如果递归到一个相等的节点,则不会创建一个新节点,会直接返回
            root.left = insert(value, root.left);

            // 插入完成后,根据堆的优先级进行旋转操作
            // 左子结点的优先级值小于根结点的优先级,
            // 根据小顶堆的规则,需要进行右旋操作
            if (root.left.priority < root.priority) {
                // 传入root根结点,返回的是左子结点,
                // 但此时左子结点已经旋转成为根结点所以赋值给根结点
                root = rightRotate(root);
            }
        }
        // 如果根节点的值小于要插入结点的值大于,则应该插入到根节点的右边
        else if (root.value < value) {
            // 递归插入
            root.right = insert(value, root.right);
            // 右子结点的优先级值小于根结点的优先级,
            // 根据小顶堆的规则,需要进行左旋操作
            if (root.right.priority < root.priority) {
                root = leftRotate(root);
            }
        }
        // 如果已经有该值,则无须插入,什么都不动
        else {

        }
        // 返回根结点
        return root;
    }

    //删除、
//     1.根据二叉搜索树的性质找到相应的结点
//     2.若该结点为叶子结点,则直接删除,若该结点为非叶子节点,
//       则进行相应的旋转,直到该结点为叶子节点,然后进行删除。
    public TreeNode delete(int value, TreeNode root) {
        // 当树不为空才进行删除
        if (root != null) {
            // 先进行查找
            // 往左找
            if (root.value > value) {
                // 因为可能找到了后会进行左旋右旋,
                // 所以其实左子结点会改变
                root.left = delete(value, root.left);
            }
            // 往右找
            else if (root.value < value) {
                root.right = delete(value, root.right);
            }
            //找到了
            else {
                // 首先找到这里,root已经变为目标结点,如果root是叶子结点删去即可
                if (root.left == null && root.right == null) {
                    // 返回当前节点,即删除后的样子 null
                    // 会递归到其父节点的root.right = delete(value, root.right);
                    // 即指向了root.right = null 或 root.left = null,即删除了我们要删除的节点
                    return null;
                } else if (root.left != null && root.right != null) {
                    // 如果root左右子结点健在
                    // 此时就是想把目标结点旋转到底层去,
                    // 然后需要选择一个优先级值比较小的结点放在目标结点位置
                    // 如果左子结点优先级较小
                    if (root.left.priority < root.right. priority) {
                        // 旋转root已经变为左子结点,原来的根结点变为右子节点
                        root = rightRotate(root);
                        // 去找那被换下去的节点,将它删除掉
                        root.right = delete(value, root.right);
                    } else {
                        root = leftRotate(root);
                        // 去找那被换下去的节点,将它删除掉
                        root.left = delete(value, root.left);
                    }
                }
               else if (root.left != null) {
                    // 没有右子节点,只能右旋了
                    root = rightRotate(root);
                    // 去找那被换下去的节点,将它删除掉
                    root.right = delete(value, root.right);
                }

                else if (root.right != null) {
                    // 没有左子节点,只能左旋了
                    root = leftRotate(root);
                    // 去找那被换下去的节点,将它删除掉
                    root.left = delete(value, root.left);
                }
            }
        }

        return root;
    }

    // 查询
    // 根据二叉搜索树性质查询
    public TreeNode query(TreeNode root, int value) {
        //这里的root才是真root,上面的方法只是局部变量
        //所以不能在查询中改变根节点
        TreeNode temp = root;
        while (temp != null) {
            if (temp.value > value) {
                temp = temp.left;
            } else if (temp.value < value) {
                temp = temp.right;
            } else {
                return temp;
            }
        }
        return null;
    }

    // 右旋,左子节点右旋
    public TreeNode rightRotate(TreeNode treeNode) {
        // temp为左子结点
        TreeNode temp = treeNode.left;
        //将父结点的左边指向 temp的右子结点
        treeNode.left = temp.right;
        // 将temp结点的右边指向父结点
        temp.right = treeNode;
        // 进行上面两步操作,在纸上画一下就找到其右旋成功了,
        // 即左子结点变为根结点了

        // 返回此时旋转后的真正根结点
        return temp;
    }

    // 左旋,右子结点左旋
    public TreeNode leftRotate(TreeNode treeNode) {
        // temp为右子结点
        TreeNode temp = treeNode.right;
        //将父结点的右边指向 temp的左子结点
        treeNode.right = temp.left;
        // 将temp结点的左边指向父结点
        temp.left = treeNode;
        // 进行上面两步操作,在纸上画一下就找到其左旋成功了,
        // 即右子结点变为根结点了

        // 返回此时旋转后的真正根结点
        return temp;
    }

    public void printTree(TreeNode root) {
        if (root != null) {
            printTree(root.left);
            System.out.println(root.value);
            printTree(root.right);
        }
    }

    public static void main(String[] args) {
        Treap treap = new Treap();
        TreeNode root = null;
        root = treap.insert(1, root);
        root = treap.insert(2, root);
        root = treap.insert(3, root);
        root = treap.insert(4, root);
        root = treap.insert(5, root);
        root = treap.insert(6, root);

        //中序遍历,如果打印的值由小到大,说明满足二叉搜索树特征
        treap.printTree(root);

        System.out.println();

        // 测试查询
        TreeNode query = treap.query(root, 1);
        System.out.println(query.value);
        query = treap.query(root, 2);
        System.out.println(query.value);
        query = treap.query(root, 3);
        System.out.println(query.value);
        query = treap.query(root, 4);
        System.out.println(query.value);
        query = treap.query(root, 5);
        System.out.println(query.value);
        query = treap.query(root, 6);
        System.out.println(query.value);
        query = treap.query(root, 7);
        System.out.println(query);

        System.out.println();
        // 测试删除
        root = treap.delete(2,root);
        root = treap.delete(3,root);
        root = treap.delete(5,root);
        root = treap.delete(7,root);
        treap.printTree(root);

    }
}


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

    public TreeNode(int value, int priority) {
        this.value = value;
        this.priority = priority;
    }
}

到此这篇关于Java实现Treap树的示例代码的文章就介绍到这了,更多相关Java Treap树内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Java实现Treap树的示例代码

本文链接: https://www.lsjlt.com/news/152927.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Java实现Treap树的示例代码
    目录Treap树数据结构遍历查询增加删除完整代码Treap树 Treap树是平衡二叉搜索树的一种实现方式,但它不是完全平衡的。平衡二叉搜索树的实现方式还有AVL树、红黑树、替罪羊树、...
    99+
    2022-11-13
  • Java实现树形结构的示例代码
    目录前言数据库表结构实现思路具体代码1、造数据,和数据库表数据一致2、树型结构实体类前言 由于业务需要,后端需要返回一个树型结构给前端,包含父子节点的数据已经在数据库中存储好,现在需...
    99+
    2022-11-13
  • java 实现简单圣诞树的示例代码
    以下是一个简单的Java代码示例,实现了一个简单的圣诞树的打印功能:```javapublic class ChristmasTre...
    99+
    2023-09-16
    java
  • Java实现二分搜索树的示例代码
    目录1.概念2.重点操作3.完整代码1.概念 a.是个二叉树(每个节点最多有两个子节点) b.对于这棵树中的节点的节点值 左子树中的所有节点值 < 根节点 < 右子树的所...
    99+
    2022-11-13
  • java实现简单圣诞树的示例代码
    以下是一个简单的Java示例代码,实现了一个基本的圣诞树打印功能:```javapublic class ChristmasTree...
    99+
    2023-09-17
    Java
  • Java实现二叉树的示例代码(递归&迭代)
    目录1.二叉树基本概念见上节:详解Java中二叉树的基础概念(递归&迭代) 2.本次展示链式存储 以此图为例,完整代码如下: //基础二叉树实现 //使用左右孩子表示法 ...
    99+
    2022-11-13
  • Java中树的存储结构实现示例代码
    一、树树与线性表、栈、队列等线性结构不同,树是一种非线性结构。一棵树只有一个根节点,如果一棵树有了多个根节点,那它已经不再是一棵树了,而是多棵树的集合,也被称为森林。二、树的父节点表示法树中除根节点之外每个节点都有一个父节点,为了记录树中节...
    99+
    2023-05-31
    java 存储结构
  • java实现双层圣诞树加修饰代码示例
    A:有咋样的实力可以写出这个代码? B:会for循环就好 A:只要会for就好? B:还有一点点逻辑能力和算法 package 海绵hong; import java.util....
    99+
    2022-11-12
  • C++实现二叉树及堆的示例代码
    1 树 树是一种非线性数据结构,它是由n个有限结点组成的具有层次关系的集合。把它叫树是因为它是根朝上,叶子朝下的 来上图瞧瞧 1.1 树的相关名词 2 二叉树 2.1 二叉树的...
    99+
    2022-11-12
  • Java实现树形List与扁平List互转的示例代码
    目录存储树的表结构扁平List转树形List双层for递归转换为Map栈树形List转扁平List递归栈背景:在平时的开发中,我们时常会遇到下列场景 公司的组织架构的数据存储与展示文...
    99+
    2023-05-19
    Java 树形List Java 扁平List Java树形List 扁平List互转
  • Java实现生成Excel树形表头完整代码示例
    本文主要分享了Java实现生成Excel树形表头完整代码示例,没有什么好解释的,直接看看代码过程。源数据格式:String[] targetNames = { "指标名称", "单位", ...
    99+
    2023-05-30
    java excel表头 ava
  • java栈实现二叉树的非递归遍历的示例代码
    一般来说遍历二叉树用到递归,但是用Stack进行遍历也是一个不错的方法。 二叉树设置 class Node{ public int val; public Node left...
    99+
    2022-11-11
  • 基于Vue实现树形穿梭框的示例代码
    Vue 项目里面需要一个树形的穿梭框,但是 elementUI 和 ant-d 组件库的穿梭框组件效果都不是很好,因为源列表和目标列表都是需要树形结构的,所以说这个就很难搞,但是也不...
    99+
    2022-11-13
  • SpringBoot mybatis 实现多级树形菜单的示例代码
    一、前言 iview-admin中提供了 v-org-tree 这么一个vue组件可以实现树形菜单,下面小编来提供一下在element-ui中的使用教程(项目见:https://gi...
    99+
    2022-11-12
  • C语言实现手写红黑树的示例代码
    目录前沿红黑树代码测试前沿 写C的红黑树前建议先看我博客这篇文章Java-红黑树 主要看原理 红黑树代码 #ifndef STUDY_RBTREE_H #define ...
    99+
    2022-11-13
  • Python实现二叉排序树与平衡二叉树的示例代码
    目录前言1. 二叉排序树1.1 构建一棵二叉排序树1.2 二叉排序树的数据结构1.3 实现二叉排序树类中的方法:2. 平衡二叉排序树2.1 二叉平衡排序树的数据结构3. 总结前言 什...
    99+
    2022-11-10
  • python实现决策树分类算法代码示例
    目录前置信息1、决策树2、样本数据策树分类算法1、构建数据集2、数据集信息熵3、信息增益4、构造决策树5、实例化构造决策树6、测试样本分类后置信息:绘制决策树代码总结前置信息 1、决...
    99+
    2022-11-11
  • Java代码实现循环队列的示例代码
    循环队列结构 队列特点 队列为一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受...
    99+
    2022-11-12
  • Python实现绘制圣诞树和烟花的示例代码
    目录序言圣诞树效果展示代码展示圣诞树上加烟花效果展示代码展示序言 这不是圣诞节快到了,准备让让女朋友开心开心,也算是亲手做的,稍稍花了点心思。 话不多说,咱们直接来展示吧,学会了赶紧...
    99+
    2022-12-08
    Python圣诞树 烟花 Python圣诞树 Python烟花
  • vue实现树形结构增删改查的示例代码
    其实很多公司都会有类似于用户权限树的增删改查功能,正好最近我刚写了一个树形结构的增删改,在这里和大家分享一下,如果有不合理的地方欢迎评论,我会尽快优化~~ 先附上一下效果图 这个是没...
    99+
    2022-11-12
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作