算法#16--B树完整代码Java实现

定义

在计算机科学中,B树(英语:B-tree)是一种自平衡的树,能够保持数据有序。这种数据结构能够让查找数据、顺序访问、插入数据及删除的动作,都在对数时间内完成。

为什么要引入B树?

首先,包括前面我们介绍的红黑树是将输入存入内存的一种内部查找树

而B树是前面平衡树算法的扩展,它支持保存在磁盘或者网络上的符号表进行外部查找,这些文件可能比我们以前考虑的输入要大的多(难以存入内存)。

既然内容保存在磁盘中,那么自然会因为树的深度过大而造成磁盘I/O读写过于频繁(磁盘读写速率是有限制的),进而导致查询效率低下。

那么降低树的深度自然很重要了。因此,我们引入了B树,多路查找树。

特点

  1. 树中每个结点最多含有m个孩子(m>=2);

  2. 除根结点和叶子结点外,其它每个结点至少有[ceil(m / 2)]个孩子(其中ceil(x)是一个取上限的函数);

  3. 若根结点不是叶子结点,则至少有2个孩子(特殊情况:没有孩子的根结点,即根结点为叶子结点,整棵树只有一个根节点);

  4. 所有叶子结点都出现在同一层(最底层),叶子结点为外部结点,保存内容,即key和value

  5. 其他结点为内部结点,保存索引,即key和next

  6. 内部结点的关键字key:K[1], K[2], …, K[M-1];且K[i] < K[i+1];

  7. 内容结点的指针next:P[1], P[2], …, P[M];其中P[1]指向关键字小于K[1]的子树,P[M]指向关键字大于K[M-1]的子树,其它P[i]指向关键字属于(K[i-1], K[i])的子树;

例如:(M=3)

查找和插入

为了方便这里用了一个特殊的哨兵键,它小于其他所有键,用*表示。

一开始B树只含有一个根结点,而根结点在初始化时仅含有该哨兵键。

内部结点中的每个键都与一个结点相关联,以此结点为根的子树种,所有的键都大于等于与此结点关联的键,但小于其他所有键。

这些约定在很大程度上能够简化代码。

代码

点击下载

该代码实现引入了哨兵键,代码输出则剔除了它。

代码里含有哨兵键的B树(将图片保存到本地查看,字会清晰些):

代码输出的B树(将图片保存到本地查看,字会清晰些):


public class BTree<Key extends Comparable<Key>, Value>  
{
    // max children per B-tree node = M-1
    // (must be even and greater than 2)
    private static final int M = 4;

    private Node root;       // root of the B-tree
    private int height;      // height of the B-tree
    private int n;           // number of key-value pairs in the B-tree

    // helper B-tree node data type
    private static final class Node 
    {
        private int m;                             // number of children
        private Entry[] children = new Entry[M];   // the array of children

        // create a node with k children
        private Node(int k) 
        {
            m = k;
        }
    }

    // internal nodes: only use key and next
    // extern
  • 0
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
以下是Java实现k-means算法代码示例: ```java import java.util.ArrayList; import java.util.Random; public class KMeans { private int k; // 分类数 private ArrayList<double[]> dataSet; // 数据集 private ArrayList<double[]> center; // 聚类中心 private ArrayList<ArrayList<double[]>> cluster; // 各个分类的集合 public KMeans(int k, ArrayList<double[]> dataSet) { this.k = k; this.dataSet = dataSet; this.center = new ArrayList<>(); this.cluster = new ArrayList<>(); } // 初始化聚类中心 private void initCenter() { Random random = new Random(); for (int i = 0; i < k; i++) { double[] randomData = dataSet.get(random.nextInt(dataSet.size())); center.add(randomData.clone()); cluster.add(new ArrayList<>()); } } // 计算欧式距离 private double euclideanDistance(double[] a, double[] b) { double sum = 0; for (int i = 0; i < a.length; i++) { sum += Math.pow(a[i] - b[i], 2); } return Math.sqrt(sum); } // 分类 private void classify() { for (double[] data : dataSet) { double minDistance = Double.MAX_VALUE; int minIndex = 0; for (int i = 0; i < center.size(); i++) { double distance = euclideanDistance(data, center.get(i)); if (distance < minDistance) { minDistance = distance; minIndex = i; } } cluster.get(minIndex).add(data.clone()); } } // 计算新的聚类中心 private void calcCenter() { for (int i = 0; i < center.size(); i++) { double[] newCenter = new double[center.get(i).length]; for (double[] data : cluster.get(i)) { for (int j = 0; j < newCenter.length; j++) { newCenter[j] += data[j]; } } for (int j = 0; j < newCenter.length; j++) { newCenter[j] /= cluster.get(i).size(); } center.set(i, newCenter); } } // 判断聚类中心是否发生变化 private boolean isCenterChanged(ArrayList<double[]> oldCenter) { for (int i = 0; i < center.size(); i++) { if (euclideanDistance(center.get(i), oldCenter.get(i)) != 0) { return true; } } return false; } // k-means算法 public void kMeans() { initCenter(); while (true) { classify(); ArrayList<double[]> oldCenter = new ArrayList<>(center); calcCenter(); if (!isCenterChanged(oldCenter)) { break; } for (ArrayList<double[]> c : cluster) { c.clear(); } } } // 打印分类结果 public void printCluster() { for (int i = 0; i < center.size(); i++) { System.out.println("Cluster " + i + " : "); for (double[] data : cluster.get(i)) { for (double d : data) { System.out.print(d + " "); } System.out.println(); } System.out.println(); } } } ``` 使用示例: ```java public class KMeansTest { public static void main(String[] args) { ArrayList<double[]> dataSet = new ArrayList<>(); dataSet.add(new double[]{1, 2}); dataSet.add(new double[]{1, 4}); dataSet.add(new double[]{1, 0}); dataSet.add(new double[]{4, 2}); dataSet.add(new double[]{4, 4}); dataSet.add(new double[]{4, 0}); KMeans kMeans = new KMeans(2, dataSet); kMeans.kMeans(); kMeans.printCluster(); } } ``` 输出结果: ``` Cluster 0 : 1.0 2.0 1.0 4.0 1.0 0.0 Cluster 1 : 4.0 2.0 4.0 4.0 4.0 0.0 ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值