写的匆忙 估计有BUG 修改后  会去掉这个 说明

/**
* @author shuly
* @date 2017/6/5.
*/ // hint 一日为叶,终身为叶, 最后还是要转换成 <链表存储节 | 数组> 比较快, 自己写个链表吧
// 先写一个数组的好用一点
class Config {
static int M = 8; // 写的不好请确保这是个偶数.
static int MIN_NUM = M / 2;
} class LinkData {
LinkData next;
Entry data;
LinkData(){
next = null;
data = null;
}
} class Node {
int m;
Node left;
Node right;
Entry[] children = new Entry[Config.M];
//LinkData children = new LinkData();
Node(int k) {
m = k;
left = null;
right = null;
}
} abstract class Entry {
Comparable key;
} class EntryLeaf extends Entry {
Object val; EntryLeaf(Comparable key, Object val) {
this.key = key;
this.val = val;
}
} class EntryNotLeaf extends Entry {
Node nextNode; EntryNotLeaf(Comparable key, Node next) {
this.nextNode = next;
this.key = key;
} } public class BPXTree<Key extends Comparable<Key>, Value> {
private int height;
private int total;
private Node root;
// todo push
private Node leafNodeHead; public BPXTree() { leafNodeHead = new Node(0);
root = new Node(0);
leafNodeHead.right = root;
root.left = leafNodeHead;
} public int insert(Key key, Value value) {
if (key == null) throw new IllegalArgumentException("插入空值我操");
++total;
Node u = insert(root, key, value, height);
if (u != null) {
Node t = new Node(2);
t.children[0] = new EntryNotLeaf(root.children[0].key, root);
t.children[1] = new EntryNotLeaf(u.children[0].key, u);
root = t;
++height; // 树的生长
}
return 1;
} /**
* @param now 当前插入节点
* @param key key
* @param value value
* @param h 高度
* @return 需要分裂则但会当前节点,否则是null
*/
private Node insert(Node now, Key key, Value value, int h) {
int j;
Entry tmp; if (h == 0) { // 叶子节点
tmp = new EntryLeaf(key, value);
for (j = 0; j < now.m; ++j) {
if (less(key, now.children[j].key)) {
break;
}
}
} else { // 非叶子节点
tmp = new EntryNotLeaf(key, null);
for (j = 0; j < now.m; ++j) {
if ((j + 1 == now.m) || less(key, now.children[j + 1].key)) {
Node u = insert(((EntryNotLeaf) now.children[j++]).nextNode, key, value, h - 1);
if (u == null) return null;
tmp.key = u.children[0].key;
((EntryNotLeaf) tmp).nextNode = u;
break;
}
}
}
// 挪地方
for (int i = now.m; i > j; --i) {
now.children[i] = now.children[i - 1];
}
now.children[j] = tmp;
now.m++;
if (now.m < Config.M) {
return null;
}
return split(now);
} private static Node split(Node now) {
int base = Config.M / 2;
Node tmp = new Node(base);
now.m = base;
for (int j = 0; j < base; ++j) {
tmp.children[j] = now.children[base + j];
now.children[base + j] = null;
}
tmp.right = now.right;
tmp.left = now;
now.right = tmp;
return tmp;
} public Value query(Key key) {
if (key == null) {
throw new IllegalArgumentException("查询值是空啊");
}
return query(root, key, height);
} /**
* @param now 当前节点
* @param key 插入的值
* @param h 当前高度
* @return key对应的value, 没有就是null;
*/
private Value query(Node now, Key key, int h) {
Entry[] children = now.children;
if (h == 0) {// 叶子节点
for (int j = 0; j < now.m; ++j) {
if (eq(key, children[j].key)) {
return (Value) ((EntryLeaf) children[j]).val;
}
}
} else { // 非叶子节点
for (int j = 0; j < now.m; ++j) {
if ((j + 1 == now.m) || less(key, children[j + 1].key)) {
return query(((EntryNotLeaf) children[j]).nextNode, key, h - 1);
}
}
}
return null;
} public Queue<Value> queue(Key left, Key right) {
Queue<Value> ans = new LinkedList<>();
query(root, left, right, height, ans);
return ans;
} // todo
private void query(Node now, Key left, Key right, int h, Queue<Value> ans) { } /**
* @param key 删除的关键字
* @return 删除的内容;
* <p>
* <p>
* 切记在合并的时候 要去要别的节点,而不是自己的给别人,也不能去和自己的堂兄弟借,要找兄弟合并。
* 这样才能 递归的更新 索引. 3Q
*/
public Value delete(Key key) {
// root 节点的size没有限制
Triple<Value, Boolean, Key> ans = delete(root, key, height);
return ans.first;
} /**
* @param now 当前节点
* @param key 删除的主键
* @param h 目前的高度
* @return <删除的 映射值, 修改的儿子节点是否足够用, 抢的节点>
* <p>
* <p>
* 采用自己先去抢,抢不到在让父亲节点调度的方式.
*/
public Triple<Value, Boolean, Key> delete(Node now, Key key, int h) {
Triple<Value, Boolean, Key> ans = new Triple<>(null, null, null);
if (h == 0) {
//叶子了
for (int i = 0; i < now.m; i++) {
if (eq(key, now.children[i].key)) {
ans.first = (Value) ((EntryLeaf) now.children[i]).val;
now.m--;
for (int j = i; j < now.m; j++) {
now.children[j] = now.children[j + 1];
}
now.children[now.m] = null; // 删除吗 不可能 越界
break;
}
}
} else {
// 非叶子 节点
// 狗儿子们开始干活了.
for (int i = 0; i < now.m; i++) {
if ((i + 1 == now.m) || less(key, now.children[i + 1].key)) {
// 去吧比卡丘
ans = delete(((EntryNotLeaf) now.children[i]).nextNode, key, h - 1); if (ans.second) {
// 操 欲求不满的东西,让我来施舍你! 妈的我 还要维护你们的链接信息,我了个去,
int source;
int target = i; if (i + 1 == now.m && i != 0) {
source = i - 1;
Node sourceNode = ((EntryNotLeaf) now.children[source]).nextNode;
Node targetNode = ((EntryNotLeaf) now.children[target]).nextNode; for (int w = 0; w < targetNode.m; ++w) {
targetNode.children[w + sourceNode.m] = targetNode.children[w];
} for (int s = 0; s < sourceNode.m; s++) {
targetNode.children[s] = sourceNode.children[s];
}
targetNode.m += sourceNode.m; if(sourceNode.left != null) {
sourceNode.left.right = targetNode;
}
targetNode.left = sourceNode.left;
} else {
source = i + 1; if (source == now.m) {
// 结束了 这是root节点
this.root = ((EntryNotLeaf)root.children[0]).nextNode;
this.height--;
return ans;
}
Node sourceNode = ((EntryNotLeaf) now.children[source]).nextNode;
Node targetNode = ((EntryNotLeaf) now.children[target]).nextNode;
for (int s = 0, t = targetNode.m; s < sourceNode.m; s++, t++) {
targetNode.children[t] = sourceNode.children[s];
}
targetNode.m += sourceNode.m;
targetNode.right = sourceNode.right;
if(sourceNode.right != null) {
sourceNode.right.left = targetNode;
}
} // 再见我 的 小伙伴, 满足了你,牺牲了他,何必同室操戈,
for (int s = source; s < now.m; s++) {
now.children[s] = now.children[s + 1];
}
now.m--;
now.children[now.m] = null;
// 抢东西更新
} else if (ans.third != null && i + 1 != now.m && ans.third.compareTo((Key) now.children[i + 1].key) == 0) {
// 借东西索引更新
now.children[i + 1].key = updateIndexUntil(((EntryNotLeaf) now.children[i + 1]).nextNode, ans.third);
now.children[i].key = ((EntryNotLeaf)now.children[i]).nextNode.children[0].key;
} else {
now.children[i].key = ((EntryNotLeaf)now.children[i]).nextNode.children[0].key;
}
//now.children[i].key = ((EntryNotLeaf)now.children[i]).nextNode.children[0].key;
break;
}
}
}
ans.second = false;
if (now.m < Config.MIN_NUM) { //卧槽节点不够了
if (now.left != null && now.left.m > Config.MIN_NUM) {
// left 请给我点吧,我不行了QAQ
now.left.m--;
Entry entry = now.left.children[now.left.m];
now.left.children[now.left.m] = null; // 这个刁钻的插入操作妈的
for (int i = 1; i <= now.m; ++i) {
now.children[i] = now.children[i - 1];
}
now.children[0] = entry;
now.m++;
ans.third = (Key) entry.key;
} else if (now.right != null && now.right.m > Config.MIN_NUM) {
// right 请给我点吧,我不行了QAQ
Entry entry = now.right.children[0];
now.right.m--;
for (int i = 0; i < now.right.m; ++i) {
now.right.children[i] = now.right.children[i + 1];
}
now.right.children[now.right.m] = null; now.children[now.m] = entry;
now.m++;
// 这个要更新那边 等待到LCA
ans.third = (Key) entry.key;
} else {
// 父亲啊,请给我做主,灭了他们其中一个要不我不满足
ans.second = true;
}
}
return ans;
} private Key updateIndexUntil(Node now, Key key) {
if (now.children[0].key.compareTo(key) == 0) {
now.children[0].key = updateIndexUntil(((EntryNotLeaf)now.children[0]).nextNode, key);
}
return (Key) now.children[0].key;
} @Override
public String toString() {
return toString(root, height, "") + "\n";
} private String toString(Node h, int ht, String indent) {
StringBuilder s = new StringBuilder();
Entry[] children = h.children;
if (ht == 0) {
for (int j = 0; j < h.m; j++) {
s.append(indent).append(children[j].key).append(" ").append(((EntryLeaf) children[j]).val).append("\n");
}
} else {
for (int j = 0; j < h.m; j++) {
s.append(indent).append("(").append(children[j].key).append(")").append("\n");
s.append(toString(((EntryNotLeaf) children[j]).nextNode, ht - 1, indent + " "));
}
}
return s.toString();
} private static boolean less(Comparable k1, Comparable k2) {
return k1.compareTo(k2) < 0;
} private static boolean eq(Comparable k1, Comparable k2) {
return k1.compareTo(k2) == 0;
} private void linkOut() {
Node head = this.leafNodeHead;
while (head != null) { for (int i = 0; i < head.m; i++) {
System.out.print(head.children[i].key + " : " + ((EntryLeaf) head.children[i]).val + '\t');
}
head = head.right;
}
} public static void main(String[] args) {
BPXTree<Integer, Long> st = new BPXTree<>();
for (int i = 1; i <= 20; i++) {
st.insert(i, (long) i);
}
Long value = st.delete(10);
Long pp = st.delete(9);
pp = st.delete(3);
pp = st.delete(6);
pp = st.delete(1);
pp = st.delete(4);
pp = st.delete(7);
pp = st.delete(2);
pp = st.delete(8);
pp = st.delete(5); pp = st.delete(11);
pp = st.delete(12);
pp = st.delete(16);
pp = st.delete(17); System.out.println("START");
System.out.println(st.toString());
System.out.println("END");
st.linkOut(); pp = st.delete(18); System.out.println("START");
System.out.println(st.toString());
System.out.println("END");
st.linkOut();
pp = st.delete(19);
pp = st.delete(20);
pp = st.delete(13);
pp = st.delete(14);
System.out.println("START");
System.out.println(st.toString());
System.out.println("END");
st.linkOut();
pp = st.delete(15); System.out.println("START");
System.out.println(st.toString());
System.out.println("END");
st.linkOut();
}
}

BPX-tree的更多相关文章

  1. [数据结构]——二叉树(Binary Tree)、二叉搜索树(Binary Search Tree)及其衍生算法

    二叉树(Binary Tree)是最简单的树形数据结构,然而却十分精妙.其衍生出各种算法,以致于占据了数据结构的半壁江山.STL中大名顶顶的关联容器--集合(set).映射(map)便是使用二叉树实现 ...

  2. SAP CRM 树视图(TREE VIEW)

    树视图可以用于表示数据的层次. 例如:SAP CRM中的组织结构数据可以表示为树视图. 在SAP CRM Web UI的术语当中,没有像表视图(table view)或者表单视图(form view) ...

  3. 无限分级和tree结构数据增删改【提供Demo下载】

    无限分级 很多时候我们不确定等级关系的层级,这个时候就需要用到无限分级了. 说到无限分级,又要扯到递归调用了.(据说频繁递归是很耗性能的),在此我们需要先设计好表机构,用来存储无限分级的数据.当然,以 ...

  4. 2000条你应知的WPF小姿势 基础篇<45-50 Visual Tree&Logic Tree 附带两个小工具>

    在正文开始之前需要介绍一个人:Sean Sexton. 来自明尼苏达双城的软件工程师.最为出色的是他维护了两个博客:2,000Things You Should Know About C# 和 2,0 ...

  5. Leetcode 笔记 110 - Balanced Binary Tree

    题目链接:Balanced Binary Tree | LeetCode OJ Given a binary tree, determine if it is height-balanced. For ...

  6. Leetcode 笔记 100 - Same Tree

    题目链接:Same Tree | LeetCode OJ Given two binary trees, write a function to check if they are equal or ...

  7. Leetcode 笔记 99 - Recover Binary Search Tree

    题目链接:Recover Binary Search Tree | LeetCode OJ Two elements of a binary search tree (BST) are swapped ...

  8. Leetcode 笔记 98 - Validate Binary Search Tree

    题目链接:Validate Binary Search Tree | LeetCode OJ Given a binary tree, determine if it is a valid binar ...

  9. Leetcode 笔记 101 - Symmetric Tree

    题目链接:Symmetric Tree | LeetCode OJ Given a binary tree, check whether it is a mirror of itself (ie, s ...

  10. Tree树节点选中及取消和指定节点的隐藏

    指定节点变色 指定节点隐藏 单击节点 未选中则选中该节点 已选中则取消该节点 前台: 1.HTML <ul id="listDept" name="listDept ...

随机推荐

  1. Jesse's Code

    题目描述 Jesse是个数学迷,他最喜欢研究“哥德巴赫猜想”,因此他的计算机密码也都采用素数. 但一直用同一个密码是不安全的,所以他要经常更换他的密码.但他只允许自己的密码中出现某些数字,且密码的每一 ...

  2. php验证邮箱,手机号是否正确

    function is_valid_email($email)//判断是不是邮箱的函数{    return preg_match('/^[a-zA-Z0-9._%-]+@([a-zA-Z0-9.-] ...

  3. 通用查询实现方案(可用于DDD)[附源码] -- 简介

    原文:通用查询实现方案(可用于DDD)[附源码] -- 简介 [声明] 写作不易,转载请注明出处(http://www.cnblogs.com/wiseant/p/3985353.html).   [ ...

  4. 【VC++学习笔记五】SDI|MDI的全屏显示

    一.Mainframe中添加一个记录是否全屏状态的变量BOOL m_bFullScreen. 二.工具栏添加一个按钮,进行全屏的操作,响应事件函数写在Mainframe中. 三.在响应函数中,添加如下 ...

  5. 洛谷 P1900 自我数

    P1900 自我数 题目描述 在1949年印度数学家D. R. Daprekar发现了一类称作Self-Numbers的数.对于每一个正整数n,我们定义d(n)为n加上它每一位数字的和.例如,d(75 ...

  6. DataGirdView 常用操作

    1.将数据源的某列添加到已有DataGirdView的列 例如:将文件夹下所有文件名添加到DataGirdView 的文件名一列,图片如下: 首先在datagridview把文件名列的DATAPROP ...

  7. 一些安全的DNS提供商

    检测当前使用的DNS服务器    https://dnsleaktest.com 一些安全的DNS提供商 DNS提供商名称 主DNS服务器 次要DNS服务器 Google 8.8.8.8 8.8.4. ...

  8. js -- 分页功能

    html 代码 <html> <head> <meta charset='utf-8'> <script type="text/javascript ...

  9. CentOS6.5下的Nagios安装配置详解(图文)

    最近因为,科研需要,接触上了Nagios,这里,我将安装笔记做个详解.为自己后续需要和博友们学习! VMware workstation 11 的下载 VMWare Workstation 11的安装 ...

  10. 分享一下事件监听addEventListener----attachEvent的用法

    来自:http://www.cnblogs.com/wkylin/archive/2011/10/09/2203161.html 事件监听addEventListener----attachEvent ...