数据结构-非线性结构-二叉树

news2025/5/9 19:11:32

概述

/**

 * 术语

 * 根节点(root node):位于二叉树顶层的节点,没有父节点。

 * 叶节点(leaf node):没有子节点的节点,其两个指针均指向 None 。

 * 边(edge):连接两个节点的线段,即节点引用(指针)。

 * 节点所在的层(level):从顶至底递增,根节点所在层为 1 。

 * 节点的度(degree):节点的子节点的数量。在二叉树中,度的取值范围是 0、1、2 。

 * 二叉树的高度(height):从根节点到最远叶节点所经过的边的数量。

 * 节点的深度(depth):从根节点到该节点所经过的边的数量。

 * 节点的高度(height):从距离该节点最远的叶节点到该节点所经过的边的数量。

 */

/**

 * 二叉树遍历:【前序、中序、后序】->【递归遍历实现、非递归遍历实现(栈实现)】、层次遍历(队列实现)

 * 二叉查找树:具有性质如下的二叉树:对于任一结点,如果它包含的数据元素为data,

 *     那么它的左子树(如果非空)只包含小于data的元素,并且它的右子树(如果非空)只包含大于或等于data的元素。

 *     中序遍历二叉查找树将会得到从小到大排列的结点序列。

 * 二叉线索树:通过利用原本指向空子节点(即 NULL 指针)的空间来指向前驱或后继节点,从而在遍历时不需要使用额外的栈或递归。

 *     这种结构特别适用于那些需要频繁遍历而修改较少的应用场景。

 * 平衡二叉树:AVL树、红黑树

 *     关键特性:左右子树高度差的绝对值不超过1

 * 完全二叉树:主要用于实现堆(最大堆、最小堆)、哈夫曼编码

 *     关键特性:按层次填充,每一层(除了最后一层)都完全填满,最后一层从左到右依次填充,没有间断

 * 满二叉树:一种特殊的二叉树,每一层的节点都完全填满的二叉树

 */

/**

 * 递归遍历

 * 前序遍历:访问顺序为“根-左-右”。即先访问根节点,然后依次递归遍历左子树和右子树。

 * 中序遍历:访问顺序为“左-根-右”。即先递归遍历左子树,然后访问根节点,最后递归遍历右子树。

 * 后序遍历:访问顺序为“左-右-根”。即先递归遍历左子树,然后递归遍历右子树,最后访问根节点。

 */

/**

 * 红黑树

 * 红黑树的一些基本特性和规则:

 * 每个节点要么是红色,要么是黑色。

 * 根节点是黑色。

 * 所有叶子节点(NIL节点,通常不显示在图中)都是黑色的。

 * 如果一个节点是红色,则它的两个子节点都是黑色(即不能有两个连续的红色节点)。

 * 从任一节点到其每个叶子的所有路径都包含相同数量的黑色节点。

 */

 // 难点:遍历、旋转、删除

common.h

#pragma once

#define TRUE 1
#define FALSE 0

// 定义节点数据类型
#define DATA_TYPE int

二叉树插入、删除、递归遍历

BinaryTree.h

#pragma once

#include "common.h"

typedef struct Node
{
    DATA_TYPE data;
    struct Node *left;
    struct Node *right;
} Node;

// 创建一个树结点
static Node *newBinaryTreeNode(DATA_TYPE data)
{
    Node *node = malloc(sizeof(Node));
    node->data = data;
    node->left = NULL;
    node->right = NULL;
    return node;
}

// 旋转节点使二叉树平衡
Node *rotate(Node *node);

// 向二叉树插入数据 平衡化重构
Node *insertNode(Node *T, DATA_TYPE data); // 递归

void insertNode_root(DATA_TYPE data); // 插入、从root开始
void insertData(DATA_TYPE data);           // 迭代 不会选择平衡化

// 返回二叉树结点数
int size();

// 节点高度
int height(Node *T);

// 前序、中序、后序遍历
void preOrder(Node *T);
void inOrder(Node *T);
void postOrder(Node *T);
// 逆中序打印二叉树
void printTree(Node *T, int level);

// 判断二叉树是否平衡
int is_balanced(Node *T);

// 查找数据是否在二叉树中
int search_val(DATA_TYPE val);

// 二叉树的root结点
Node *getRoot();

// 删除节点
Node *delete_data(DATA_TYPE val);

// 清空二叉树
void clear();

void test_binary_tree();

BinaryTree.c

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include "BinaryTree.h"

#define MAX_LINE 1024 // 定义二叉树每行包含节点的最大个数 2的指数

static Node *root = NULL;
static int node_size = 0;

/*********************二叉树平衡化*********************/
// 获取平衡因子
static int balanceFactor(Node *node)
{
    if (node == NULL)
    {
        return 0;
    }
    return height(node->left) - height(node->right);
}

static Node *leftRotate(Node *node)
{
    Node *right = node->right;
    node->right = right->left;
    right->left = node;
    return right;
}

static Node *rightRotate(Node *node)
{
    Node *left = node->left;
    node->left = left->right;
    left->right = node;
    return left;
}

// 旋转节点使二叉树平衡
Node *rotate(Node *node)
{
    int bf = balanceFactor(node);
    if (bf > 1) // 左子树
    {
        if (balanceFactor(node->left) >= 0) // 左子树
        {
            return rightRotate(node);
        }
        else
        {
            // 先左旋再右旋
            node->left = leftRotate(node->left);
            return rightRotate(node);
        }
    }
    else if (bf < -1) // 右子树
    {
        if (balanceFactor(node->right) <= 0) // 右子树
        {
            return leftRotate(node);
        }
        else
        {
            node->right = rightRotate(node->right);
            return leftRotate(node);
        }
    }
    return node;
}
/*********************二叉树平衡化*********************/

// 插入数据,迭代方式 不会选择平衡化
void insertData(DATA_TYPE data)
{
    if (root == NULL)
    {
        root = malloc(sizeof(Node));
        root->data = data;
        root->left = NULL;
        root->right = NULL;
        node_size++;
        return;
    }
    Node *node = root;
    while (node)
    {
        if (data < node->data)
        {
            if (node->left == NULL)
            {
                node->left = malloc(sizeof(Node));
                node->left->data = data;
                node->left->left = NULL;
                node->left->right = NULL;
                break;
            }
            else
            {
                node = node->left;
            }
        }
        else
        {
            if (node->right == NULL)
            {
                node->right = malloc(sizeof(Node));
                node->right->data = data;
                node->right->left = NULL;
                node->right->right = NULL;
                break;
            }
            else
            {
                node = node->right;
            }
        }
    }
    node_size++;
}

// 插入数据:递归方式 平衡化重构
Node *insertNode(Node *T, DATA_TYPE data)
{
    if (root == NULL)
    {
        root = malloc(sizeof(Node));
        root->data = data;
        root->left = NULL;
        root->right = NULL;
        node_size++;
        return root;
    }
    if (T == NULL)
    {
        Node *node = malloc(sizeof(Node));
        node->data = data;
        node->left = NULL;
        node->right = NULL;
        node_size++;
        return node;
    }
    if (data >= T->data)
    {
        T->right = insertNode(T->right, data);
    }
    else
    {
        T->left = insertNode(T->left, data);
    }
    T = rotate(T);
    return T;
}

void insertNode_root(DATA_TYPE data)
{
    root = insertNode(root, data);
}

void preOrder(Node *T)
{
    if (T)
    {
        printf("%d -> ", T->data);
        preOrder(T->left);
        preOrder(T->right);
    }
}
void inOrder(Node *T)
{
    if (T)
    {
        inOrder(T->left);
        printf("%d -> ", T->data);
        inOrder(T->right);
    }
}
void postOrder(Node *T)
{
    if (T)
    {
        postOrder(T->left);
        postOrder(T->right);
        printf("%d -> ", T->data);
    }
}

// 采用逆中序和按层次缩进,是因为把打印结果按顺时针方向旋转90度就能呈现出正常的二叉树形状
void printTree(Node *T, int level)
{
    if (T)
    {
        printTree(T->right, level + 1);
        for (int i = 0; i < level; i++)
        {
            printf("     ");
        }
        printf("%d\n", T->data);
        printTree(T->left, level + 1);
    }
}

int size()
{
    return node_size;
}

int height(Node *T)
{
    if (T == NULL)
    {
        return 0;
    }
    return __max(abs(height(T->left)), abs(height(T->right))) + 1;
}

static void insertToRoot(DATA_TYPE data)
{
    insertNode(root, data);
}

// 左右子树高度差小于等于1
int is_balanced(Node *T)
{
    if (T == NULL)
    {
        return TRUE; // 空树被认为是平衡的
    }
    return abs(height(T->left) - height(T->right)) <= 1 && is_balanced(T->left) && is_balanced(T->right);
}

static int search(Node *T, DATA_TYPE val)
{
    while (T)
    {
        if (T->data == val)
        {
            return TRUE;
        }
        T = (T->data > val) ? T->left : T->right;
    }
    return FALSE;
}

int search_val(DATA_TYPE val)
{
    return search(root, val);
}

Node *getRoot()
{
    return root;
}

/*********************删除元素*********************/
static Node *deleteLeftmost(Node *T)
{
    if (T->left == NULL)
    {
        return T->right;
    }
    else
    {
        T->left = deleteLeftmost(T->left);
        return T;
    }
}

static DATA_TYPE getLeftmost(Node *T)
{
    if (T->left == NULL)
    {
        return T->data;
    }
    else
    {
        return getLeftmost(T->left);
    }
}

static Node *deleteTopmost(Node *T)
{
    if (T->left == NULL)
    {
        return T->right;
    }
    else if (T->right == NULL)
    {
        return T->left;
    }
    else
    {
        T->data = getLeftmost(T->right);
        T->right = deleteLeftmost(T->right);
        return T;
    }
}

static Node *delete(Node *T, DATA_TYPE val)
{
    if (T)
    {
        if (T->data == val)
        {
            node_size--;
            return deleteTopmost(T);
        }
        else if (val < T->data)
        {
            T->left = delete(T->left, val);
        }
        else
        {
            T->right = delete(T->right, val);
        }
    }
    return T;
}

Node *delete_data(DATA_TYPE val)
{
    return delete(root, val);
}

void clear()
{
    free(root);
    root = NULL;
    node_size = 0;
}
/*********************删除元素*********************/

void test_binary_tree()
{
    printf("|***********************基础操作***********************|\n");
    // insertData(4); // root
    // insertData(2); // root left child
    // insertData(1); // 2 left child
    // insertData(3); // 2 right child
    // insertData(6); // root right child
    // insertData(5); // 6 left child
    // insertData(7); // 6 right child

    // insertToRoot(4); // root
    // insertToRoot(2); // root left child
    // insertToRoot(1); // 2 left child
    // insertToRoot(3); // 2 right child
    // insertToRoot(6); // root right child
    // insertToRoot(5); // 6 left child
    // insertToRoot(7); // 6 right child

    insertNode_root(4);
    insertNode_root(2);
    insertNode_root(1);
    insertNode_root(3);
    insertNode_root(6);
    insertNode_root(5);
    insertNode_root(7);

    insertNode_root(8);
    insertNode_root(9);
    insertNode_root(10);
    insertNode_root(11);
    insertNode_root(12);
    // insertNode_root(13);
    printf("逆中序打印:\n");
    printTree(root, 0);

    printf("结点数:%d\n", size());
    printf("是否包含[%d]:%d\n", 3, search_val(3));
    printf("是否包含[%d]:%d\n", 9, search_val(9));

    printf("前序遍历:");
    preOrder(root);
    printf("\n");
    printf("中序遍历:");
    inOrder(root);
    printf("\n");
    printf("后序遍历:");
    postOrder(root);
    printf("\n");
    printf("逆中序打印:\n");
    printTree(root, 0);
    printf("\n");
    int len = height(root);
    printf("二叉树高度:%d\n", len);
    printf("二叉树是否平衡:%d\n", is_balanced(root));

    printf("测试删除元素......");
    printf("\n");
    delete_data(4);
    printf("逆中序打印:\n");
    printTree(root, 0);

    printf("\n");
    delete_data(1);
    printf("逆中序打印:\n");
    printTree(root, 0);

    printf("\n");
    delete_data(5);
    printf("逆中序打印:\n");
    printTree(root, 0);

    clear();

    printf("\n");
    insertNode_root(10);
    insertNode_root(8);
    insertNode_root(15);
    insertNode_root(12);
    insertNode_root(19);
    insertNode_root(13); // 先右旋再左旋
    printf("逆中序打印:\n");
    printTree(root, 0);

    printf("|***********************平衡树***********************|\n");
}

二叉树层序遍历

BinaryTreeLevelOrder.h

#include "BinaryTree.h"

// 辅助队列节点--用于层序遍历
typedef struct QueueNode
{
    Node *data;
    struct QueueNode *next;
} QueueNode;

/********************辅助队列方法********************/
int is_queue_empty();
void enQueue(Node *T);
Node *deQueue();
/********************辅助队列方法********************/

// 二叉树层序遍历
DATA_TYPE **levelOrder(Node *T, int len /* 有多少层 */);

void test_binary_tree_level_order();

BinaryTreeLevelOrder.c

#include <stdio.h>
#include <stdlib.h>

#include "BinaryTreeLevelOrder.h"

// #define col_len (height(getRoot()))

// 层序遍历辅助队列结点数
static int queue_node_size = 0;
static QueueNode *Q = NULL;

// 存储二维数组每行有多少个列 即表示二叉树每一层有多少个节点
static int *col;
static int col_len = 0;

/********************辅助队列方法********************/
int is_queue_empty()
{
    return queue_node_size == 0 || Q == NULL;
}
void enQueue(Node *T)
{
    if (Q == NULL)
    {
        Q = malloc(sizeof(QueueNode));
        Q->data = T;
        Q->next = NULL;
        queue_node_size++;
        return;
    }
    QueueNode *q_node = Q;
    while (q_node->next != NULL)
    {
        q_node = q_node->next;
    }
    q_node->next = malloc(sizeof(QueueNode));
    q_node->next->data = T;
    q_node->next->next = NULL;
    queue_node_size++;
}
Node *deQueue()
{
    Node *val = Q->data;
    Q = Q->next;
    queue_node_size--;
    return val;
}
/********************辅助队列方法********************/

DATA_TYPE **levelOrder(Node *T, int len /* 有多少层 */)
{
    // int (*arr)[MAX_LINE] = malloc(sizeof(*arr) * MAX_LINE);
    // DATA_TYPE *arr;
    DATA_TYPE **arr = malloc(sizeof(DATA_TYPE *) * len);
    col = malloc(sizeof(int) * len);
    enQueue(T);
    while (!is_queue_empty())
    {
        int curr_queue_size = queue_node_size; // 每行节点个数
        DATA_TYPE *per_line = malloc(sizeof(DATA_TYPE) * curr_queue_size);
        int index = 0;
        for (int i = 0; i < curr_queue_size; i++)
        {
            Node *n = deQueue();
            per_line[index++] = n->data;
            // 从左到右收集节点
            if (n->left)
            {
                enQueue(n->left);
            }
            if (n->right)
            {
                enQueue(n->right);
            }
        }
        col[col_len] = index; // 每行有多少列
        arr[col_len] = per_line;
        col_len++;
    }
    return arr;
}

void test_binary_tree_level_order()
{
    printf("|***********************层序遍历***********************|\n");
    Node *root = getRoot();
    int len = height(root);
    DATA_TYPE **arr = levelOrder(root, len); // 锯齿形数组 需要额外数据结构(数组或链表)保存每行列数

    // col_len 等于 len 即二叉树的高度 即二叉树有几行
    for (int i = 0; i < col_len; i++)
    {
        printf("第%d行有结点数: %d\t", i + 1, col[i]);
    }
    printf("\n");

    for (int i = 0; i < len; i++)
    {
        int c = col[i];
        for (int j = 0; j < c; j++)
        {
            int x = arr[i][j];
            printf("arr[%d][%d] = %d\t", i, j, x);
        }
        printf("\n");
    }
}

二叉树非递归遍历

BinaryTreeNonRecursiveOrder.h

#include "BinaryTree.h"

// 辅助队列节点--用于层序遍历
typedef struct StackNode
{
    Node *data;
    struct StackNode *next;
} StackNode;

/********************辅助队列方法********************/
int is_stack_empty();
void push(Node *T);
Node *pop();
/********************辅助队列方法********************/

// 非递归前序遍历
DATA_TYPE *non_recursive_pre_order(Node *root, int node_size);
// 非递归中序遍历
DATA_TYPE *non_recursive_in_order(Node *root, int node_size);
// 非递归后序遍历
DATA_TYPE *non_recursive_post_order(Node *root, int node_size);

void test_binary_tree_non_recursive_order();

BinaryTreeNonRecursiveOrder.c

#include <stdio.h>
#include <stdlib.h>

#include "BinaryTreeNonRecursiveOrder.h"

static int stack_size = 0;
static StackNode *head = NULL;

/********************辅助栈方法********************/

static StackNode *newStackNode(Node *T)
{
    StackNode *node = malloc(sizeof(StackNode));
    node->data = T;
    node->next = NULL;
    return node;
}

int is_stack_empty()
{
    return stack_size == 0;
}
void push(Node *T)
{
    if (head == NULL)
    {
        head = newStackNode(T);
        stack_size++;
        return;
    }
    StackNode *node = newStackNode(T);
    node->next = head;
    head = node;
    stack_size++;
}
Node *pop()
{
    Node *node = head->data;
    head = head->next;
    stack_size--;
    return node;
}
/********************辅助栈方法********************/

DATA_TYPE *non_recursive_pre_order(Node *root, int node_size)
{
    if (root == NULL)
    {
        return NULL;
    }
    DATA_TYPE *result = malloc(sizeof(DATA_TYPE) * node_size);
    DATA_TYPE *p = result;
    while (root || !is_stack_empty())
    {
        if (root)
        {
            *p++ = root->data;
            push(root);
            root = root->left;
        }
        else
        {
            root = pop();
            root = root->right;
        }
    }
    return result;
}
DATA_TYPE *non_recursive_in_order(Node *root, int node_size)
{
    if (root == NULL)
    {
        return NULL;
    }
    DATA_TYPE *result = malloc(sizeof(DATA_TYPE) * node_size);
    DATA_TYPE *p = result;
    while (root || !is_stack_empty())
    {
        if (root)
        {
            push(root);
            root = root->left;
        }
        else
        {
            root = pop();
            *p++ = root->data;
            root = root->right;
        }
    }
    return result;
}

// 非递归后序遍历
DATA_TYPE *non_recursive_post_order(Node *root, int node_size)
{
    if (root == NULL)
    {
        return NULL;
    }
    DATA_TYPE *result = malloc(sizeof(DATA_TYPE) * node_size);
    DATA_TYPE *p = result;
    Node *pre = NULL;
    while (root || !is_stack_empty())
    {
        while (root)
        {
            push(root);
            root = root->left;
        }
        root = pop();
        if (root->right == NULL || root->right == pre)
        {
            *p++ = root->data;
            pre = root;
            root = NULL;
        }
        else
        {
            push(root);
            root = root->right;
        }
    }
    return result;
}

static void printArray(DATA_TYPE *arr, int len)
{
    for (int i = 0; i < len; i++)
    {
        printf("%d -> ", *arr++);
    }
    printf("\n");
}

void test_binary_tree_non_recursive_order()
{
    printf("|***********************二叉树非递归遍历***********************|\n");
    Node *root = getRoot();
    int len = size(root); // 二叉树结点数 用于动态内存分配时计算长度

    DATA_TYPE *arr = non_recursive_post_order(root, len);
    printf("非递归后序遍历:");
    printArray(arr, len);

    arr = non_recursive_in_order(root, len);
    printf("非递归中序遍历:");
    printArray(arr, len);
    
    arr = non_recursive_pre_order(root, len);
    printf("非递归前序遍历:");
    printArray(arr, len);
}

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

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

相关文章

【PostgreSQL数据分析实战:从数据清洗到可视化全流程】3.2 缺失值检测与处理(NULL值填充/删除策略)

&#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 文章大纲 缺失值检测与处理全攻略&#xff1a;NULL值填充与删除策略实战3.2 缺失值检测与处理3.2.1 缺失值类型与业务影响3.2.1.1 缺失值的三种形态3.2.1.2 业务影响分级 3.2.2 缺失值…

2025年渗透测试面试题总结-某步在线面试(题目+回答)

网络安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 一、操作系统相关问题总结与分析及扩展回答 1. Linux命令熟悉度 2. 查看进程的命令 3. 查看网络进程…

Java后端程序员学习前端之JavaScript

1.什么是JavaScript 1.1.概述 JavaScript是一门世界上最流行的脚本语言javaScript 一个合格的后端人员&#xff0c;必须要精通JavaScript 1.2.历史 JavaScript的起源故事-CSDN博客 2.快速入门 2.1.引入JavaScript 1.内部标签 <script>//.......</script> --…

uniapp-商城-43-shop 后台管理 页面

后台管理较为简单&#xff0c;主要用于后台数据的管理&#xff0c;包含商品类别和商品信息&#xff0c;其实还可以扩展到管理用户等等 1、后台首页 包含 分类管理 商品管理 关于商家等几个栏目 主要代码&#xff1a; <template><view class"manage">…

vue2 结合后端预览pdf 跨域的话就得需要后端来返回 然后前端呈现

<el-button :loading"pdfIslock" v-if"isPDFFile(form.pic)" type"primary" style"margin: 15px 0" click"previewPDF(form.pic)"> 预览pdf </el-button>//npm install pdfjs-dist //如果没有就得先安装import …

什么是 HSQLDB?

大家好&#xff0c;这里是架构资源栈&#xff01;点击上方关注&#xff0c;添加“星标”&#xff0c;一起学习大厂前沿架构&#xff01; Java开发人员学习Java数据库连接&#xff08;JDBC&#xff09;的最简单方法是试验HyperSQL数据库&#xff08;又名HSQLDB&#xff09;。 …

多语言爬虫实现网站价格监控

最近突发奇想想用多种代码来爬取数据做价格监控。常见的比如Python、JavaScript(Node.js)、或者Go&#xff1f;不过通常来说&#xff0c;Python应该是首选&#xff0c;因为它的库比较丰富&#xff0c;比如requests和BeautifulSoup&#xff0c;或者Scrapy。不过客户要求多种代码…

16.Three.js 中的 RectAreaLight 全面详解 + Vue 3 实战案例

&#x1f60e; 本文将带你从零了解 THREE.RectAreaLight 的工作原理、使用方式、注意事项&#xff0c;并在最后用 Vue 3 的 Composition API 封装一个完整的光源演示组件&#xff0c;一站式搞懂矩形区域光的魅力 &#x1f4a1;&#xff01; &#x1f5bc;️ 一、展示图效果示意…

excel 批量导出图片并指定命名

一、开发环境 打开excel文件中的宏编辑器和JS代码调试 工具-》开发工具-》WPS宏编辑器 左边是工程区&#xff0c;当打开多个excel时会有多个&#xff0c;要注意不要把代码写到其他工作簿去了 右边是代码区 二、编写代码 宏是js语言&#xff0c;因此变量或者方法可以网上搜…

Mem0.ai研究团队开发的全新记忆架构系统“Mem0”正式发布

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

通过DeepSeek大语言模型控制panda机械臂,听懂人话,拟人性回答。智能机械臂助手又进一步啦

文章目录 前言环境配置运行测试报错 前言 通过使用智能化的工作流控制系统来精确操控机械臂&#xff0c;不仅能够基于预设算法可靠地规划每个动作步骤的执行顺序和力度&#xff0c;确保作业流程的标准化和可重复性&#xff0c;还能通过模块化的程序设计思路灵活地在原有工作流中…

如何添加或删除极狐GitLab 项目成员?

极狐GitLab 是 GitLab 在中国的发行版&#xff0c;关于中文参考文档和资料有&#xff1a; 极狐GitLab 中文文档极狐GitLab 中文论坛极狐GitLab 官网 项目成员 (BASIC ALL) 成员是有权访问您的项目的用户和群组。 每个成员都有一个角色&#xff0c;这决定了他们在项目中可以…

计算机网络-LDP标签发布与管理

前面学习了LDP建立邻居&#xff0c;建立会话&#xff0c;今天来学习在MPLS中的标签发布与管理。 在MPLS网络中&#xff0c;下游LSR决定标签和FEC的绑定关系&#xff0c;并将这种绑定关系发布给上游LSR。LDP通过发送标签请求和标签映射消息&#xff0c;在LDP对等体之间通告FEC和…

云境天合水陆安全漏电监测仪—迅速确定是否存在漏电现象

云境天合水陆安全漏电监测仪是一种专为水下及潮湿环境设计的电气安全检测设备&#xff0c;通过高灵敏度电磁传感器探测漏电电流产生的交变磁场&#xff0c;基于法拉第电磁感应定律&#xff0c;自动区分高灵敏度信号和低灵敏度信号&#xff0c;精准定位泄漏电源的具体位置。一旦…

软考 系统架构设计师系列知识点之杂项集萃(54)

接前一篇文章&#xff1a;软考 系统架构设计师系列知识点之杂项集萃&#xff08;53&#xff09; 第87题 某银行系统采用Factory Method方法描述其不同账户之间的关系&#xff0c;设计出的类图如下所示。其中与Factory Method的“Creator”角色对应的类是&#xff08;&#xff…

Nginx +Nginx-http-flv-module 推流拉流

这两天为了利用云服务器实现 Nginx 进行OBS Rtmp推流&#xff0c;Flv拉流时发生了诸多情况&#xff0c;记录实现过程。 环境 OS&#xff1a;阿里云CentOS 7.9 64位Nginx&#xff1a;nginx-1.28.0Nginx-http-flv-module&#xff1a;nginx-http-flv-module-1.2.12 安装Nginx编…

KeyPresser 一款自动化按键工具

1. 简介 KeyPresser 是一款自动化按键工具,它可以与窗口交互,并支持后台运行, 无需保持被控窗口在前台运行。用户可以选择要操作的目标窗口,并通过勾选复选框来控制要发送哪些按键消息。可以从组合框中选择所需的按键,并在编辑框中输入时间间隔以控制按键发送之间的延迟。程…

DVWA靶场保姆级通关教程--03CSRF跨站请求伪造

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 目录 文章目录 前言 一、low级别的源码分析 二、medium级别源码分析 安全性分析 增加了一层 Referer 验证&#xff1a; 关键点是&#xff1a;在真实的网络环境中&a…

架构思维:构建高并发读服务_基于流量回放实现读服务的自动化测试回归方案

文章目录 引言一、升级读服务架构&#xff0c;为什么需要自动化测试&#xff1f;二、自动化回归测试系统&#xff1a;整体架构概览三、日志收集1. 拦截方式2. 存储与优化策略3. 架构进化 四、数据回放技术实现关键能力 五、差异对比对比方式灵活配置 六、三种回放模式详解1. 离…

Qt实现车载多媒体项目,包含天气、音乐、视频、地图、五子棋功能模块,免费下载源文件!

本文主要介绍项目&#xff0c;项目的结构&#xff0c;项目如何配置&#xff0c;项目如何打包。这篇文章如果对你有帮助请点赞和收藏&#xff0c;谢谢&#xff01;源代码仅供学习使用&#xff0c;如果转载文章请标明出处&#xff01;&#xff08;免费下载源代码&#xff09;&…