伸展树(三)之 Java的实现
2014-04-01 22:18
2031 查看
概要
前面分别通过C和C++实现了伸展树,本章给出伸展树的Java版本。基本算法和原理都与前两章一样。1. 伸展树的介绍
2. 伸展树的Java实现(完整源码)
3. 伸展树的Java测试程序
转载请注明出处:https://www.geek-share.com/detail/2607361883.html
更多内容: 数据结构与算法系列 目录
(01) 伸展树(一)之 图文解析 和 C语言的实现
(02) 伸展树(二)之 C++的实现
(03) 伸展树(三)之 Java的实现
伸展树的介绍
伸展树(Splay Tree)是特殊的二叉查找树。它的特殊是指,它除了本身是棵二叉查找树之外,它还具备一个特点: 当某个节点被访问时,伸展树会通过旋转使该节点成为树根。这样做的好处是,下次要访问该节点时,能够迅速的访问到该节点。
伸展树的Java实现
1. 基本定义public class SplayTree<T extends Comparable<T>> { private SplayTreeNode<T> mRoot; // 根结点 public class SplayTreeNode<T extends Comparable<T>> { T key; // 关键字(键值) SplayTreeNode<T> left; // 左孩子 SplayTreeNode<T> right; // 右孩子 public SplayTreeNode() { this.left = null; this.right = null; } public SplayTreeNode(T key, SplayTreeNode<T> left, SplayTreeNode<T> right) { this.key = key; this.left = left; this.right = right; } } ... }
SplayTree是伸展树,而SplayTreeNode是伸展树节点。在此,我将SplayTreeNode定义为SplayTree的内部类。在伸展树SplayTree中包含了伸展树的根节点mRoot。SplayTreeNode包括的几个组成元素:
(01) key -- 是关键字,是用来对伸展树的节点进行排序的。
(02) left -- 是左孩子。
(03) right -- 是右孩子。
2. 旋转
旋转是伸展树中需要重点关注的,它的代码如下:
/* * 旋转key对应的节点为根节点,并返回根节点。 * * 注意: * (a):伸展树中存在"键值为key的节点"。 * 将"键值为key的节点"旋转为根节点。 * (b):伸展树中不存在"键值为key的节点",并且key < tree.key。 * b-1 "键值为key的节点"的前驱节点存在的话,将"键值为key的节点"的前驱节点旋转为根节点。 * b-2 "键值为key的节点"的前驱节点存在的话,则意味着,key比树中任何键值都小,那么此时,将最小节点旋转为根节点。 * (c):伸展树中不存在"键值为key的节点",并且key > tree.key。 * c-1 "键值为key的节点"的后继节点存在的话,将"键值为key的节点"的后继节点旋转为根节点。 * c-2 "键值为key的节点"的后继节点不存在的话,则意味着,key比树中任何键值都大,那么此时,将最大节点旋转为根节点。 */ private SplayTreeNode<T> splay(SplayTreeNode<T> tree, T key) { if (tree == null) return tree; SplayTreeNode<T> N = new SplayTreeNode<T>(); SplayTreeNode<T> l = N; SplayTreeNode<T> r = N; SplayTreeNode<T> c; for (;;) { int cmp = key.compareTo(tree.key); if (cmp < 0) { if (tree.left == null) break; if (key.compareTo(tree.left.key) < 0) { c = tree.left; /* rotate right */ tree.left = c.right; c.right = tree; tree = c; if (tree.left == null) break; } r.left = tree; /* link right */ r = tree; tree = tree.left; } else if (cmp > 0) { if (tree.right == null) break; if (key.compareTo(tree.right.key) > 0) { c = tree.right; /* rotate left */ tree.right = c.left; c.left = tree; tree = c; if (tree.right == null) break; } l.right = tree; /* link left */ l = tree; tree = tree.right; } else { break; } } l.right = tree.left; /* assemble */ r.left = tree.right; tree.left = N.right; tree.right = N.left; return tree; } public void splay(T key) { mRoot = splay(mRoot, key); }
上面的代码的作用:将"键值为key的节点"旋转为根节点,并返回根节点。它的处理情况共包括:
(a):伸展树中存在"键值为key的节点"。
将"键值为key的节点"旋转为根节点。
(b):伸展树中不存在"键值为key的节点",并且key < tree->key。
b-1) "键值为key的节点"的前驱节点存在的话,将"键值为key的节点"的前驱节点旋转为根节点。
b-2) "键值为key的节点"的前驱节点存在的话,则意味着,key比树中任何键值都小,那么此时,将最小节点旋转为根节点。
(c):伸展树中不存在"键值为key的节点",并且key > tree->key。
c-1) "键值为key的节点"的后继节点存在的话,将"键值为key的节点"的后继节点旋转为根节点。
c-2) "键值为key的节点"的后继节点不存在的话,则意味着,key比树中任何键值都大,那么此时,将最大节点旋转为根节点。
下面列举个例子分别对a进行说明。
在下面的伸展树中查找10,,共包括"右旋" --> "右链接" --> "组合"这3步。
/** * Java 语言: 伸展树 * * @author skywang * @date 2014/02/03 */ public class SplayTreeTest { private static final int arr[] = {10,50,40,30,20,60}; public static void main(String[] args) { int i, ilen; SplayTree<Integer> tree=new SplayTree<Integer>(); System.out.print("== 依次添加: "); ilen = arr.length; for(i=0; i<ilen; i++) { System.out.print(arr[i]+" "); tree.insert(arr[i]); } System.out.print("\n== 前序遍历: "); tree.preOrder(); System.out.print("\n== 中序遍历: "); tree.inOrder(); System.out.print("\n== 后序遍历: "); tree.postOrder(); System.out.println(); System.out.println("== 最小值: "+ tree.minimum()); System.out.println("== 最大值: "+ tree.maximum()); System.out.println("== 树的详细信息: "); tree.print(); i = 30; System.out.printf("\n== 旋转节点(%d)为根节点\n", i); tree.splay(i); System.out.printf("== 树的详细信息: \n"); tree.print(); // 销毁二叉树 tree.clear(); } }
View Code
在二叉查找树的Java实现中,使用了泛型,也就意味着它支持任意类型;但是该类型必须要实现Comparable接口。
伸展树的Java测试程序
伸展树的测试程序运行结果如下:== 依次添加: 10 50 40 30 20 60 == 前序遍历: 60 30 20 10 50 40 == 中序遍历: 10 20 30 40 50 60 == 后序遍历: 10 20 40 50 30 60 == 最小值: 10 == 最大值: 60 == 树的详细信息: 60 is root 30 is 60's left child 20 is 30's left child 10 is 20's left child 50 is 30's right child 40 is 50's left child == 旋转节点(30)为根节点 == 树的详细信息: 30 is root 20 is 30's left child 10 is 20's left child 60 is 30's right child 50 is 60's left child 40 is 50's left child
测试程序的主要流程是:新建伸展树,然后向伸展树中依次插入10,50,40,30,20,60。插入完毕这些数据之后,伸展树的节点是60;此时,再旋转节点,使得30成为根节点。
依次插入10,50,40,30,20,60示意图如下:
将30旋转为根节点的示意图如下:
相关文章推荐
- 伸展树 之 Java的实现
- 伸展树--Java实现
- 伸展树--Java实现
- 伸展树与半伸展树Java实现 http://www.blogjava.net/javacap/archive/2007/12/19/168627.html
- 使用伸展树(SplayTree)统计单词频率的Java实现
- 使用异或进行简单的密码加密(JAVA实现)
- Java调取创蓝253短信验证码的实现代码
- Java实现数组排序含冒泡排序、选择排序
- java实现系统托盘示例
- 实现文件复制、剪切、删除操作 Java
- 直接选择排序算法设计与java实现
- Java实现斐波那契数列
- Java对PHP服务器hmac_sha1签名认证方法的匹配实现
- 算法(第四版)学习笔记之java实现二叉查找树
- js生成日志信息及实现java直接调用flume
- 二叉树的几种遍历(递归,非递归)JAVA实现
- dubbo rest emoji表情拦截器 java实现
- Java多线程下载的实现方法
- 在Java中使用JGraph实现图形绘制
- java实现数据结构单链表示例(java单链表)