查找-多路查找详解篇1

简介: 查找-多路查找详解篇1

多路查找树

多路查找树(Multway Search Tree)是一种高级的树形数据结构,它
允许每个节点有多个子节点(通常大于等于2)。多路查找树的每个节点
可以存储多个关键字和对应的值。

分类

2-3树(2-3 Tree):
2-3树是一种最简单的多路查找树,每个节点可以存储1个或2个关键字,
并有2个或3个子节点。
2-3树的特点是所有叶子节点都在同一层,且根节点到每个叶子节点的
路径长度相等,保持树的平衡性。
B-树(B-tree):
B-树是一种平衡的多路查找树,每个节点可以存储多个关键字,并有相
应数量的子节点。
B-树的特点是节点的关键字按照升序排列,具有高度平衡的特性,主要
用于在磁盘等外部存储设备中高效存储和检索数据。
B+树(B+ tree):
B+树是B-树的一种变种,在B-树的基础上做了一些优化,特别适合于范
围查询和顺序访问。
B+树的特点是只有叶子节点存储了真实数据,而内部节点仅用于索引,
叶子节点通过指针连接形成一个链表,方便范围查询。
B树(B-tree):
B*树也是B-树的一种变种,与B+树类似,它在B-树的基础上做了一些改
进。
B*树通过在非叶子节点中存储部分关键字,扩大了节点的使用率,减少
了磁盘访问次数,并提高了空间和时间的效率。
Trie树(字典树或前缀树):
Trie树是一种特殊的多路查找树,在处理字符串和前缀匹配的情况下非
常有用。
Trie树的特点是每个节点代表一个字符,从根节点到叶子节点的路径可
以表示一个完整的字符串。
除此以外,还有如2-3-4树、2-3-4-树、B*+树等。每种多路查找树在
平衡性、存储结构、查询性能等方面可能有所不同,选择合适的多路查
找树取决于应用需求和数据特点。对于大规模的外部存储数据,B-树和
B+树是常见的选择;对于高效的字符串匹配和前缀查询,Trie树是一种
有效的数据结构。

详细介绍



2-3树(2-3 Tree)

2-3树是一种平衡的多路查找树,每个节点可以存储1个或2个关键字,并有2个
或3个子节点。以下是关于2-3树的详细介绍:



结构特点:

2-3树由节点组成,每个节点可以存储1个或2个关键字,这些关键字按升序排列。
每个节点有2个或3个子节点,对应于存储的关键字个数。
所有叶子节点都在同一层,且根节点到每个叶子节点的路径长度相等,保持树的
平衡性。

插入操作:

1、当要插入一个关键字时,从根节点开始,判断关键字应插入的位置。
2、如果节点已满(即已有两个关键字),则需要进行节点分裂操作。将中间较
  大的关键字移动到上一层的父节点,并将两个剩余的关键字分别创建为新的
  子节点。
3、如果节点还没有满,则直接将关键字插入到正确的位置。


删除操作:

当要删除一个关键字时,从根节点开始,找到包含该关键字的节点。
  如果该节点是叶子节点,直接删除关键字即可。如果该节点是内部节点,有
    几种情况需要处理:
  如果该节点有2个关键字,则可以直接删除关键字,不需要做其他操作。
  如果该节点有1个关键字:
  如果其兄弟节点有2个关键字,则可以借用兄弟节点的一个关键字,并进行
    相关的调整。
  如果其兄弟节点也只有1个关键字,则需要进行合并操作,将关键字和子节
    点合并到一起。

查询操作:

2-3树的查询操作与二叉查找树类似,从根节点开始,根据关键字的大小比较,
向左或向右子节点递归查询,直到找到匹配的关键字或遇到叶子节点。

强调

2-3树的特点在于其每个节点可以存储多个关键字,这样可以减少树的高度,提
供更高效的搜索和插入操作。它保持了树的平衡性,且所有叶子节点都在同一层,
这样可以保证较为平衡的查询性能。然而,2-3树的实现和维护操作较为复杂,
导致其并不常用,更常见的是其变种B-树和B+树,它们在2-3树的基础上进行了
一些优化和改进。

Java代码实现

// 2-3树的节点类
class Node {
    private int[] keys;  // 节点的关键字
    private Node[] children;  // 子节点数组
    private int size;  // 节点包含的关键字数量
    private boolean isLeaf;  // 是否为叶子节点
    public Node(boolean isLeaf) {
        this.keys = new int[3];
        this.children = new Node[4];
        this.size = 0;
        this.isLeaf = isLeaf;
    }
    // 从节点中查找关键字的位置
    public int findKey(int key) {
        for (int i = 0; i < size; i++) {
            if (keys[i] == key) {
                return i;
            } else if (keys[i] > key) {
                return -1;
            }
        }
        return -1;
    }
    // 在节点中插入关键字
    public void insertKey(int key) {
        if (size == 0) {
            keys[0] = key;
            size++;
        } else {
            int i = size - 1;
            while (i >= 0 && keys[i] > key) {
                keys[i + 1] = keys[i];
                i--;
            }
            keys[i + 1] = key;
            size++;
        }
    }
    // 在节点中删除关键字
    public void deleteKey(int key) {
        int index = findKey(key);
        if (index != -1) {
            for (int i = index; i < size - 1; i++) {
                keys[i] = keys[i + 1];
            }
            size--;
        }
    }
    // 获取节点的关键字数量
    public int getSize() {
        return size;
    }
    // 判断节点是否为叶子节点
    public boolean isLeaf() {
        return isLeaf;
    }
    // 获取节点指定位置的子节点
    public Node getChild(int index) {
        return children[index];
    }
    // 设置节点指定位置的子节点
    public void setChild(int index, Node child) {
        children[index] = child;
    }
}
// 2-3树类
class TwoThreeTree {
    private Node root;
    public TwoThreeTree() {
        root = null;
    }
    // 在2-3树中插入关键字
    public void insert(int key) {
        if (root == null) {
            root = new Node(true);
            root.insertKey(key);
        } else {
            Node newNode = insertKey(root, key);
            if (newNode != null) {
                Node oldRoot = root;
                root = new Node(false);
                root.setChild(0, oldRoot);
                root.setChild(1, newNode);
                root.insertKey(newNode.keys[0]);
                root.insertKey(oldRoot.keys[0]);
            }
        }
    }
    // 在给定的节点中插入关键字
    private Node insertKey(Node node, int key) {
        if (node.isLeaf()) {
            node.insertKey(key);
            if (node.getSize() > 2) {
                return splitLeaf(node);
            }
        } else {
            int i = node.getSize() - 1;
            while (i >= 0 && key < node.getChild(i).keys[0]) {
                i--;
            }
            Node newNode = insertKey(node.getChild(i + 1), key);
            if (newNode != null) {
                node.insertKey(newNode.keys[0]);
  }

B-树(B-tree)

B-树(B-tree)是一种平衡的多路查找树,广泛应用于在磁盘等外部存储设备中
高效地存储和检索大量数据。以下是关于B-树的详细介绍:


结构特点:

B-树由节点组成,每个节点可以存储多个
关键字,这些关键字按升序排列。
B-树的特点是节点的关键字按升序排列,具有高度平衡的特性。
每个节点通常有多个子节点,最多可以拥有m个子节点,其中m称为B-树的阶数。

插入操作:

1、当要插入一个关键字时,从根节点开始,判断关键字应插入的位置。
2、如果节点已满,则需要进行节点分裂操作。将中间位置的关键字提升为父节
  点,并将节点分裂为两个节点,将剩余的关键字均匀分配到这两个节点中。
3、如果要插入的节点还没有满,则直接将关键字插入到合适的位置。

删除操作:

1、当要删除一个关键字时,从根节点开始,找到包含该关键字的节点。
2、如果该节点是叶子节点,直接删除关键字即可。如果该节点是内部节点,需
  要找到其前驱或后继关键字来替代删除的关键字。
3、在删除操作后,如果节点中的关键字数量过少,则需要进行节点合并或者从
  兄弟节点中借用关键字来保持树的平衡。

查询操作:

B-树的查询操作与二叉查找树类似,从根节点开始,根据关键字的大小比较,
向左或向右子节点递归查询,直到找到匹配的关键字或遇到叶子节点。


强调

B-树适用于大规模数据存储和查询的场景,尤其是需要在外部存储设备上进行操
作的情况。B-树的高度平衡保证了较为均衡的查询性能,因为从根节点到叶子节
点的路径长度相等或差别不大。B-树的阶数m可以根据具体应用和硬件限制来选
择,通常情况下,较大的阶数有助于减少磁盘访问的次数,提高效率。
B-树的变种B+树在B-树的基础上做了一些优化,将所有数据存储在叶子节点中,
使得范围查询和顺序访问更加高效。因此,在现代数据库系统和文件系统中,
B+树更加常见和广泛应用。

代码实现

import java.util.ArrayList;
import java.util.List;
class BMinusTreeNode {
    public boolean isLeaf; // 是否是叶子节点
    public List<Integer> keys; // 节点中存储的关键字
    public List<BMinusTreeNode> children; // 节点的子节点
    public BMinusTreeNode() {
        keys = new ArrayList<>();
        children = new ArrayList<>();
    }
}
class BMinusTree {
    private BMinusTreeNode root;
    private int t; // B-树的阶数
    public BMinusTree(int degree) {
        root = new BMinusTreeNode();
        root.isLeaf = true;
        t = degree;
    }
    public void insert(int key) {
        // 根节点满了就分裂
        if (root.keys.size() == (2 * t)) {
            BMinusTreeNode newRoot = new BMinusTreeNode();
            newRoot.children.add(root);
            splitChild(newRoot, 0, root);
            root = newRoot;
        }
        insertNonFull(root, key);
    }
    private void insertNonFull(BMinusTreeNode node, int key) {
        int index = node.keys.size() - 1;
        if (node.isLeaf) {
            while (index >= 0 && node.keys.get(index) > key) {
                index--;
            }
            node.keys.add(index + 1, key);
        } else {
            while (index >= 0 && node.keys.get(index) > key) {
                index--;
            }
            index++;
            if (node.children.get(index).keys.size() == (2 * t)) {
                splitChild(node, index, node.children.get(index));
                if (node.keys.get(index) < key) {
                    index++;
                }
            }
            insertNonFull(node.children.get(index), key);
        }
    }
    private void splitChild(BMinusTreeNode parent, int index, BMinusTreeNode node) {
        BMinusTreeNode newNode = new BMinusTreeNode();
        newNode.isLeaf = node.isLeaf;
        parent.keys.add(index, node.keys.get(t - 1));
        parent.children.add(index + 1, newNode);
        for (int i = t; i < 2 * t - 1; i++) {
            newNode.keys.add(node.keys.get(i));
        }
        if (!node.isLeaf) {
            for (int i = t; i < 2 * t; i++) {
                newNode.children.add(node.children.get(i));
            }
        }
        for (int i = 2 * t - 2; i >= t - 1; i--) {
            node.keys.remove(i);
        }
        if (!node.isLeaf) {
            for (int i = 2 * t - 1; i >= t; i--) {
                node.children.remove(i);
            }
        }
    }
相关文章
|
6月前
|
算法 前端开发
在系统中查找重复文件
在系统中查找重复文件
74 0
|
1月前
|
算法
算法—查找假币
算法—查找假币
46 0
|
3月前
|
算法 C++
查找方式:依次查找与二分查找
查找方式:依次查找与二分查找
|
6月前
查找数据
查找数据。
36 1
|
算法
查找
查找是指在图中寻找特定的节点或边的过程。在图中进行查找操作可以帮助我们找到与目标节点或边相关的信息,或者判断图中是否存在某个节点或边。 在图中进行查找操作的常见算法有: 1. 深度优先搜索(DFS):从图中的一个节点开始,沿着一条路径一直深入直到无法再深入为止,然后回溯到上一个节点,继续深入其他路径,直到找到目标节点或遍历完所有节点。 2. 广度优先搜索(BFS):从图中的一个节点开始,先访问它的所有邻居节点,然后再依次访问邻居的邻居节点,直到找到目标节点或遍历完所有节点。 3. Dijkstra算法:用于在带权有向图中找到从一个节点到其他节点的最短路径。该算法通过不断更新节点的最短距离来逐步
74 0
|
6月前
排序和查找
排序和查找
57 0
二叉排序树的建立、查找、插入、删除
二叉排序树的建立、查找、插入、删除
110 0
|
存储 算法
查找-之有序表查找
待查找的表是有序排列的
94 0
查找-之有序表查找
|
算法 大数据 索引
算法查找——分块查找
分块查找是折半查找(二分查找)和顺序查找的一种改进方法,分块查找由于只要求索引表是有序的,对块内节点没有排序要求,因此特别适合于节点动态变化的情况。分块查找的速度虽然不如折半查找算法,但比顺序查找算法快得多,同时又不需要对全部节点进行排序
248 0
算法查找——分块查找