查找-多路查找详解篇

多路查找树

多路查找树(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);
            }
        }
    }

B+树(B+tree)

B+树(B+ tree)是B-树的一种变种,特别适用于范围查询和顺序访问。

结构特点:

B+树与B-树类似,由节点组成,每个节点可以存储多个关键字,这些关键字按升
序排列。

B+树的特点是只有叶子节点存储了真实数据,而内部节点仅用于索引。叶子节点
通过指针连接形成一个链表,方便范围查询和顺序访问。
内部节点特点:
内部节点存储关键字和指向子节点的指针。
内部节点的关键字按升序排列,用于指示范围查询的起点。
内部节点的指针指向比关键字更大的子节点。
叶子节点特点:
叶子节点存储真实数据和指向下一个叶子节点的指针。
叶子节点的关键字按升序排列,支持范围查询和顺序访问。
所有叶子节点通过指针连接成一个链表,便于范围查询和顺序访问。

插入操作:

当要插入一个关键字时,从根节点开始,找到合适的叶子节点。
如果叶子节点已满,则需要进行节点分裂操作。将中间位置的关键字提升到父节
点,并将两个剩余的部分分别创建为新的叶子节点。
如果叶子节点还没有满,则直接将关键字插入到合适的位置。

删除操作:

当要删除一个关键字时,从根节点开始,找到包含该关键字的叶子节点。
直接删除叶子节点中的关键字,并更新链表指针。
删除操作后,如果叶子节点的关键字个数过少,则需要从兄弟节点借用关键字或
进行节点合并。

查询操作:


B+树的查询操作与B-树类似,从根节点开始,根据关键字的大小比较,向左或向
	右子节点递归查询,直到找到匹配的关键字或遇到叶子节点。
对于范围查询和顺序访问,可以从叶子节点开始,沿着链表进行遍历。

强调

B+树的特点在于只有叶子节点存储真实数据,这样使得范围查询和顺序访问更加
高效,因为数据在叶子节点上连续存储,读取连续的数据块比随机读取更快。而
内部节点仅存储索引信息,可以容纳更多的索引,提高了查询效率。B+树的实现
适用于需要高效地处理大量数据的数据库和文件系统,能够提供较高的查询性能
和存储效率。

代码实现

import java.util.ArrayList;
import java.util.List;

class BPlusTreeNode {
    public boolean isLeaf;
    public List<Integer> keys;
    public List<Object> values;
    public List<BPlusTreeNode> children;
    public BPlusTreeNode next;

    public BPlusTreeNode() {
        isLeaf = false;
        keys = new ArrayList<>();
        values = new ArrayList<>();
        children = new ArrayList<>();
        next = null;
    }
}

class BPlusTree {
    private BPlusTreeNode root;
    private int m;

    public BPlusTree(int m) {
        root = new BPlusTreeNode();
        root.isLeaf = true;
        this.m = m;
    }

    // 插入操作
    public void insert(int key, Object value) {
        if (root.keys.size() == m) {
            BPlusTreeNode newRoot = new BPlusTreeNode();
            newRoot.children.add(root);
            splitChild(newRoot, 0, root);
            root = newRoot;
        }
        insertNonFull(root, key, value);
    }

    // 非满子节点插入操作
    private void insertNonFull(BPlusTreeNode node, int key, Object value) {
        int index = node.keys.size() - 1;
        if (node.isLeaf) {
            while (index >= 0 && node.keys.get(index) > key) {
                index--;
            }
            node.keys.add(index + 1, key);
            node.values.add(index + 1, value);
            node.next = node.next;
        } else {
            while (index >= 0 && node.keys.get(index) > key) {
                index--;
            }
            index++;
            if (node.children.get(index).keys.size() == m) {
                splitChild(node, index, node.children.get(index));
                if (node.keys.get(index) < key) {
                    index++;
                }
            }
            insertNonFull(node.children.get(index), key, value);
        }
    }

    // 分裂满子节点
    private void splitChild(BPlusTreeNode parent, int index, BPlusTreeNode node) {
        BPlusTreeNode newNode = new BPlusTreeNode();
        newNode.isLeaf = node.isLeaf;
        parent.keys.add(index, node.keys.get(m / 2));
        parent.children.add(index + 1, newNode);

        newNode.keys.addAll(node.keys.subList((m / 2) + 1, m));
        newNode.values.addAll(node.values.subList((m / 2) + 1, m));
        
        if (!node.isLeaf) {
            newNode.children.addAll(node.children.subList((m / 2) + 1, m + 1));
            node.children.subList((m / 2) + 1, m + 1).clear();
        } else {
            newNode.next = node.next;
            node.next = newNode;
        }

        node.keys.subList(m / 2, m).clear();
        node.values.subList(m / 2, m).clear();
    }

    // 搜索操作
    public List<Object> search(int key) {
        return search(root, key);
    }

    private List<Object> search(BPlusTreeNode node, int key) {
        int index = 0;
        while (index < node.keys.size() && key > node.keys.get(index)) {
            index++;
        }
        if (index < node.keys.size() && key == node.keys.get(index)) {
            return node.values.get(index);
        } else if (node.isLeaf) {
            return null;
        } else {
            return search(node.children.get(index), key);
        }
    }
}

B树(B-tree)

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

结构特点:

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

插入操作:

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

删除操作:

当要删除一个关键字时,从根节点开始,找到包含该关键字的节点。
如果该节点是叶子节点,直接删除关键字。
如果该节点是内部节点,有几种情况需要处理:
如果该节点有足够多的关键字,则可以直接删除关键字。
如果该节点的关键字数量过少,需要考虑兄弟节点的关键字数量以及兄弟节点合
并的情况。

查询操作:

B树的查询操作与二叉查找树类似,从根节点开始,根据关键字的大小比较,向
左或向右子节点递归查询,直到找到匹配的关键字或遇到叶子节点。
B树适用于大规模数据存储和查询的场景,特别适用于外部存储设备上的数据存
储。其平衡性保证了较为均衡的查询性能,因为从根节点到叶子节点的路径长度
相等或差别不大。B树的阶数m可以根据具体应用和硬件限制来选择,较大的阶数
有助于减少磁盘访问的次数,提高效率。

强调

B树的变种B+树在B树的基础上做了一些优化,将所有的数据都存储在叶子节点
中,使得范围查询和顺序访问更加高效。因此,B+树在现代数据库系统和文件
系统中更为常见和广泛应用。、

代码实现

import java.util.ArrayList;
import java.util.List;

class BTreeNode {
    int degree; // B树的阶数
    List<Integer> keys; // 节点中存储的关键字
    List<BTreeNode> children; // 节点的子节点
    boolean isLeaf; // 是否是叶子节点

    public BTreeNode(int degree, boolean isLeaf) {
        this.degree = degree;
        this.isLeaf = isLeaf;
        keys = new ArrayList<>();
        children = new ArrayList<>();
    }
}

class BTree {
    BTreeNode root; // B树的根节点
    int degree; // B树的阶数

    public BTree(int degree) {
        this.degree = degree;
        root = new BTreeNode(degree, true);
    }

    // 插入关键字
    public void insert(int key) {
        if (root.keys.size() == (2 * degree - 1)) {
            BTreeNode newRoot = new BTreeNode(degree, false);
            newRoot.children.add(root);
            splitChild(newRoot, 0, root);
            root = newRoot;
        }
        insertNonFull(root, key);
    }

    // 在非满节点插入关键字
    private void insertNonFull(BTreeNode node, int key) {
        int index = node.keys.size() - 1;
        if (node.isLeaf) {
            while (index >= 0 && key < node.keys.get(index)) {
                index--;
            }
            node.keys.add(index + 1, key);
        } else {
            while (index >= 0 && key < node.keys.get(index)) {
                index--;
            }
            index++;
            if (node.children.get(index).keys.size() == (2 * degree - 1)) {
                splitChild(node, index, node.children.get(index));
                if (key > node.keys.get(index)) {
                    index++;
                }
            }
            insertNonFull(node.children.get(index), key);
        }
    }

    // 分裂子节点
    private void splitChild(BTreeNode parent, int index, BTreeNode node) {
        BTreeNode newNode = new BTreeNode(degree, node.isLeaf);
        parent.keys.add(index, node.keys.get(degree - 1));
        parent.children.add(index + 1, newNode);
        for (int i = 0; i < degree - 1; i++) {
            newNode.keys.add(node.keys.get(i + degree));
            if (!node.isLeaf) {
                newNode.children.add(node.children.get(i + degree));
            }
        }
        if (!node.isLeaf) {
            newNode.children.add(node.children.get(2 * degree - 1));
        }
        for (int i = degree - 1; i >= 0; i--) {
            node.keys.remove(i + degree - 1);
            if (!node.isLeaf) {
                node.children.remove(i + degree);
            }
        }
    }

    // 搜索关键字
    public boolean search(int key) {
        return search(root, key);
    }

    private boolean search(BTreeNode node, int key) {
        int index = 0;
        while (index < node.keys.size() && key > node.keys.get(index)) {
            index++;
        }
        if (index < node.keys.size() && key == node.keys.get(index)) {
            return true;
        } else if (node.isLeaf) {
            return false;
        } else {
            return search(node.children.get(index), key);
        }
    }
}

Trie树(字典树或前缀树)

Trie树,也被称为字典树或前缀树,是一种用于高效存储和搜索字符串的树型数
据结构。Trie树的主要特点是通过字符串的前缀来进行搜索和匹配。

结构特点:

Trie树由根节点和一系列子节点组成。
根节点不包含任何关键字,每个子节点都表示一个字符,并按字符的顺序连接形
成路径。
从根节点到每个叶子节点的路径都对应一个字符串。
每个节点可以存储额外的信息,如词频或附加数据等。

插入操作:

当要插入一个字符串时,从根节点开始,逐个字符按顺序插入。
如果某个字符对应的子节点不存在,则创建一个新的子节点。
插入字符串的最后一个字符后,将当前节点标记为一个单词的结束。

搜索操作:

当要搜索一个字符串时,从根节点开始,逐个字符按顺序匹配。
如果某个字符对应的子节点存在,则继续匹配下一个字符。
如果匹配遇到缺失的字符或到达某个节点后没有子节点,则表示字符串不在Trie
树中。
如果匹配成功并且在Trie树中找到最后一个字符,则表示字符串存在于Trie树中。

删除操作:

当要删除一个字符串时,从根节点开始,逐个字符按顺序遍历。
如果遍历过程中发现某个字符对应的子节点不存在,则表示字符串不存在于Trie
树中。
如果遍历成功,并到达字符串的最后一个字符,将当前节点的结束标记取消。
如果遍历成功,但还存在其他相关字符串(例如,删除"abc"但还有"abcd"),
可以保留当前节点以表示其他相关字符串。

优点:

搜索的时间复杂度与字符串长度无关,仅与Trie树的高度相关,通常比哈希表更
高效。
可以高效地搜索具有相同前缀的字符串集合。
对于字符串的前缀匹配和自动补全,Trie树可以提供高效的结果。

缺点:

空间消耗较大,尤其在处理大量长字符串时。为了缓解这个问题,可以使用压缩
的Trie树,如压缩前缀树(Patricia树)或Trie树的变种来减少存储空间。

代码实现

class TrieNode {
    private TrieNode[] children;
    private boolean isEndOfWord;

    public TrieNode() {
        children = new TrieNode[26]; // 26个英文字母
        isEndOfWord = false;
    }

    public TrieNode getChild(char ch) {
        return children[ch - 'a'];
    }

    public void setChild(char ch, TrieNode node) {
        children[ch - 'a'] = node;
    }

    public boolean isEndOfWord() {
        return isEndOfWord;
    }

    public void setEndOfWord(boolean isEndOfWord) {
        this.isEndOfWord = isEndOfWord;
    }
}

class Trie {
    private TrieNode root;

    public Trie() {
        root = new TrieNode();
    }

    public void insert(String word) {
        TrieNode node = root;
        for (char ch : word.toCharArray()) {
            if (node.getChild(ch) == null) {
                node.setChild(ch, new TrieNode());
            }
            node = node.getChild(ch);
        }
        node.setEndOfWord(true);
    }

    public boolean search(String word) {
        TrieNode node = findNode(word);
        return node != null && node.isEndOfWord();
    }

    public boolean startsWith(String prefix) {
        TrieNode node = findNode(prefix);
        return node != null;
    }

    private TrieNode findNode(String str) {
        TrieNode node = root;
        for (char ch : str.toCharArray()) {
            node = node.getChild(ch);
            if (node == null) {
                return null;
            }
        }
        return node;
    }
}

使用示例

public class Main {
    public static void main(String[] args) {
        Trie trie = new Trie();
        trie.insert("apple");
        trie.insert("banana");
        trie.insert("grape");
        
        System.out.println(trie.search("apple")); // 输出: true
        System.out.println(trie.search("orange")); // 输出: false
        
        System.out.println(trie.startsWith("app")); // 输出: true
        System.out.println(trie.startsWith("ban")); // 输出: true
        System.out.println(trie.startsWith("grap")); // 输出: true
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/53059.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Vite+Vue3 开发UI组件库并发布到npm

一直对开源UI组件库比较感兴趣&#xff0c;摸索着开发了一套&#xff0c;虽然还只是开始&#xff0c;但是从搭建到发布这套流程基本弄明白了&#xff0c;现在分享给大家&#xff0c;希望对同样感兴趣的同学有所帮助。 目前我的这套名为hasaki-ui的组件库仅有两个组件&#xff0…

FitBot-一款先进的以健康为中心的聊天机器人

在健康意识高涨&#xff0c;追求均衡生活方式成为普遍追求的时代&#xff0c;营养问题无疑是核心支柱。然而&#xff0c;饮食计划的复杂性和大量的营养数据往往成为我们实现这种平衡的障碍。例如糖尿病患者&#xff0c;他们需要持续和准确的营养指导来有效管理血糖水平。如果能…

框架的知识点整理

目录 1、什么是Spring框架&#xff1f;Spring框架有哪些主要模块&#xff1f; 2 、 使用Spring框架有什么好处&#xff1f; 3、Spring MVC 工作原理 1、什么是Spring框架&#xff1f;Spring框架有哪些主要模块&#xff1f; Spring框架是一个开源的轻量级的Java应用程序开…

Spring事务创建与使用

目录 前言Spring中事务的实现声明式事务Transactional 作⽤范围Transactional 参数说明对于事务不回滚的解决方案 前言 在数据库中我们提到了 事务, 事务的定义为, 将一系列操作封装成一个整体去调用 , 要么一起成功, 要么一起失败 Spring中事务的实现 在Spring中事务的操作…

电动汽车市场的减速,正在让小鹏汽车付出代价

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 总结&#xff1a; &#xff08;1&#xff09;由于价格压力上升、竞争加剧和需求减弱&#xff0c;小鹏汽车的交付量出现了明显下滑&#xff0c;6月份的交付量已经同比下降了43%。 &#xff08;2&#xff09;小鹏汽车对2023年…

服务调用---------Ribbon和Feign

目录​​​​​​​ 1、Ribbon 1.1 Ribbon简介 1.2 Ribbon负载均衡 负载均衡原理 负载均衡策略 Ribbon和Nginx的区别 1.3 服务调用和Ribbon负载均衡实现 2、Feign&openFeign 3、Feign支持的配置 日志功能 连接池 feign-api远程包 1、Ribbon 1.1 Ribbon简介 Ribb…

【Vue3+Ts+Vite】配置滚动条样式

一、先看效果 二、直接上代码 <template><div class"main-container"><h1 v-for"index in 50" :key"index">这是home页面</h1></div> </template> <style lang"scss" scoped> .main-conta…

【AI底层逻辑】——篇章5(下):机器学习算法之聚类降维时间序列

续上&#xff1a; 目录 4、聚类 5、降维 6、时间序列 三、无完美算法 往期精彩&#xff1a; 4、聚类 聚类即把相似的东西归在一起&#xff0c;与分类不同的是&#xff0c;聚类要处理的是没有标签的数据集&#xff0c;它根据样本数据的分布特性自动进行归类。 人在认知是…

Flutter 最佳实践和编码准则

Flutter 最佳实践和编码准则 视频 前言 最佳实践是一套既定的准则&#xff0c;可以提高代码质量、可读性和可靠性。它们确保遵循行业标准&#xff0c;鼓励一致性&#xff0c;并促进开发人员之间的合作。通过遵循最佳实践&#xff0c;代码变得更容易理解、修改和调试&#xff…

基于光子实验的指数级加速的量子同态加密理论

前言 量子计算机不仅有望在某些重要任务上超越经典计算机&#xff0c;而且还能保护计算的隐私。例如&#xff0c;盲量子计算协议支持安全委托量子计算&#xff0c;其中客户端可以保护其数据和算法的隐私&#xff0c;不受分配来运行计算的量子服务器的影响。然而&#xff0c;这…

​《吐血整理》进阶系列教程-拿捏Fiddler抓包教程(9)-Fiddler如何设置捕获Https会话​

1.简介 由于近几年来各大网站越来越注重安全性都改成了https协议&#xff0c;不像前十几年前直接是http协议直接裸奔在互联网。还有的小伙伴或者童鞋们按照上一篇宏哥的配置都配置好了&#xff0c;想大展身手抓一下百度的包&#xff0c;结果一试傻眼了&#xff0c;竟然毛都没有…

Selenium+Java环境搭建(测试系列6)

目录 前言&#xff1a; 1.浏览器 1.1下载Chrome浏览器 1.2查看Chrome浏览器版本 1.3下载Chrome浏览器的驱动 2.配置系统环境变量path 3.验证是否成功 4.出现的问题 结束语&#xff1a; 前言&#xff1a; 这节中小编给大家讲解一下有关于Selenium Java环境的搭建&…

数据结构: 线性表(顺序表实现)

文章目录 1. 线性表的定义2. 线性表的顺序表示:顺序表2.1 概念及结构2.2 接口实现2.2.1 顺序表初始化 (SeqListInit)2.2.2 顺序表尾插 (SeqListPushBack)2.2.3 顺序表打印 (SeqListPrint)2.2.6 顺序表销毁 (SeqListDestroy)2.2.5 顺序表尾删 (SeqListPopBack)2.2.6 顺序表头插 …

晋级榜单揭晓!华秋第九届硬创大赛-华南分赛区路演成功举办

7月21日&#xff0c;第十五届深创赛福田预选赛区暨华秋第九届硬创大赛华南分赛区决赛路演活动在深圳华强科创广场成功举办。活动由深圳华秋电子有限公司&#xff08;以下简称 华秋 &#xff09;、深圳市福田区新一代信息技术产业链党委、深圳新一代产业园、微纳研究院、华强科创…

【嵌入式学习笔记】嵌入式入门1——GPIO

1.什么是GPIO General Purpose Input Output&#xff0c;即通用输入输出端口&#xff0c;简称GPIO&#xff0c;作用是负责采集外部器件的信息或者控制外部器件工作&#xff0c;即输入输出。 2.STM32 GPIO简介 2.1.GPIO特点 不同型号&#xff0c;IO口数量可能不一样&#x…

中小学分班查询系统0成本制作方法公布了,人人可用

传统的学生分班查询平台通常需要进行专业的技术开发&#xff0c;以实现学生查询和查看分班信息的功能。这个过程涉及到软件开发、数据库设计、系统集成等多个环节&#xff0c;需要有一支专业的技术团队来完成。 然而&#xff0c;这样的技术开发和维护过程需要耗费大量的经济成…

HBase有写入数据,页面端显示无数据量

写了一个测试类&#xff0c;插入几条数据&#xff0c;测试HBase的数据量。很简单的功能&#xff0c;这就出现问题了。。网页端可以看到&#xff0c;能够看到读写请求&#xff0c;但是不管是内存、还是磁盘&#xff0c;都没有数据。 于是就想到去HDFS查看&#xff0c;也是有数据…

Python简要复习

Python程序设计复习 Python基础知识 python的特点 兼具编译型和解释型特性&#xff0c;兼顾过程式、函数式和面向对象编程范式的通用编程语言 解释型语言无需像编译型需要一次性的编译成机器码&#xff0c;然后运行&#xff0c;而是由名叫解释器的程序动态的将源代码逐句转…

热备份路由协议原理

热备份路由协议原理 HSRP协议/VRRP协议热备份协议 热备份协议&#xff08;Hot Standby Protocol&#xff09; 是一种基于冗余设计的协议&#xff0c;用于提高网络的可靠性和冗余性。它允许多个设备共享同一个IP地址&#xff0c;其中一个设备被选为主设备&#xff0c;其他设备…

Tinkercad 建模21个小技巧

21个Tinkercad 建模小技巧 原文 参考文章&#xff1a;在 Tinkercad 中加快设计的 22 个技巧 一起来了解一下21个Tinkercad 3D建模小技巧&#xff0c;让你快人一步。 技巧1 Copy & Paste 文件&#xff0c;整合设计 想把文件A里面的模型拷贝到文件B里面&#xff1f; 很容…