`
543089122
  • 浏览: 153259 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

简单_随机平衡二叉树(Treap)

阅读更多
我们可以看到,如果一个二叉排序树节点插入的顺序是随机的,这样我们得到的二叉排序树大多数情况下是平衡的,即使存在一些极端情况,但是这种情况发生的概率很小,所以我们可以这样建立一颗二叉排序树,而不必要像AVL那样旋转,可以证明随机顺序建立的二叉排序树在期望高度是,但是某些时候我们并不能得知所有的带插入节点,打乱以后再插入。所以我们需要一种规则来实现这种想法,并且不必要所有节点。也就是说节点是顺序输入的,我们实现这一点可以用Treap。
  Treap=Tree+Heap
  Treap是一棵二叉排序树,它的左子树和右子树分别是一个Treap,和一般的二叉排序树不同的是,Treap纪录一个额外的数据,就是优先级。Treap在以关键码构成二叉排序树的同时,还满足堆的性质(在这里我们假设节点的优先级大于该节点的孩子的优先级)。但是这里要注意的是Treap和二叉堆有一点不同,就是二叉堆必须是完全二叉树,而Treap可以并不一定是。
貌似TreapDB用的就是Treap算法实现的,当然肯定还有其他的数据结构进行了混搭。



package sunfa.tree;

import java.util.Comparator;
import java.util.Random;

/**
 * 随机平衡二叉树Treap=Tree+heap,Tree取前3个单词,heap取后2个单词
 * 
 * 其实这棵树还是比较好理解的,与普通的BST相比节点多了个随机数,普通BST的旋转是以插入的key的大小为评判标准的,<br>
 * 而Treap是以节点的随机数的大小作为评判标准的。为什么要给节点弄个随机数呢?因为普通的BST之所以会退化为线性表<br>
 * 主要原因是顺序插入造成的。
 * 
 * @param <K>
 * @param <V>
 */
public class Treap<K, V> {

	public static void main(String[] args) {
		Treap<Integer, Integer> tree = new Treap<Integer, Integer>(
				new Comparator<Integer>() {
					public int compare(Integer o1, Integer o2) {
						return o1 - o2;
					}
				});
		//测试200W条数据插入Treap树  时间是1600毫秒左右,树的深度:50
		long start = System.currentTimeMillis();
		for (int i = 0; i < tree.n; i++) {
			tree.put(i, i);
		}
		System.out.println(System.currentTimeMillis()-start);
		System.out.println("h:" + tree.h());
//		tree.printTree(tree.root);
	}

	Comparator<K> comp;

	public Treap(Comparator<K> c) {
		this.comp = c;
	}

	private Entry<K, V> root;
	private Random ran = new Random();
	private int n = 2000000;

	private void printTree(Entry<K, V> node) {
		if (node == null)
			return;
		System.out.print("[" + node.key + "=" + node.fix + "],");
		printTree(node.left);
		printTree(node.right);
	}

	public void put(K key, V value) {
		put0(null, root, key, value, 2);
	}
	/**
	 * 插入的方式和SBT类似
	 * @param p  根节点
	 * @param node   插入节点
	 * @param key
	 * @param value
	 * @param i
	 */
	private void put0(Entry<K, V> p, Entry<K, V> node, K key, V value, int i) {
		if (key == null)
			throw new NullPointerException();
		if (node == null) {
			node = new Entry<K, V>(p, null, null, key, value, ran.nextInt(n));
			if (null == this.root)
				this.root = node;
			if (i == 0)
				p.left = node;
			else if (i == 1)
				p.right = node;
			return;
		}
		int c = compare(key, node.key);
		if (c < 0) {
			put0(node, node.left, key, value, 0);
			if (node.left.fix < node.fix)
				// 之所以递归put0里面进行旋转也是为了压缩路径,改成非递归的形式就起不到路径压缩了,和SBT树的插入算法类似
				rightRotate(node);
		} else {
			put0(node, node.right, key, value, 1);
			if (node.right.fix < node.fix)
				leftRotate(node);
		}
	}

	/**
	 * Treap的查找和普通的BST的查找一样,并且不会改变Treap的结构
	 * @param key
	 * @return
	 */
	public V get(K key) {
		Entry<K, V> entry = getEntry(key);
		return entry==null?null:entry.value;
	}
	private Entry<K, V> getEntry(K key){
		if (key == null)
			return null;
		Entry<K, V> t = root;
		while (true) {
			int c = compare(key, t.key);
			if (c == 0) {
				return t;
			} else if (c < 0) {
				if (t.left != null)
					t = t.left;
				else
					return null;
			} else {
				if (t.right != null)
					t = t.right;
				else
					return null;
			}
		}
	}
	private int compare(K k1, K k2) {
		return this.comp != null ? (((comp).compare(k1, k2)))
				: (((Comparable<K>) k1).compareTo(k2));
	}

//	public V remove(K key){
//		Entry<K, V> entry = getEntry(key);
//		if(entry==null)
//			return null;
//		
//	}
	private void delete0(Entry<K, V> p,K key){
		int c = compare(key, p.key);
		if(c==0){
			if(p.left==null || p.right==null){
				Entry<K, V> t = p;
				if(p.right==null){
					p = p.left;
				}else{
					p = p.right;
				}
				
			}
		}
	}
	private void leftRotate(Entry<K, V> x) {
		// ①
		Entry<K, V> y = x.right;// 分离出旋转元素的右子节点
		// ②
		x.right = y.left;// 旋转元素的右子节点的左子节点挂接到旋转元素的右子节点处
		if (y.left != null) {
			y.left.parent = x;//
		}
		// ③
		y.parent = x.parent;// 分离出来的部分挂接到旋转元素的父节点下
		if (x.parent == null) {// 如果旋转元素为根节点,就让旋转元素成为根
			this.root = y;
		} else if (x == x.parent.left) {// 如果旋转元素是它父节点的左子节点,让旋转元素父节点的左指针指向分离出的节点
			x.parent.left = y;
		} else {// 如果是右子节点,就用父节点的右指针指向分离节点
			x.parent.right = y;
		}
		// ④
		y.left = x;// 分离出来的部分的左子节点指向旋转元素
		x.parent = y;// 旋转元素的父节点指向分离出的元素
	}

	private void rightRotate(Entry<K, V> x) {
		// ①
		Entry<K, V> y = x.left;// 分离出旋转元素的右子节点
		// ②
		x.left = y.right;// 旋转元素的右子节点的左子节点挂接到旋转元素的右子节点处
		if (y.right != null)
			y.right.parent = x;//
		// ③
		y.parent = x.parent;// 分离出来的部分挂接到旋转元素的父节点下
		if (x.parent == null) {// 如果旋转元素为根节点,就让旋转元素成为根
			this.root = y;
		} else if (x == x.parent.left) {// 如果旋转元素是它父节点的左子节点,让旋转元素父节点的左指针指向分离出的节点
			x.parent.left = y;
		} else {// 如果是右子节点,就用父节点的右指针指向分离节点
			x.parent.right = y;
		}
		// ④
		y.right = x;// 分离出来的部分的左子节点指向旋转元素
		x.parent = y;// 旋转元素的父节点指向分离出的元素
	}

	public int h() {
		return h0(this.root);
	}

	private int h0(Entry<K, V> p) {
		if (p == null)
			return -1;
		return 1 + Math.max(h0(p.left), h0(p.right));
	}

	static class Entry<K, V> {
		Entry<K, V> parent, left, right;
		K key;
		V value;
		int fix;//随机数

		public Entry(Entry<K, V> parent, Entry<K, V> left, Entry<K, V> right,
				K key, V value, int fix) {
			super();
			this.parent = parent;
			this.left = left;
			this.right = right;
			this.key = key;
			this.value = value;
			this.fix = fix;
		}
	}
}
0
1
分享到:
评论

相关推荐

    平衡二叉树的基本操作

    平衡二叉树是一种特殊的二叉树结构,它的左右子树高度差不超过1,并且左右子树都是平衡二叉树。这种结构在数据处理和搜索算法中具有重要作用,因为它保证了查找、插入和删除等操作的时间复杂度为O(log n)。下面我们...

    Qt_AverageTree.rar

    在IT领域,平衡二叉树是一种特殊的二叉数据结构,它的设计目的是为了保持数据的平衡,从而优化查找、插入和删除等操作的时间复杂度。在本项目"Qt_AverageTree"中,开发者使用Qt框架来实现一个平衡二叉树的可视化演示...

    Treap树堆实现

    它在保持查找树特性的同时,通过引入随机化来保证平衡,从而避免了传统平衡二叉树如AVL或红黑树等在插入和删除操作时可能面临的复杂旋转问题。Treap的名字来源于“Tree”和“Heap”的组合,因为它是树形结构和堆属性...

    史上最简单的平衡树——无旋Treap.pdf

    ### 最简平衡树——无旋Treap(fhq_treap)详解 #### 一、简介 无旋Treap(fhq_treap),由范浩强发明,是一种高效的平衡树数据结构。它综合了Treap与Splay树的优点,支持常见的平衡树操作如插入、删除、查找等,...

    leetcode的题目:Balanced Binary Tree

    平衡二叉树有多种实现方式,如AVL树、红黑树、Treap等。每种实现都有其特定的特性与优势: 1. **AVL树**:AVL树是最先被提出的自平衡二叉搜索树,由G. M. Adelson-Velsky和E. M. Landis在1962年提出。AVL树要求每个...

    c/c++二叉树详解,作业,学习参考

    2. **Treap**:Treap是随机化的二叉搜索树,它结合了二叉搜索树和堆的特性。每个节点都有一个优先级,通常由随机函数生成,这个优先级决定了树的形状。Treap的平均性能很好,插入、删除和查找操作的时间复杂度也为O...

    平衡树_王天懿.pptx

    平衡树是一种特殊的二叉树数据结构,主要用于高效地执行查找、插入和删除操作。它的主要特点是每个节点的左子树中的所有节点值都小于该节点,而右子树中的所有节点值都大于该节点。这样的设计确保了二叉搜索树在进行...

    数据结构之Treap详解

    与二叉堆不同,Treap不强制形成完全二叉树,因此其形状更加随机,有助于保持较好的平衡状态。 **1. Treap的构建与性质** 每个Treap节点包含四个属性: - `value`:存储节点的键值。 - `priority`:存储节点的...

    数据结构课程设计\二叉平衡排序树

    4. Treap:Treap结合了随机化和平衡,每个节点包含一个优先级,通过随机选择优先级来保持平衡,同时保持了二叉搜索树的性质。 在C语言实现二叉平衡排序树时,你需要关注以下几个关键点: 1. 结构定义:定义二叉树...

    treap:有效实现隐式treap数据结构

    - Treap的平均时间复杂度为O(log n),这是因为随机优先级保证了树的平衡性。但在最坏情况下,如果优先级顺序恰好导致退化为链表,时间复杂度会退化为O(n)。 - 由于Haskell的不可变性,Treap的插入和删除操作需要...

    07 BalancedBinarySortTree.zip

    1. **平衡二叉树定义**:平衡二叉树(Balanced Binary Tree)是一类特殊的二叉树,它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。这种结构使得在树的任一节点上的所有元素都能够...

    数据结构二叉平衡树课程设计

    - **Treap**:随机化的平衡二叉搜索树,结合了堆和二叉搜索树的特性,每个节点有一个优先级,通过优先级保持平衡。 4. **平衡调整策略**: - AVL树的平衡调整主要通过四种旋转操作:左旋、右旋、左右旋和右左旋,...

    平衡树的建立 插入删除 等操作

    - **Treap**:结合了随机性和平衡性的数据结构,每个节点包含一个优先级和键值,通过堆属性保持平衡。 2. **平衡树的建立** - **初始化**:创建一个空的根节点,对于AVL树和红黑树,根节点默认为黑色。 - **插入...

    算法与数据结构设计课件-Treaps.pdf

    Treap的一个关键优点是它的随机性,随机生成的优先级使得数据结构在插入和删除过程中自然地保持了近似平衡,从而提供了接近于最优的时间复杂度。这种方法避免了像AVL树和红黑树那样的复杂旋转策略,简化了实现,同时...

    数据结构与算法分析Java语言描述随书源码

    - **Treap** (Treap.java): Treap是随机化的二叉搜索树,结合了堆的特性,每个节点都附带一个随机优先级,以保持树的平衡。 2. 算法: - **排序算法**:在Sort.java中,不仅包含基础排序算法,也可能有高级的排序...

    bstFun:Java中的教育学treaprandomized二叉树实现

    本项目“bstFun”聚焦于Java中的教育学treap(随机化二叉搜索树)的实现,旨在帮助学习者理解并比较不同类型的二叉搜索树,如普通二叉搜索树(BST)、陷阱(worst-case)二叉搜索树以及treap。 **二叉搜索树(BST)...

    数据结构与算法分析_Java语言描述(第3版)完整源码

    7. **Treap.java** - Treap是一种随机化的二叉搜索树,结合了堆的特性,通过随机化旋转保持平衡,从而提供近似最优的查找性能。 通过学习和分析这些源码,你可以深入理解各种数据结构的内部运作机制,以及如何在...

    高级算法(algorithm)

    Treap在数据存储和检索中提供了较好的平衡性和随机性。 随机数生成在模拟、统计计算和加密算法中扮演着重要角色。在高级算法中,可能会讲解如何实现各种随机数生成算法,包括线性同余法、Mersenne Twister等,以...

Global site tag (gtag.js) - Google Analytics