查找-多路查找详解篇

news2024/10/4 23:43:04

多路查找树

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

红队打靶,红日系列,红日靶场5

文章目录 靶场详情外网渗透端口扫描漏洞发现与利用获取shell 内网渗透提权内网信息收集 横向移动上线msf路由转发与代理通道Psexec 攻击 靶场详情 此次靶场虚拟机共用两个&#xff0c;一个外网一个内网&#xff0c;用来练习红队相关内容和方向&#xff0c;主要包括常规信息收集…

Eurographics 2023最新综述:图形学中的神经-符号模型

随着 CVPR 2023 Best Paper 的公布&#xff0c;其中一篇名为 VISPROG 的工作引起了广泛关注。这项工作利用自然语言指令解决复杂且组合性的视觉任务&#xff0c;重新将神经-符号方法带回了人们的视野&#xff0c;并证明了计算机视觉社区对这种方法的认可。实际上&#xff0c;VI…

Unity自定义后处理——用偏导数求图片颜色边缘

大家好&#xff0c;我是阿赵。   继续介绍屏幕后处理效果的做法。这次介绍一下用偏导数求图形边缘的技术。 一、原理介绍 先来看例子吧。   这个例子看起来好像是要给模型描边。之前其实也介绍过很多描边的方法&#xff0c;比如沿着法线方向放大模型&#xff0c;或者用Ndo…

数据结构和算法——排序算法的比较和排序综测测验

目录 排序算法的比较 排序综合测验 快又稳定 元素错位 有序排序 排序结果 排序算法的比较 排序方法平均时间复杂度最坏情况下时间复杂度额外空间复杂度稳定性简单选择排序不稳定冒泡排序稳定直接插入排序稳定希尔排序不稳定堆排序不稳定快速排序不稳定归并排序稳定基数排…

SCT2632——65V输出3A非同步整流DCDC转换器

SCT2632是一款3A降压转换器&#xff0c;具有宽输入电压&#xff0c;从4.2V到60V&#xff0c;集成了220mΩ高压侧MOSFET。SCT2632采用峰值电流模式控制&#xff0c;支持脉冲跳过调制&#xff08;PSM&#xff09;&#xff0c;以帮助转换器在轻负载或待机状态下实现高效率条件。SC…

矿用人员定位系统在矿山事故预防中的效果评估

矿业行业的高风险和复杂环境使得采矿安全成为一项重要的挑战。为了保障矿工的安全并减少事故风险&#xff0c;矿用人员定位系统成为了关键技术之一。 在这篇文章中&#xff0c;华安联大便和大家各位朋友一起探讨矿用人员定位系统的重要性、工作原理、作用&#xff0c;并通过真…

Packet Tracer - 配置和验证 NTP

Packet Tracer - 配置和验证 NTP 地址分配表 设备 接口 IP 地址 子网掩码 N1 NIC 209.165.200.225 255.255.255.0 R1 G0/0 209.165.200.226 255.255.255.0 R2 G0/0 209.165.200.227 255.255.255.0 目标 在本练习中&#xff0c;您将在 R1 和 R2 中配置 NTP 以…

苍穹外卖day07——缓存菜品套餐+购物车功能实现

缓存菜品——需求设计与分析 问题说明 用户访问量过大带来的一个直接效果就是响应速度慢&#xff0c;使用体验下降。 实现思路 使用redis缓存菜品数据&#xff0c;减少数据库查询操作。 页面展示上基本就是同一个分类在同一页&#xff0c;所以key-value结构可以使用不同的分…

【SQL应知应会】表分区(二)• Oracle版

欢迎来到爱书不爱输的程序猿的博客, 本博客致力于知识分享&#xff0c;与更多的人进行学习交流 本文收录于SQL应知应会专栏,本专栏主要用于记录对于数据库的一些学习&#xff0c;有基础也有进阶&#xff0c;有MySQL也有Oracle 分区表 • Oracle版 前言一、分区表1.什么是表分区…

富文本编辑器wangEditor初探

1、前言 现有的Quill比较简单&#xff0c;无法满足业务需求&#xff08;例如SEO的图片属性编辑需求&#xff09; Quill已经有比较长的时间没有更新了&#xff0c;虽然很灵活&#xff0c;但是官方demo都没有一个。 业务前期也没有这块的需求&#xff0c;也没有考虑到这块的扩展…

如何提高代码效率——时间复杂度与空间复杂度——【C语言】

当我们面对一个问题时&#xff0c;会有许多种解题思路。我们现在的计算机技术已经达到非常先进的地步&#xff0c;所以当我们用不同的方法对待问题时&#xff0c;时间差异不会很明显&#xff0c;内存差异我们一般在平常小问题时感受不到&#xff0c;所以我们不会去纠结程序的优…

基于ssm+mysql+html道路养护管理系统

基于ssmmysqlhtml道路养护管理系统 一、系统介绍二、功能展示1.道路信息管理2.损害类型信息管理3.损害类型信息管理4.评定等级信息管理5.日常巡查信息管理6.定期检查信息管理 四、获取源码 一、系统介绍 系统主要功能&#xff1a;道路信息管理、损害类型信息管理、评定等级信息…

VSCode SSH远程连接与删除

1.ubuntu设置 安装SSH服务并获取远程访问的IP地址 在Ubuntu系统中&#xff0c;“CtrlAltT”打开终端工具&#xff0c;执行如下命令安装SSH服务。 sudo apt-get install openssh-server如果安装失败则先安装依赖项。 2.VS Code 设置 2.1安装与设置Remote SSH 打开Windows系…

今天,我被二维码卷到了...

# 关注并星标腾讯云开发者# 每周4 | 鹅厂一线程序员&#xff0c;为你“试毒”新技术# 第1期 | 腾讯王锐&#xff1a;测评二维码艺术画生成体验 都说AI绘画来势汹汹&#xff0c;但论创意&#xff0c;还是人类玩得花&#x1f92b;。下面这几张乍一看平平无奇、却在网上疯传的AI生…

rcu链表综合实践

基础知识 rcu-read copy update的缩写。和读写锁起到相同的效果。据说牛逼一点。对于我们普通程序员&#xff0c;要先学会使用&#xff0c;再探究其内部原理。 链表的数据结构&#xff1a; struct list_head {struct list_head *next, *prev; };还有一种&#xff1a;struct h…

自建纯内网iot平台服务,软硬件服务器全栈实践

基于以下几个考虑&#xff0c;自制硬件设备&#xff0c;mqtt内网服务器。 1.米家app不稳定&#xff0c;逻辑在云端或xiaomi中枢网关只支持少部分在本地计算。 2.监控homeassistant官方服务有大量数据交互。可能与hass安装小米账户有关。 3.硬件&#xff1a;原理图&#xff0c;l…

apifox 调用camunda engine-rest接口报错“type“: “NotFoundException“

官方文档在这&#xff1a; https://docs.camunda.org/rest/camunda-bpm-platform/7.19/ 现象 engine-rest本是可以直接请求的&#xff0c;我把openapi导入到apifox之中了&#xff0c;我测试一下接口没有能请求成功的&#xff0c;基本都报以下的错。 报错如下 {"type&qu…

【iOS】Frame与Bounds的区别详解

iOS的坐标系 iOS特有的坐标是&#xff0c;是在iOS坐标系的左上角为坐标原点&#xff0c;往右为X正方向&#xff0c;向下为Y正方向。 bounds和frame都是属于CGRect类型的结构体&#xff0c;系统的定义如下&#xff0c;包含一个CGPoint&#xff08;起点&#xff09;和一个CGSiz…

《向量数据库指南》:向量数据库Pinecone如何集成Haystack库

目录 安装Haystack库 初始化PineconeDocumentStore 数据准备 初始化检索器 检查文档和嵌入 初始化提取式问答管道 提问 在这个指南中,我们将看到如何集成Pinecone和流行的Haystack库进行问答。 安装Haystack库 我们首先安装最新版本的Haystack,其中包括PineconeDocum…

【爬虫案例】用Python爬取iPhone14的电商平台评论

用python爬取某电商网站的iPhone14评论数据&#xff0c; 爬取目标&#xff1a; 核心代码如下&#xff1a; 爬取到的5分好评&#xff1a; 爬取到的3分中评&#xff1a; 爬取到的1分差评&#xff1a; 所以说&#xff0c;用python开发爬虫真的很方面&#xff01; 您好&…