【C语言】数据结构——链式二叉树实例探究

💗个人主页💗
⭐个人专栏——数据结构学习⭐
💫点击关注🤩一起学习C语言💯💫

导读:

我们在前面学习了单链表,顺序表,栈和队列,小堆。
今天我们来学习链式二叉树
关注博主或是订阅专栏,掌握第一消息。

1. 链式二叉树的概念和结构

链式二叉树(Linked Binary Tree)是一种基于链表实现的二叉树结构。在链式二叉树中,每个节点由三个部分组成:数据、左子节点和右子节点。
在这里插入图片描述

1.1 链式二叉树的特点

链式二叉树的特点包括:

  1. 每个节点都有一个数据项,可以是任意类型的数据。
  2. 每个节点都有一个左子节点和一个右子节点。如果某个节点没有左子节点或右子节点,对应的子节点指针就为空。
  3. 子节点可以是空的,也可以是另一个链式二叉树的根节点。这就构成了二叉树的递归结构。

链式二叉树的优点是可以动态地插入和删除节点,不需要预先指定树的大小。
同时,链式二叉树的节点可以随意分配在内存中,不需要连续的存储空间。
缺点是相对于数组实现的二叉树,链式二叉树需要额外的指针来连接节点,因此会占用更多的内存空间。

1.2 链式二叉树的遍历

链式二叉树的遍历方式有三种:前序遍历、中序遍历和后序遍历。

前序遍历先访问根节点,然后按照左子树、右子树的顺序遍历;
中序遍历先访问左子树,然后访问根节点,最后访问右子树;
后序遍历先访问左子树,然后访问右子树,最后访问根节点。

2. 二叉树的代码实现

2.1 创建二叉树

我们先创建一个六个节点的二叉树


typedef int BTDataType;
//typedef char BTDataType;

typedef struct BinaryTreeNode
{
    BTDataType data;
    struct BinaryTreeNode* left;
    struct BinaryTreeNode* right;
}TreeNode;

//开辟空间并赋值
TreeNode* BuyTreeNode(int x)
{
    TreeNode* node = (TreeNode*)malloc(sizeof(TreeNode));
    assert(node);
    node->data = x;
    node->left = NULL;
    node->right = NULL;
    return node;
}
TreeNode* CreateTree()
{
    TreeNode* node1 = BuyTreeNode(7);
    TreeNode* node2 = BuyTreeNode(9);
    TreeNode* node3 = BuyTreeNode(30);
    TreeNode* node4 = BuyTreeNode(25);
    TreeNode* node5 = BuyTreeNode(66);
    TreeNode* node6 = BuyTreeNode(88);
    node1->left = node2;
    node1->right = node4;
    node2->left = node3;
    node4->left = node5;
    node4->right = node6;
    return node1;
}

在这里插入图片描述

2.2 前序遍历

前序遍历:访问根结点的操作发生在遍历其左右子树之前。
**注意:**左节点全部访问完之后才访问右节点。
遇到NULL,则返回,否则继续调用,直到遇到NULL

//前序遍历
void PrevOrder(TreeNode* root)
{
    if (root == NULL)
    {
        printf("NULL ");
        return NULL;
    }
    //先访问根节点
    printf("%d ", root->data);
    //之后访问左节点和右节点
    PrevOrder(root->left);
    PrevOrder(root->right);
}

在这里我们把空值也打印了出来
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.3 中序遍历

中序遍历(Inorder Traversal)——访问根结点的操作发生在遍历其左右子树之中(间)。
**注意:**是把一个节点的所有左子树访问完之后再去打印值,最后再访问右子树。

//中序遍历
void InOrder(TreeNode* root)
{
    if (root == NULL)
    {
        printf("NULL ");
        return NULL;
    }
    //访问完所有左子树后再打印值
    InOrder(root->left);
    printf("%d ", root->data);
    InOrder(root->right);
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.4 计算节点个数

计算链式二叉树的节点个数可以通过递归的方式实现。

  1. 若二叉树为空,则节点个数为0。
  2. 若二叉树不为空,则节点个数为根节点的个数加上左子树的节点个数和右子树的节点个数。
  3. 使用递归对左子树和右子树分别计算节点个数。
  4. 返回根节点的个数加上左子树和右子树的节点个数。
// 节点个数
int TreeSize(TreeNode* root)
{
    //如果为空返回0
    if (root == NULL)
    {
        return 0;
    }
    //不为空调用左右节点,每次调用都会加一
    return TreeSize(root->left)
        + TreeSize(root->right) + 1;
}

在这里插入图片描述
在这里插入图片描述

2.5 计算叶子节点的个数

叶子节点是指在树中没有子节点的节点,可以通过遍历树的方式来计算叶子节点的个数。
以下是计算叶子节点个数的递归算法:

  1. 如果树为空,则叶子节点个数为0。
  2. 如果树只有一个节点,则叶子节点个数为1。
  3. 否则,叶子节点个数等于左子树的叶子节点个数加上右子树的叶子节点个数。
// 叶子节点的个数
int TreeLeafSize(TreeNode* root)
{
    if (root == NULL)
    {
        return 0;
    }
    //如果该节点的左节点和右节点都为空
    if (!(root->left) && !(root->right))
    {
        return 1;
    }
    return TreeLeafSize(root->left) + TreeLeafSize(root->right);
}

在这里插入图片描述

2.6 计算树的高度

计算树的高度可以使用递归的方法来完成。一个树的高度可以定义为从根节点到最远叶子节点的边数。

// 树的高度
int TreeHight(TreeNode* root)
{
    if (root == NULL)
    {
        return 0;
    }
    //返回较大的一个
    return fmax(TreeHight(root->left), TreeHight(root->right)) + 1;
}

在这里插入图片描述

2.7 计算树第k层节点个数

树的第k层节点个数取决于树的结构,不同的树的第k层节点个数可能不同。一般情况下,树的第k层节点个数为k层的节点数减去k-1层的节点数。

int TreeLevelK(TreeNode* root, int k)
{
    assert(k > 0);
    if (root == NULL)
    {
        return 0;
    }
    if (k == 1)
    {
        return 1;
    }
    return TreeLevelK(root->left, k - 1) + 
        TreeLevelK(root->right, k - 1);
}

在这里插入图片描述
k=1时,说明到达了k层
在这里插入图片描述

2.8 二叉树查找值为x的节点

二叉树查找值为x的节点可以通过递归来实现,具体步骤如下:

  1. 如果当前节点为空,则返回空。
  2. 如果当前节点的值等于x,则返回当前节点。
  3. 如果该节点的值不等于x,递归在左子树中查找值为x的节点。
  4. 如果该左子树节点的值不等于x,递归在右子树中查找值为x的节点。
TreeNode* TreeFind(TreeNode* root, BTDataType x)
{
    if (root == NULL)
    {
        return NULL;
    }
    if (root->data == x)
    {
        return root;
    }
    //另设记录函数调用返回的值,再判断是否为kong
    TreeNode* ret1 = TreeFind(root->left, x);
    if (ret1)
    {
        return ret1;
    }
    TreeNode* ret2 = TreeFind(root->right, x);
    if (ret2)
    {
        return ret2;
    }
    return NULL;
}

在这里插入图片描述

2.9 通过前序遍历的数组构建二叉树

通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树,通过遍历我们要建立如下效果:
在这里插入图片描述

// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
TreeNode* TreeCreate(char* a, int* pi)
{
    if (a[*pi] == '#')
    {
        (*pi)++;
        return NULL;
    }
    TreeNode* root = (TreeNode*)malloc(sizeof(TreeNode));
    if (root == NULL)
    {
        perror("malloc fail");
        exit(-1);
    }
    root->data = a[(*pi)++];
    root->left = TreeCreate(a, pi);
    root->right = TreeCreate(a, pi);
    return root;
}
int main()
{
    char arr[] = "ABD##E#H##CF##G##";
    int i = 0;
    TreeNode* rootstr = TreeCreate(arr, &i);
    return 0;
}

2.10 层序遍历

链式二叉树的层序遍历可以通过使用队列来实现。具体步骤如下:

  1. 首先,将根节点入队。

  2. 进入循环,直到队列为空。

    • 从队列中取出一个节点,并将其值输出。
    • 如果该节点有左子节点,则将左子节点入队。
    • 如果该节点有右子节点,则将右子节点入队。
  3. 循环结束后,层序遍历完成。

//层序遍历
void LevelOrder(TreeNode* root)
{
    QNode q;
    QueueInit(&q);
    if (root)
    {
        QueuePush(&q, root);
    }
    int levelSize = 1;
    while (!QueueEmpty(&q))
    {
        while (levelSize--)
        {
            TreeNode* front = QueueFront(&q);
            QueuePop(&q);
            printf("%c ", front->data);
            if (front->left)
            {
                QueuePush(&q, front->left);
            }
            if (front->right)
            {
                QueuePush(&q, front->right);
            }
        }
        printf("\n");
        levelSize = QueueSize(&q);
    }
    printf("\n");

    QueueDestroy(&q);
}

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.11 判断一棵树是否是完全二叉树

完全二叉树是指除了最后一层外,其他层的节点都是满的,且最后一层的节点从左到右依次填满。因此,我们可以通过遍历树的节点来判断是否是完全二叉树。

  1. 使用层次遍历的方法遍历树的节点。
  2. 当遇到第一个为空的节点时,停止遍历。
  3. 继续遍历树的节点,如果还存在非空节点,那么该树不是完全二叉树。
  4. 如果遍历完所有节点,都没有发现非空节点,那么该树是完全二叉树。
//判断一棵树是否是完全二叉树
bool TreeComplete(TreeNode* root)
{
    Queue q;
    QueueInit(&q);
    if (root)
    {
        QueuePush(&q, root);
    }
    while (!QueueEmpty(&q))
    {
        TreeNode* front = QueueFront(&q);
        QueuePop(&q);

        if (front == NULL)
        {
            break;
        }

        QueuePush(&q, front->left);
        QueuePush(&q, front->right);
    }
    // 前面遇到空以后,后面还有非空就不是完全二叉树
    while (!QueueEmpty(&q))
    {
        TreeNode* front = QueueFront(&q);
        QueuePop(&q);

        if (front)
        {
            QueueDestroy(&q);
            return false;
        }
    }
    QueueDestroy(&q);
    return true;
}

2.12 二叉树销毁

需要把每一个节点都销毁,值得注意的是,要从最下层的节点开始销毁,而不是根节点

//二叉树销毁
void DestroyTree(TreeNode* root)
{
    if (root == NULL)
    {
        return NULL;
    }
    DestroyTree(root->left);
    DestroyTree(root->right);
    free(root);
}

3. 代码整理

该代码的层序遍历导入了我们之前写的队列

Queue.h

#define _CRT_SECURE_NO_WARNINGS 

#pragma once
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>


// 链式结构:表示队列 
typedef int QDataType;
typedef struct QueueNode
{
	QDataType val;
	struct QueueNode* next;
}QNode;

// 队列的结构 
typedef struct Queue
{
	QNode* phead;
	QNode* ptail;
	int size;
}Queue;

// 初始化队列 
void QueueInit(Queue* pq);

// 销毁队列 
void QueueDestroy(Queue* pq);

// 队尾入队列 
void QueuePush(Queue* pq, QDataType x);

// 队头出队列
void QueuePop(Queue* pq);

// 获取队列头部元素 
QDataType QueueFront(Queue* pq);

// 获取队列队尾元素
QDataType QueueBack(Queue* pq);

// 检测队列是否为空,如果为空返回true,如果非空返回false 
bool QueueEmpty(Queue* pq);

// 获取队列中有效元素个数 
int QueueSize(Queue* pq);

Queue.c

#include "Queue.h"

// 初始化队列 
void QueueInit(Queue* pq)
{
	pq->phead = NULL;
	pq->ptail = NULL;
	pq->size = 0;
}

// 销毁队列 
void QueueDestroy(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->phead->next;
	while (cur)
	{
		free(pq->phead);
		pq->phead = cur;
		cur = cur->next;
	}
	cur = NULL;
	pq->phead = NULL;
	pq->ptail = NULL;
	pq->size = 0;
}

// 队尾入队列 
void QueuePush(Queue* pq, QDataType x)
{
	//开辟新空间
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return;
	}
	newnode->val = x;
	newnode->next = NULL;
	if (pq->ptail == NULL)
	{
		pq->phead = pq->ptail = newnode;
	}
	else
	{
		pq->ptail->next = newnode;
		pq->ptail = newnode;
	}
	pq->size++;
}

// 队头出队列
void QueuePop(Queue* pq)
{
	assert(pq);
	assert(pq->phead);
	QNode* tmp = pq->phead;
	pq->phead = pq->phead->next;
	free(tmp);
	tmp = NULL;
	if (pq->phead == NULL)
	{
		pq->ptail = NULL;
	}
	pq->size--;
}

// 获取队列头部元素
QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(pq->phead);
	return pq->phead->val;
}

// 获取队列队尾元素
QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(pq->ptail);
	return pq->ptail->val;
}

// 检测队列是否为空,如果为空返回true,如果非空返回false 
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->size == 0;
}

// 获取队列中有效元素个数 
int QueueSize(Queue* pq)
{
	assert(pq);
	return pq->size;
}

study.c

#include "Queue.h"

typedef int BTDataType;
//typedef char BTDataType;

typedef struct BinaryTreeNode
{
    BTDataType data;
    struct BinaryTreeNode* left;
    struct BinaryTreeNode* right;
}TreeNode;

TreeNode* BuyTreeNode(int x)
{
    TreeNode* node = (TreeNode*)malloc(sizeof(TreeNode));
    assert(node);
    node->data = x;
    node->left = NULL;
    node->right = NULL;
    return node;
}
TreeNode* CreateTree()
{
    TreeNode* node1 = BuyTreeNode(7);
    TreeNode* node2 = BuyTreeNode(9);
    TreeNode* node3 = BuyTreeNode(30);
    TreeNode* node4 = BuyTreeNode(25);
    TreeNode* node5 = BuyTreeNode(66);
    TreeNode* node6 = BuyTreeNode(88);
    node1->left = node2;
    node1->right = node4;
    node2->left = node3;
    node4->left = node5;
    node4->right = node6;
    return node1;
}

//前序遍历
void PrevOrder(TreeNode* root)
{
    if (root == NULL)
    {
        printf("NULL ");
        return NULL;
    }
    //先访问根节点
    printf("%d ", root->data);
    //之后访问左节点和右节点
    PrevOrder(root->left);
    PrevOrder(root->right);
}

//中序遍历
void InOrder(TreeNode* root)
{
    if (root == NULL)
    {
        printf("NULL ");
        return NULL;
    }
    //访问完所有左子树后再打印值
    InOrder(root->left);
    printf("%d ", root->data);
    InOrder(root->right);
}

// 节点个数
int TreeSize(TreeNode* root)
{
    //如果为空返回0
    if (root == NULL)
    {
        return 0;
    }
    //不为空调用左右节点,每次调用都会加一
    return TreeSize(root->left)
        + TreeSize(root->right) + 1;
}

// 叶子节点的个数
int TreeLeafSize(TreeNode* root)
{
    if (root == NULL)
    {
        return 0;
    }
    //如果该节点的左节点和右节点都为空
    if (!(root->left) && !(root->right))
    {
        return 1;
    }
    return TreeLeafSize(root->left) + TreeLeafSize(root->right);
}

// 树的高度
int TreeHight(TreeNode* root)
{
    if (root == NULL)
    {
        return 0;
    }
    //返回较大的一个
    return fmax(TreeHight(root->left), TreeHight(root->right)) + 1;
}

//树第k层节点个数
int TreeLevelK(TreeNode* root, int k)
{
    assert(k > 0);
    if (root == NULL)
    {
        return 0;
    }
    if (k == 1)
    {
        return 1;
    }
    return TreeLevelK(root->left, k - 1) + 
        TreeLevelK(root->right, k - 1);
}

// 二叉树查找值为x的节点
TreeNode* TreeFind(TreeNode* root, BTDataType x)
{
    if (root == NULL)
    {
        return NULL;
    }
    if (root->data == x)
    {
        return root;
    }
    //另设记录函数调用返回的值,再判断是否为kong
    TreeNode* ret1 = TreeFind(root->left, x);
    if (ret1)
    {
        return ret1;
    }
    TreeNode* ret2 = TreeFind(root->right, x);
    if (ret2)
    {
        return ret2;
    }
    return NULL;
}

// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
TreeNode* TreeCreate(char* a, int* pi)
{
    if (a[*pi] == '#')
    {
        (*pi)++;
        return NULL;
    }
    TreeNode* root = (TreeNode*)malloc(sizeof(TreeNode));
    if (root == NULL)
    {
        perror("malloc fail");
        exit(-1);
    }
    root->data = a[(*pi)++];
    root->left = TreeCreate(a, pi);
    root->right = TreeCreate(a, pi);
    return root;
}

//二叉树销毁
void DestroyTree(TreeNode* root)
{
    if (root == NULL)
    {
        return NULL;
    }
    DestroyTree(root->left);
    DestroyTree(root->right);
    free(root);
}

//层序遍历
void LevelOrder(TreeNode* root)
{
    QNode q;
    //初始化队列
    QueueInit(&q);
    if (root)
    {
        //把根节点入队列
        QueuePush(&q, root);
    }
    //从1开始
    int levelSize = 1;
    while (!QueueEmpty(&q))
    {
        while (levelSize--)
        {
            TreeNode* front = QueueFront(&q);
            QueuePop(&q);
            printf("%c ", front->data);
            //入左子树和右子树
            if (front->left)
            {
                QueuePush(&q, front->left);
            }
            if (front->right)
            {
                QueuePush(&q, front->right);
            }
        }
        printf("\n");
        //获取队列有效数据个数
        levelSize = QueueSize(&q);
    }
    printf("\n");
    QueueDestroy(&q);
}

//判断一棵树是否是完全二叉树
bool TreeComplete(TreeNode* root)
{
    Queue q;
    QueueInit(&q);
    if (root)
    {
        QueuePush(&q, root);
    }
    //遍历入队列
    while (!QueueEmpty(&q))
    {
        TreeNode* front = QueueFront(&q);
        QueuePop(&q);
        if (front == NULL)
        {
            break;
        }
        QueuePush(&q, front->left);
        QueuePush(&q, front->right);
    }
    // 前面遇到空以后,后面还有非空就不是完全二叉树
    while (!QueueEmpty(&q))
    {
        TreeNode* front = QueueFront(&q);
        QueuePop(&q);

        if (front)
        {
            QueueDestroy(&q);
            return false;
        }
    }
    QueueDestroy(&q);
    return true;
}

void Test1()
{
    TreeNode* root = CreateTree();
    printf("前序遍历:\n");
    PrevOrder(root);
    printf("\n");
    printf("中序遍历:\n");
    InOrder(root);
    printf("\n");

    printf("节点个数:%d\n", TreeSize(root));
    printf("叶子节点的个数:%d\n", TreeLeafSize(root));
    printf("树的高度:%d\n", TreeHight(root));
    printf("树第k层节点个数:%d\n", TreeLevelK(root, 3));
    int x = 0;
    printf("请输入想要查找的x值:》");
    scanf("%d", &x);
    printf("查找值为x的节点: %p\n", TreeFind(root, x));
    bool ret = TreeComplete(root);
    if (ret)
    {
        printf("yes\n");
    }
    else
    {
        printf("no\n");
    }
}

void Test2()
{
    char arr[] = "ABD##E#H##CF##G##";
    int i = 0;
    TreeNode* rootstr = TreeCreate(arr, &i);
    LevelOrder(rootstr);
}
int main()
{
    //Test1();
    Test2();
    return 0;
}


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

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

相关文章

深入探索Qt 6.3:全面了解新特性及应用技巧

学习目标&#xff1a; 帮助读者深入了解Qt 6.3的新特性&#xff0c;并提供相关应用技巧&#xff0c;以帮助他们更好地应用Qt 6.3进行开发 学习内容&#xff1a; Qt 6.3的新特性概述&#xff1a;介绍Qt 6.3相对于之前版本的改进和新增的功能&#xff0c;如模块的增减、性能优化…

2023 亚马逊云科技 re:lnvent 大会探秘: Amazon Connect 全渠道云联络中心

2023 亚马逊云科技 re:lnvent 大会探秘: Amazon Connect 全渠道云联络中心 前言一. Amazon Connect 介绍 &#x1f5fa;️二. Amazon Connect 使用教程 &#x1f5fa;️1.我们打开URl链接找到对应服务2.输入Amazon Connect选中第一个点击进入即可&#xff1b;3.在进入之后我们就…

html中RGB和RGBA颜色表示法

文章目录 RGB什么是RGBRGB颜色模式的取值范围RGB常用颜色对照表 RGBA什么是RGBARGBA颜色模式的取值范围 总结 RGB 什么是RGB RGB是一种颜色空间&#xff0c;其中R代表红色&#xff08;Red&#xff09;、G代表绿色&#xff08;Green&#xff09;、B代表蓝色&#xff08;Blue&a…

C++(继承)

目录 前言&#xff1a; 正文&#xff1a; 1.继承的概念及定义 1.1继承的概念 1.2继承的本质 2.继承的定义 2.1继承格式 2.2继承关系和访问限定符 3 继承中的作用域 3.1隐藏 4 基类和派生类对象赋值转换 4.1切片 5 派生类中的默认成员函数 5.1隐式调用 5.2显示调用…

JDK17 SpringBoot3 整合常见依赖

JDK版本:17 SpringBoot 整合Mybatis Plus 、Redis等 依赖文件 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xs…

【MySQL】数据库和表的操作

数据库和表的操作 一、数据库的操作1. 创建数据库2. 字符集和校验规则&#xff08;1&#xff09;查看系统默认字符集以及校验规则&#xff08;2&#xff09;查看数据库支持的字符集&#xff08;3&#xff09;查看数据库支持的字符集校验规则&#xff08;4&#xff09;校验规则对…

代码随想录算法训练营 | day56 动态规划 583.两个字符串的删除操作,72.编辑距离

刷题 583.两个字符串的删除操作 题目链接 | 文章讲解 | 视频讲解 题目&#xff1a;给定两个单词 word1 和 word2&#xff0c;找到使得 word1 和 word2 相同所需的最小步数&#xff0c;每步可以删除任意一个字符串中的一个字符。 示例&#xff1a; 输入: "sea", &…

一键修复找不到msvcp140.dll无法继续执行代码的办法,有效修复

电脑出现“找不到msvcp140.dll无法继续执行代码”是什么情况&#xff1f;如果系统中没有这个文件或文件发生损坏&#xff0c;那么在启动某些应用程序或游戏时&#xff0c;可能会遇到错误消息&#xff0c;如“程序无法启动因为msvcp140.dll丢失在您的计算机上”或“找不到msvcp1…

Java方法重写及@Override注解(学习推荐版)

定义 所有类都继承了object类&#xff0c;例如重写object的toString()方法 规则 就近原则 重写的规则总结&#xff1a; ①子类重写的方法的方法名和形参列表与父类被重写的方法的方法名和形参列表相同。 ②子类重写的方法的权限修饰符不小于父类被重写的方法的权限修饰符 …

Java接收并解析HL7协议数据

一、前言 HL7协议相信医疗行业的IT人员都不陌生&#xff0c;笔者由于接触时间比较短&#xff0c;乍一听“协议”还是比较懵&#xff0c;不自觉就把它和“HTTP”、"SOAP”之类的网络协议挂上关联&#xff0c;可事实上这个HL7只是一种数据格式&#xff0c;传输方式也可以使用…

【基础知识】大数据组件YARN简述

YARN是一个分布式的资源管理系统。 YARN是Hadoop系统的核心组件&#xff0c;主要功能包括负责在Hadoop集群中的资源管理&#xff0c;负责对作业进行调度运行以及监控。 ResourceManager 负责集群的资源管理与调度&#xff0c;为运行在YARN上的各种类型作业分配资源。 非HA集…

FreeRTOS-07任务切换 对vPortSVCHandler和xPortPendSVHandler的理解

任务的基本单位是TCB块&#xff0c;相当于任务的身份证&#xff0c;其基本成员包括栈指针&#xff0c;栈所在地址&#xff0c;链表节点地址&#xff0c;如下&#xff1a; FreeRTOS.h typedef struct tskTaskControlBlock {volatile StackType_t *pxTopOfStack; /* 栈顶…

前缀和数组、差分数组、树状数组在Leetcode中的应用

文章目录 前缀和数组、差分数组、树状数组知识简单回顾Leetcode 1109. 航班预订统计Leetcode 307. 区域和检索-数组可修改LeetCode 面试题10.10. 数字流的秩LeetCode 1310. 子数组异或查询LeetCode 1409. 查询带键的排列 前缀和数组、差分数组、树状数组知识简单回顾 之前的文…

揭开`this`的神秘面纱:探索 JavaScript 中的上下文密钥(上)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

c语言编写http服务器(Linux下运行)

参考文章&#xff1a;https://blog.csdn.net/baixingyubxy/article/details/125964986?spm1001.2014.3001.5506 上面是详细讲解&#xff0c;我这篇是总结了他的代码&#xff0c;因为他没给整体代码 所有代码&#xff1a; #include <stdio.h> #include <stdlib.h&g…

Python Django Jet:优化 Django 后台管理

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 大家好&#xff0c;今天分享 Python 中的 Django Jet 库。 Github项目地址&#xff1a;https://github.com/geex-arts/django-jet Django Jet 是一个强大的 Django 后台管理界面扩展&#xff0c;旨在提供更现代…

人工智能125个常用名词解释

1 什么是人工智能 人工智能&#xff08;Artificial Intelligence&#xff0c;简称AI&#xff09;是指计算机系统通过模拟人类的思维和行为来完成特定任务的技术和方法。人工智能的研究涉及多个学科&#xff0c;包括计算机科学、数学、心理学、哲学等领域。 人工智能可以被分为…

SVM —— 理论推导

SVM 支持向量线性可分最大间隔超平面最大间隔超平面的推导支持向量分类间隔的推导最优化问题 对偶问题拉格朗日乘子法强对偶性 SVM 优化软间隔解决问题优化目标及求解 核函数线性不可分核函数的作用常见核函数 SVM 算法优缺点 支持向量机&#xff08;Support Vector Machine&am…

Collecting package metadata (current_repodata.json): failed(解决方案)

如果有重装过anaconda&#xff0c;在C盘的用户目录下&#xff0c;会有一个名叫.condarc的文件会自动生成。 当使用conda install和conda create命令会出现下面的问题&#xff1a;Collecting package metadata (current_repodata.json): failed 解决方案&#xff1a; 1.打开Anac…

Leetcod面试经典150题刷题记录 —— 双指针篇

双指针篇 1. 验证回文串Python3 2. 判断子序列Python3双指针 3. 两数之和 II - 输入有序数组Python3 4. 盛最多水的容器Python3双指针 5. 三数之和 1. 验证回文串 题目链接&#xff1a;验证回文串 - leetcode 题目描述&#xff1a; 如果在将所有大写字符转换为小写字符、并移除…