【数据结构6】AVL树、AVL树的旋转-左旋和右旋、二叉搜索树的扩展应用-B树(B-Tree)、B+树

news2024/11/14 21:24:35

1 AVL树
2 AVL树的旋转-左旋和右旋
2.1 AVL树的旋转实现
3 二叉搜索树的扩展应用-B树
3.2 B+树

1 AVL树

AVL树:AVL树是一棵自平衡的二叉搜索树。

AVL树具有以下性质:
	根的左右子树的高度之差的绝对值不能超过1
	根的左右子树都是平衡二叉树

平均情况下,二叉搜索树进行搜索的时间复杂度为O(lgn)。
最坏情况下,二又搜索树可能非常偏斜。

解决方案:
	1 随机化插入
	2 D AVL树

在这里插入图片描述

2 AVL树的旋转-左旋和右旋

1 插入一个节点可能会破坏AVL树的平衡,可以通过"旋转"操作来进行修正
2 插入一个节点后,只有从插入节点到根节点的路上的节点的平衡可能被改变。
	需要找出第一个破坏了平衡条件的节点,称之为K。K的两颗子树的高度差23 不平衡的出现可能有4种情况

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2.1 AVL树的旋转实现

class BiTreeNode:
    def __init__(self, data):
        """
        初始化二叉树节点
        :param data: 节点的值
        """
        self.data = data  # 节点的值
        self.lchild = None  # 左子节点
        self.rchild = None  # 右子节点
        self.parent = None  # 父节点


class BST:
    def __init__(self, li: list):
        """
        初始化二叉搜索树,并插入给定的值
        :param li: 包含插入值的列表
        """
        self.root = None  # 初始化根节点为空
        if li:
            for val in li:
                self.insert_no_rec(val)  # 使用非递归插入方法将列表中的值插入树中

    def insert_no_rec(self, val):
        """
        非递归插入节点到二叉搜索树中
        :param val: 要插入的值
        :return: None
        """
        p = self.root
        if not p:
            # 如果树为空,将新节点设置为根节点
            self.root = BiTreeNode(val)
            return
        while True:
            if val < p.data:
                # 如果要插入的值小于当前节点的值,则移动到左子树
                if p.lchild:
                    p = p.lchild
                else:
                    # 如果左子树为空,则在此位置插入新节点
                    p.lchild = BiTreeNode(val)
                    p.lchild.parent = p  # 更新新节点的父节点
                    return
            elif val > p.data:
                # 如果要插入的值大于当前节点的值,则移动到右子树
                if p.rchild:
                    p = p.rchild
                else:
                    # 如果右子树为空,则在此位置插入新节点
                    p.rchild = BiTreeNode(val)
                    p.rchild.parent = p  # 更新新节点的父节点
                    return
            else:
                # 如果要插入的值等于当前节点的值,则不做任何操作(BST中不允许重复值)
                return

    def query_no_rec(self, val):
        """
        非递归查询二叉搜索树中的节点
        :param val: 要查询的值
        :return: 节点对象(如果找到)或 None(如果未找到)
        """
        p = self.root
        while p:
            if p.data < val:
                # 如果当前节点的值小于要查询的值,则移动到右子树
                p = p.rchild
            elif p.data > val:
                # 如果当前节点的值大于要查询的值,则移动到左子树
                p = p.lchild
            else:
                # 如果当前节点的值等于要查询的值,返回当前节点
                return p
        # 如果遍历结束仍未找到值,返回 None
        return None

    def pre_order(self, root):
        """
        二叉树的前序遍历
        :param root:
        :return:
        """
        if root:
            print(root.data, end=',')
            self.pre_order(root.lchild)
            self.pre_order(root.rchild)

    def mid_order(self, root):
        """
        二叉树的中序遍历
        :param root:
        :return:
        """
        if root:
            self.mid_order(root.lchild)
            print(root.data, end=',')
            self.mid_order(root.rchild)

    def post_order(self, root):
        """
        二叉树的后序遍历
        :param root:
        :return:
        """
        if root:
            self.post_order(root.lchild)
            self.post_order(root.rchild)
            print(root.data, end=',')


class AVLNode(BiTreeNode):
    def __init__(self, data):
        BiTreeNode.__init__(self, data)
        self.bf = 0  # balance_factor


class AVLTree(BST):
    def __init__(self, li: list = None):
        BST.__init__(self, li)

    def insert_no_rec(self, val):
        """
        插入节点到二叉搜索树中
        :param val: 要插入的值
        :return: None
        """
        # 1.插入节点
        p = self.root
        if not p:
            # 如果树为空,将新节点设置为根节点
            self.root = AVLNode(val)
            return
        while True:
            if val < p.data:
                # 如果要插入的值小于当前节点的值,则移动到左子树
                if p.lchild:
                    p = p.lchild
                else:
                    # 如果左子树为空,则在此位置插入新节点
                    p.lchild = AVLNode(val)
                    p.lchild.parent = p  # 更新新节点的父节点
                    node = p.lchild  # node 存储的就是插入的节点
                    break
            elif val > p.data:
                # 如果要插入的值大于当前节点的值,则移动到右子树
                if p.rchild:
                    p = p.rchild
                else:
                    # 如果右子树为空,则在此位置插入新节点
                    p.rchild = AVLNode(val)
                    p.rchild.parent = p  # 更新新节点的父节点
                    node = p.rchild
                    break
            else:  # val = p.data
                # 如果要插入的值等于当前节点的值,则不做任何操作(BST中不允许重复值)
                return
        # 2.更新balance factor
        while node.parent:  # node.parent不为空
            if node.parent.lchild == node:  # 传递是从左子树来的,左子树更沉了
                # 更新node.parent的bf -= 1
                if node.parent.bf < 0:  # 原来的node.parent.bf == -1,更新变成-2
                    # 做旋转
                    # 看node哪边沉
                    g = node.parent.parent  # 为了连接旋转之后的子树
                    x = node.parent  # 旋转前的子树的根
                    if node.bf > 0:  # 右边沉
                        n = self.rotate_left_right(node.parent, node)
                    else:  # 左边沉
                        n = self.rotate_right(node.parent, node)
                    # 记得把n和g连起来
                elif node.parent.bf > 0:  # 原来node.parent.bf = 1,更新之后变成0
                    node.parent.bf = 0
                    break
                else:  # 原来的node.parent.bf = 0,更新之后变成-1
                    node.parent.bf = -1
                    node = node.parent
                    continue
            else:  # 传递是从右子树来的,右子树更沉了
                # 更新node.parent.bf+=1
                if node.parent.bf > 0:  # 原来node.parent.bf = 1,更新之后变成2
                    # 做旋转
                    # 看哪边沉
                    g = node.parent.parent  # 为了连接旋转之后的子树
                    x = node.parent  # 旋转前的子树的根
                    if node.bf < 0:  # 左边沉
                        n = self.rotate_right_left(node.parent, node)
                    else:  # 右边沉
                        n = self.rotate_left(node.parent, node)
                    # 记得把n和g连起来
                elif node.parent.bf < 0:  # 原来node.parent.bf = -1,更新之后变成0
                    node.parent.bf = 0
                    break
                else:  # 原来node.parent.bf = 0,更新之后变成1
                    node.parent.bf = 1
                    node = node.parent
                    continue
            # 连接旋转后的子树,把n和g连起来
            n.parent = g
            if g:  # g不是空
                if x == g.lchild:
                    g.lchild = n
                else:
                    g.rchild = n
                break
            else:
                self.root = n
                break

    def rotate_left(self, p, c):
        """
        左旋操作
        :param p: 当前节点 p(旋转前的根节点)
        :param c: 右孩子节点 c(旋转后的新根节点)
        :return: 新的子树根节点 c
        """
        s2 = c.lchild  # s2 是 c 的左孩子
        p.rchild = s2  # p 的右孩子指向 s2
        if s2:
            s2.parent = p  # 如果 s2 存在,更新 s2 的父节点为 p
        c.lchild = p  # c 的左孩子指向 p
        p.parent = c  # 更新 p 的父节点为 c

        # 更新平衡因子
        p.bf = 0
        c.bf = 0
        return c  # 返回新的根节点 c

    def rotate_right(self, p, c):
        """
        右旋操作
        :param p: 当前节点 p(旋转前的根节点)
        :param c: 左孩子节点 c(旋转后的新根节点)
        :return: 新的子树根节点 c
        """
        s2 = c.rchild  # s2 是 c 的右孩子
        p.lchild = s2  # p 的左孩子指向 s2
        if s2:
            s2.parent = p  # 如果 s2 存在,更新 s2 的父节点为 p

        c.rchild = p  # c 的右孩子指向 p
        p.parent = c  # 更新 p 的父节点为 c

        # 更新平衡因子
        p.bf = 0
        c.bf = 0
        return c  # 返回新的根节点 c

    def rotate_right_left(self, p, c):
        """
        右旋-左旋复合操作
        :param p: 当前节点 p(旋转前的根节点)
        :param c: 右孩子节点 c(旋转前的右孩子)
        :return: 新的子树根节点 g(旋转后的新根节点)
        """
        g = c.lchild  # g 是 c 的左孩子(旋转后的新根节点)

        s3 = g.rchild  # s3 是 g 的右孩子
        c.lchild = s3  # c 的左孩子指向 s3
        if s3:
            s3.parent = c  # 如果 s3 存在,更新 s3 的父节点为 c

        g.rchild = c  # g 的右孩子指向 c
        c.parent = g  # 更新 c 的父节点为 g

        s2 = g.lchild  # s2 是 g 的左孩子
        p.rchild = s2  # p 的右孩子指向 s2
        if s2:
            s2.parent = p  # 如果 s2 存在,更新 s2 的父节点为 p

        g.lchild = p  # g 的左孩子指向 p
        p.parent = g  # 更新 p 的父节点为 g

        # 更新平衡因子
        if g.bf > 0:
            p.bf = -1
            c.bf = 0
        elif g.bf < 0:
            p.bf = 0
            c.bf = 1
        else:
            p.bf = 0
            c.bf = 0
        g.bf = 0
        return g  # 返回新的根节点 g

    def rotate_left_right(self, p, c):
        """
        左旋-右旋复合操作
        :param p: 当前节点 p(旋转前的根节点)
        :param c: 左孩子节点 c(旋转前的左孩子)
        :return: 新的子树根节点 g(旋转后的新根节点)
        """
        g = c.rchild  # g 是 c 的右孩子(旋转后的新根节点)

        s2 = g.lchild  # s2 是 g 的左孩子
        c.rchild = s2  # c 的右孩子指向 s2
        if s2:
            s2.parent = c  # 如果 s2 存在,更新 s2 的父节点为 c

        g.lchild = c  # g 的左孩子指向 c
        c.parent = g  # 更新 c 的父节点为 g

        s3 = g.rchild  # s3 是 g 的右孩子
        p.lchild = s3  # p 的左孩子指向 s3
        if s3:
            s3.parent = p  # 如果 s3 存在,更新 s3 的父节点为 p

        g.rchild = p  # g 的右孩子指向 p
        p.parent = g  # 更新 p 的父节点为 g

        # 更新平衡因子
        if g.bf < 0:
            p.bf = 1
            c.bf = 0
        elif g.bf > 0:
            p.bf = 0
            c.bf = -1
        else:
            p.bf = 0
            c.bf = 0
        g.bf = 0
        return g  # 返回新的根节点 g


tree = AVLTree([9, 8, 7, 6, 10, 5, 4, 3, 2, 1])
tree.pre_order(tree.root)
print('')
tree.mid_order(tree.root)

执行结果:
8,4,2,1,3,6,5,7,9,10,
1,2,3,4,5,6,7,8,9,10,

3 二叉搜索树的扩展应用-B树

"B树(B-Tree): B树是一棵自平衡的多路搜索树。常用于数据库的索引。"

B-Tree(B树)是一种自平衡的树数据结构,它可以保持数据有序,并允许二分查找、顺序访问、插入和删除。
B树广泛用于数据库和文件系统的实现中,因为它能够很好地管理大量数据,并且可以有效地减少磁盘I/O操作。

B-Tree的特点:
1 节点:每个节点可以包含多个键(数据),而不是像二叉树那样每个节点只包含一个键。
2 有序性:在每个节点中,键是按照非递减顺序排列的。
3 孩子节点数量:一个节点有 m 个孩子,则节点中最多有 m-1 个键。
	B树的阶数 m 决定了节点的最小和最大子节点数量。
4 平衡性:B树是自平衡的,所有叶子节点都位于同一层,保证了查找、插入和删除操作的效率。

B-Tree的性质:
1 一个B树的节点包含至多 m-1 个键(数据),和至多 m 个子树。
2 如果根节点不是叶子节点,则根节点至少有两棵子树。
3 每个内部节点至少包含 ⌈m/2- 1 个键和 ⌈m/2⌉ 个子树。
4 所有叶子节点都在同一层。

B-Tree的插入和删除:
1 插入:
	1 从根节点开始,递归找到应插入的叶子节点。
	2 如果叶子节点未满,则直接插入。
	3 如果叶子节点已满,则需要将该节点分裂成两个节点,并将中间键提升到父节点。
	  若父节点也满,则继续向上分裂,直到根节点。

2 删除:
	1 如果删除的是叶子节点中的键且节点中的键数大于最小值,则直接删除。
	2 如果删除的键在内部节点,需要选择合适的替代键(例如前驱或后继),然后递归删除该键。
	3 如果节点在删除后键数不足,则需要进行合并或从兄弟节点借键。

在这里插入图片描述

class BTreeNode:
    def __init__(self, leaf=False):
        """
        初始化B树节点。
        :param leaf: 布尔值,表示该节点是否为叶子节点。如果为True,则该节点是叶子节点。
        """
        self.leaf = leaf  # 是否为叶子节点
        self.keys = []  # 节点中存储的键值列表
        self.children = []  # 子节点列表,存储指向子节点的引用

class BTree:
    def __init__(self, t):
        """
        初始化B树。
        :param t: B树的最小度数,表示每个节点中最少包含t-1个键,最多包含2t-1个键。
        """
        self.root = BTreeNode(True)  # 创建B树的根节点,初始时默认为叶子节点
        self.t = t  # 最小度数

    def insert(self, k):
        """
        插入键值k到B树中。
        :param k: 要插入的键值。
        """
        root = self.root
        # 如果根节点已满,需要分裂
        if len(root.keys) == (2 * self.t) - 1:
            # 创建一个新的根节点,并设置它为非叶子节点
            temp = BTreeNode()
            # 将旧的根节点作为子节点挂载到新的根节点
            self.root = temp
            temp.children.append(root)
            # 分裂旧的根节点
            self._split_child(temp, 0)
            # 将键值插入到适当的位置
            self._insert_non_full(temp, k)
        else:
            # 如果根节点未满,直接插入
            self._insert_non_full(root, k)

    def _split_child(self, x, i):
        """
        分裂子节点。假设x是一个非满节点,且x的第i个子节点是满的。
        :param x: 需要分裂的节点的父节点。
        :param i: 需要分裂的子节点在父节点子节点列表中的索引。
        """
        t = self.t
        # 获取需要分裂的子节点
        y = x.children[i]
        # 创建一个新的节点z来存储y的后半部分键值和子节点
        z = BTreeNode(y.leaf)
        # 将z插入到x的子节点列表中
        x.children.insert(i + 1, z)
        # 将y的中间键值提升到x中
        x.keys.insert(i, y.keys[t - 1])
        # 将y的后半部分键值移动到z中
        z.keys = y.keys[t:(2 * t) - 1]
        # 将y的前半部分键值保留在y中
        y.keys = y.keys[0:t - 1]
        # 如果y不是叶子节点,将它的后半部分子节点也移动到z中
        if not y.leaf:
            z.children = y.children[t:(2 * t)]
            y.children = y.children[0:t]

    def _insert_non_full(self, x, k):
        """
        在非满节点中插入键值k。
        :param x: 当前节点。
        :param k: 要插入的键值。
        """
        i = len(x.keys) - 1
        if x.leaf:
            # 如果是叶子节点,直接在合适位置插入键值
            x.keys.append(None)
            while i >= 0 and k < x.keys[i]:
                x.keys[i + 1] = x.keys[i]
                i -= 1
            x.keys[i + 1] = k
        else:
            # 如果不是叶子节点,找到合适的子节点进行递归插入
            while i >= 0 and k < x.keys[i]:
                i -= 1
            i += 1
            # 如果子节点已满,先分裂子节点
            if len(x.children[i].keys) == (2 * self.t) - 1:
                self._split_child(x, i)
                # 如果新插入的键值大于分裂后的中间键值,则移到右边的子节点进行插入
                if k > x.keys[i]:
                    i += 1
            self._insert_non_full(x.children[i], k)

    def search(self, k, x=None):
        """
        在B树中查找键值k。
        :param k: 要查找的键值。
        :param x: 当前节点,默认为None表示从根节点开始查找。
        :return: 如果找到返回包含键值k的节点和索引,否则返回None。
        """
        if x is not None:
            i = 0
            # 找到第一个大于或等于k的位置
            while i < len(x.keys) and k > x.keys[i]:
                i += 1
            # 如果找到k,返回当前节点和索引
            if i < len(x.keys) and k == x.keys[i]:
                return (x, i)
            # 如果当前节点是叶子节点且没有找到,返回None
            elif x.leaf:
                return None
            else:
                # 否则递归到适当的子节点继续查找
                return self.search(k, x.children[i])
        else:
            # 如果x为None,从根节点开始查找
            return self.search(k, self.root)

    def print_tree(self, x, l=0):
        """
        打印B树结构。
        :param x: 当前节点。
        :param l: 当前节点的层级,用于格式化输出。
        """
        print("Level", l, " ", len(x.keys), end=": ")
        for i in x.keys:
            print(i, end=" ")
        print()
        l += 1
        # 递归打印每个子节点
        if len(x.children) > 0:
            for i in x.children:
                self.print_tree(i, l)

# 示例使用:
btree = BTree(3)  # 创建最小度数为3的B树
data = [10, 20, 5, 6, 12, 30, 7, 17]  # 要插入的键值列表
for item in data:
    btree.insert(item)  # 将键值逐个插入B树

btree.print_tree(btree.root)  # 打印B树的结构

在这里插入图片描述

3.2 B+树

B+树 是 B树 的一种扩展版本,主要用于数据库和文件系统中的索引结构。

与 B树 相比,B+树 有以下几个显著特点:
1 所有的键值都存在叶子节点:
	在 B+树 中,所有的数据记录都存储在叶子节点中,而内部节点仅存储索引键值,用于指引搜索路径。
2 链表结构的叶子节点:
	B+树 的所有叶子节点通过一个链表连接起来,便于范围查询的实现。
	这样可以很方便地遍历数据范围,而不需要重新从根节点开始查找。
3内部节点的键值用于索引:
	B+树 的内部节点存储的是子树中最小键值的副本,而不包含指向具体记录的指针。

在这里插入图片描述

class BPlusTreeNode:
    def __init__(self, leaf=False):
        """
        初始化B+树节点。
        :param leaf: 布尔值,表示该节点是否为叶子节点。
        """
        self.leaf = leaf  # 是否为叶子节点
        self.keys = []  # 节点中存储的键值列表
        self.children = []  # 子节点列表或叶子节点中的数据记录指针
        self.next = None  # 指向下一个叶子节点的指针(仅在叶子节点中使用)

class BPlusTree:
    def __init__(self, t):
        """
        初始化B+树。
        :param t: B+树的最小度数,表示每个节点中最少包含t-1个键,最多包含2t-1个键。
        """
        self.root = BPlusTreeNode(True)  # 创建B+树的根节点,初始时默认为叶子节点
        self.t = t  # 最小度数

    def insert(self, k):
        """
        插入键值k到B+树中。
        :param k: 要插入的键值。
        """
        root = self.root
        if len(root.keys) == (2 * self.t) - 1:  # 根节点已满,需要分裂
            temp = BPlusTreeNode()  # 创建新的根节点
            self.root = temp  # 更新根节点
            temp.children.append(root)  # 原来的根节点成为新根节点的子节点
            self._split_child(temp, 0)  # 分裂根节点的子节点
            self._insert_non_full(temp, k)  # 插入键值到新的根节点
        else:
            self._insert_non_full(root, k)  # 插入键值到非满节点

    def _split_child(self, x, i):
        """
        分裂子节点。假设x是一个非满节点,且x的第i个子节点是满的。
        :param x: 需要分裂的节点的父节点。
        :param i: 需要分裂的子节点在父节点子节点列表中的索引。
        """
        t = self.t
        y = x.children[i]  # 要分裂的子节点
        z = BPlusTreeNode(y.leaf)  # 新建一个节点z用于存储分裂出的部分

        # 在x中插入新节点z,并在x的keys中插入分裂点的中间键
        x.children.insert(i + 1, z)
        x.keys.insert(i, y.keys[t - 1])

        # 将y中大于等于中间键的键和值分裂到z中
        z.keys = y.keys[t:]
        y.keys = y.keys[:t - 1]

        if y.leaf:
            z.children = y.children[t:]  # 如果y是叶子节点,复制y的部分数据到z
            y.children = y.children[:t]
            z.next = y.next  # 更新叶子节点链表的链接
            y.next = z
        else:
            z.children = y.children[t:]  # 如果y不是叶子节点,复制y的部分子节点到z
            y.children = y.children[:t]

    def _insert_non_full(self, x, k):
        """
        在非满节点中插入键值k。
        :param x: 当前节点。
        :param k: 要插入的键值。
        """
        i = len(x.keys) - 1  # 找到要插入的位置

        if x.leaf:  # 如果是叶子节点,直接插入
            x.keys.append(None)  # 占位
            while i >= 0 and k < x.keys[i]:
                x.keys[i + 1] = x.keys[i]  # 依次后移,腾出插入位置
                i -= 1
            x.keys[i + 1] = k  # 插入键值
        else:  # 如果不是叶子节点,需要递归插入到合适的子节点中
            while i >= 0 and k < x.keys[i]:
                i -= 1
            i += 1
            if len(x.children[i].keys) == (2 * self.t) - 1:  # 如果子节点已满,先分裂
                self._split_child(x, i)
                if k > x.keys[i]:  # 如果k大于分裂出的中间键,插入到右侧的子节点
                    i += 1
            self._insert_non_full(x.children[i], k)  # 递归插入到子节点

    def search(self, k, x=None):
        """
        在B+树中查找键值k。
        :param k: 要查找的键值。
        :param x: 当前节点,默认为None表示从根节点开始查找。
        :return: 如果找到返回包含键值k的叶子节点,否则返回None。
        """
        if x is not None:  # 如果指定了节点,从该节点开始查找
            i = 0
            while i < len(x.keys) and k > x.keys[i]:  # 找到大于等于k的位置
                i += 1
            if i < len(x.keys) and k == x.keys[i] and x.leaf:  # 如果在叶子节点中找到k
                return x  # 返回该叶子节点
            elif x.leaf:  # 如果在叶子节点中未找到k
                return None  # 查找失败
            else:  # 如果是内部节点,递归查找合适的子节点
                return self.search(k, x.children[i])
        else:  # 如果未指定节点,从根节点开始查找
            return self.search(k, self.root)

    def print_tree(self, x, l=0):
        """
        打印B+树结构。
        :param x: 当前节点。
        :param l: 当前节点的层级,用于格式化输出。
        """
        print("Level", l, " ", len(x.keys), end=": ")  # 输出当前节点的层级和键值数量
        for i in x.keys:  # 输出当前节点的所有键值
            print(i, end=" ")
        print()
        l += 1
        if len(x.children) > 0:  # 如果有子节点,递归打印子节点
            for i in x.children:
                self.print_tree(i, l)


# 示例使用:
btree = BPlusTree(3)  # 创建一个B+树,最小度数为3
data = [10, 20, 5, 6, 12, 30, 7, 17]  # 要插入的数据列表
for item in data:  # 逐个插入数据
    btree.insert(item)

btree.print_tree(btree.root)  # 打印B+树结构

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

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

相关文章

基于.net的外卖点单系统的设计与实现/基于asp.net的外卖系统

基于.net的外卖点单系统的设计与实现 摘 要 国内餐饮行业的快速发展&#xff0c;人们为了能够更加方便地管理用户点单&#xff0c;外卖点单系统被人们开发出来从而更好地方便管理用户点单&#xff0c;一个完美的外卖点单系统已经成为各个餐饮店的追求目标。 本系统asp.net利用…

ssrf攻击fastcgi复现

文章目录 环境搭建使用网页查看开始攻击 环境搭建 在/usr/local/nginx/html下新建一个php文件 phpinfo.php 1.php <?php highlight_file(__FILE__); $url $_GET[url]; $curl curl_init($url); curl_setopt($curl, CURLOPT_HEADER, 0); $responseText curl_exec($curl)…

Transformer模型中的PositionEmbedding实现:让你的NLP项目飞起来!

在自然语言处理的海洋中&#xff0c;Transformer模型如同一艘巨轮&#xff0c;承载着对文本理解和生成的无限可能。 然而&#xff0c;即使是最强大的模型&#xff0c;也需借助一些关键组件来达到其最佳性能。 其中&#xff0c;PositionEmbedding便是这样一把钥匙&#xff0c;…

BUG——GT911上电后中断一直触发

版型&#xff1a;正点原子 I.MX6UL MINI板 屏幕&#xff1a;7寸 1024*600 ATK-MD0700R V1.4 我的建议是买7寸屏幕就不要Mini板&#xff0c;因为Mini板太小装不下7寸屏幕&#xff0c;你需要一个更大的板子 简介&#xff1a; 算是作为一个后来者对这一现象的补充。解决方案就…

如何使用ssm实现开放式教学评价管理系统+vue

TOC ssm121开放式教学评价管理系统vue 第1章 绪论 1.1 背景及意义 系统管理也都将通过计算机进行整体智能化操作&#xff0c;对于开放式教学评价管理系统所牵扯的管理及数据保存都是非常多的&#xff0c;例如个人中心、教师管理、学生管理、游客管理、评价信息管理、综合评…

如何系统化的学习 Redis?

搭建完整的知识框架和架构体系 张无剑&#xff1a;恭喜码哥&#xff0c;恭喜靓仔&#xff0c;网络资料很多&#xff0c;但碎片化严重&#xff0c;我如何才能成为 Redis 高手&#xff0c;建立完整的知识框架&#xff1f; Redis 是广受欢迎的 NoSQL 数据库&#xff0c;唯快不破是…

class_4:条件语句和逻辑运算符

mood_index int(input("对象今天的心情怎么样&#xff01;"))if mood_index > 80:print("今天可以好好happy一下了")print("O(∩_∩)O哈哈~") else:print("今天还是乖乖的吧&#xff01;否则小命不保") #BMI 体重 /&#xff08;身…

热血传奇经典1.85原始珍藏版单机安装教程+GM+假人+无需虚拟机

今天给大家带来一款单机游戏的架设&#xff1a;热血传奇经典1.85原始珍藏版。 另外&#xff1a;本人承接各种游戏架设&#xff08;单机联网&#xff09; 本人为了学习和研究软件内含的设计思想和原理&#xff0c;带了架设教程仅供娱乐。 教程是本人亲自搭建成功的&#xff0…

编程之路:在Bug的迷宫中寻找出口

编程是一种艺术&#xff0c;也是一种科学。它要求我们既要有创造性的思维&#xff0c;又要有严谨的逻辑。在这条充满挑战的道路上&#xff0c;每个人都会遇到挫折&#xff0c;这些挫折可能来自于一个难以解决的Bug&#xff0c;一个复杂的算法&#xff0c;或者是在实现某个功能时…

UDS诊断系列之十九 读取故障码(DTC)

一、读取符合条件的DTC数量 通过调用19服务的01子功能&#xff0c;我们可以轻松地读取符合特定条件的故障码数量。重要的是要意识到&#xff0c;此功能仅提供故障码的数量&#xff0c;而不包含任何额外的信息。这意味着&#xff0c;虽然你可以获得故障码的总数&#xff0c;但不…

【SQL】关注者数量

目录 题目 分析 代码 题目 表&#xff1a; Followers ------------------- | Column Name | Type | ------------------- | user_id | int | | follower_id | int | ------------------- (user_id, follower_id) 是这个表的主键&#xff08;具有唯一值的列的组合&am…

Global Context Vision Transformers

摘要 https://arxiv.org/pdf/2206.09959 我们提出了全局上下文视觉转换器&#xff08;GC ViT&#xff09;&#xff0c;这是一种新颖的架构&#xff0c;旨在提高计算机视觉中的参数和计算利用率。我们的方法利用全局上下文自注意力模块与标准的局部自注意力相结合&#xff0c;以…

通信协议学习:CAN总线协议

以下的学习主要是观看江科大视频后的总结&#xff0c;需要学习建议观看原视频&#xff1a;https://www.bilibili.com/video/BV1vu4m1F7Gt/?p1&spm_id_frompageDriver&vd_source0a52d160c212359f7f490eb9a868d174 CAN总线简介 CAN总线&#xff08;Controller Area Net…

selenium-java实现自动登录跳转页面

如果要一直刷新一个网页&#xff0c;总不能人工一直去点&#xff0c;所以想到大学时候学过selenium技术&#xff0c;写个脚本来一直刷新&#xff0c;因为经常写java语言&#xff0c;所以选用java语言来写 实验环境 注意&#xff0c;需要先准备好Google浏览器和Chrome-Driver驱…

mysql高可用之组复制 (MGR)

目录 1 MySQL的主从复制介绍 2 组复制流程 3 组复制单主和多主模式 3.1 single-primary mode(单写或单主模式) 3.2 multi-primary mode(多写或多主模式) 4 实现mysql组复制 4.1 MASTER 1 4.2 MASTER 2 4.3 MASTER 3 4.4 MASTER 1 检验 1 MySQL的主从复制介绍 MySQL Group Rep…

终端防火墙软件哪个好?2024年内网安全解决方案!

在2024年选择终端防火墙软件时&#xff0c;需要考虑多个因素&#xff0c;包括软件的防护能力、兼容性、管理便捷性、性能影响以及更新与维护等。 以下是一些在当前市场上表现优异的终端防火墙软件推荐&#xff0c;它们均能提供有效的内网安全解决方案&#xff1a; 1. 安企神 …

在HFSS中依据厂家模型自己进行连接器仿真---以SMP接口为例

在HFSS中依据厂家模型自己进行连接器仿真—以SMP接口为例 HFSS工程下载链接&#xff1a;在HFSS中依据厂家模型自己进行连接器仿真-以SMP接口为例-HFSS工程文件 在其他软件中仿真时&#xff0c;例如ADS、AWR等等&#xff0c;往往无法对连接头进行仿真。在HFSS中&#xff0c;我…

stm32f1xx中的几个ID

目录 一、ID的作用二、ID的说明产品唯一身份标识MCU ID codeJTAG IDJEDEC-106 ID 三、自定义ID 一、ID的作用 在物联网系统中产品的ID不可或缺&#xff0c;产品组网后就需要一个身份去让网里其它的设备去识别自己&#xff1b; ID表示的含义可能多种多样&#xff0c;如一个生产批…

一种多策略改进飞蛾扑火智能优化算法IMFO 种群初始化精英反向策略+柯西变异策略

一种多策略改进飞蛾扑火智能优化算法IMFO 种群初始化精英反向策略柯西变异策略 文章目录 前言一种多策略改进飞蛾扑火智能优化算法IMFO 种群初始化精英反向策略柯西变异策略 一、MFO飞蛾扑火算法基本原理二、改进飞蛾扑火算法IMFO改进1&#xff1a;种群初始化精英反向策略改进2…

车辆分类检测数据集数据集

车辆分类检测数据集 数据集中的所有车辆分为六类:客车、微型客车、小型货车、轿车、SUV和卡车。每种车型的车辆数量分别为558辆、883辆、476辆、5922辆、1392辆、822辆。 xml标签 数据集描述&#xff1a; 该数据集包含多种类型的车辆图像&#xff0c;旨在用于训练和评估车辆分…