学习笔记—数据结构—二叉树(链式)

目录

二叉树(链式)

概念

结构

初始化

遍历

前序遍历

中序遍历

后序遍历

层序遍历

结点个数

叶子结点个数

第k层结点个数

深度/高度

查找值为x的结点

销毁

判断是否为完整二叉树

总结

头文件Tree.h

Tree.c

测试文件test.c

补充文件Queue.h

补充文件Queue.c


二叉树(链式)

概念

用链表来表示⼀棵二叉树,即用链来指示元素的逻辑关系。 通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址

结构

//二叉树结点的结构
typedef int BTDataType;
typedef struct BinaryTreeNode
{BTDataType data;               //值域struct BinaryTreeNode* left;   //左孩子struct BinaryTreeNode* right;  //右孩子
}BTNode;

初始化

//初始化
BTNode* buyNode(BTDataType x)
{BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));if (newnode == NULL){perror("mallor fail!");exit(1);}newnode->data = x;newnode->left = newnode->right = NULL;return newnode;
}

遍历

前序遍历

前序遍历(Preorder Traversal 亦称先序遍历):访问根结点的操作发生在遍历其左右⼦树之前

访问顺序为:根结点、左子树、右子树

//前序遍历--根左右
void PreOrder(BTNode* root)
{if (root == NULL){return;}printf("%d ", root->data);PreOrder(root->left);PreOrder(root->right);
}

中序遍历

中序遍历(Inorder Traversal):访问根结点的操作发生在遍历其左右子树之中(间)

访问顺序为:左子树、根结点、右子树

//中序遍历--左根右
void InOrder(BTNode* root)
{if (root == NULL){return;}InOrder(root->left);printf("%d ", root->data);InOrder(root->right);
}

后序遍历

后序遍历(Postorder Traversal):访问根结点的操作发生在遍历其左右子树之后

访问顺序为:左子树、右子树、根结点

//后续遍历--左右根
void PostOrder(BTNode* root)
{if (root == NULL){return;}PostOrder(root->left);PostOrder(root->right);printf("%d ", root->data);}

层序遍历

在二叉树的层序遍历是指按照树的层次顺序,从上到下、从左到右逐层访问二叉树的节点。这种遍历方式可以帮助我们了解二叉树的结构布局,特别是在处理树状数据结构时非常有用。

对于这么一个二叉树来说,我们通过层序遍历最后得到的是1 2 3 4 5 6

这里我们是不能通过递归来实现的

但是我们可以借助队列来实现这么一个结构

队列的结构是先进先出

恰好我们队列的底层结构就是链表来实现的,和这里的链式二叉树一样的

我们将之前写的Queue.c文件和Queue.h文件复制到我们链式二叉树的文件夹里面

typedef struct BinaryTreeNode* QDataType;

struct BinaryTreeNode*这个就是我们要保存在队列中的数据类型

之前的在队列中保存的数据类型是int类型

队列中存储的是堆节点的地址

那么存储的就是节点的指针,那么我们将这个类型重新定义

//层序遍历
void Levelorder(BTNode* root)
{//创建一个队列结构Queue q;QueueInit(&q);//进行初始化//第一步:让根节点直接入队列QueuePush(&q, root);//往队列中push根节点while (!Queuempty(&q))//只要队列不为空,我们就一直取队头数据{//取队头数据BTNode* front = QueueFront(&q);//将队头取出,返回值是节点的地址//打印对头printf("%d ", front->data);//让队头出队列QueuePop(&q);//那么此时的队列是空的//将队头节点的左右孩子入队列if (front->left)//如果这个节点的左孩子不是空的,那么我们将这个节点往队列中入{QueuePush(&q, front->left);}if (front->right)//如果这个节点的右孩子不是空的,那么我们将这个节点往队列中入{QueuePush(&q, front->right);}}QueueDestroy(&q);//销毁
}

结点个数

利用递归的方法,左右子树调用,如果该节点为NULL 便会返回0,否则返回1。

// 二叉树结点个数
int BinaryTreeSize(BTNode* root)
{if (root == NULL){return 0;}//递归return 1 + BinaryTreeSize(root->left) + BinaryTreeSize(root->right);
}

叶子结点个数

// 二叉树叶子结点个数
int BinaryTreeLeafSize(BTNode* root)
{if (root == NULL){return 0;}if (root->left ==NULL && root->right ==NULL){return 1;}//进行递归return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}

第k层结点个数

假设查找第三层,K为3 ,每次递归K–,知道K== 1 的时候 返回1

// 二叉树第k层结点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{if (root == NULL){return 0;}if (k == 1){return 1;}return BinaryTreeLevelKSize(root->left, (k - 1)) + BinaryTreeLevelKSize(root->right, (k - 1));
}

深度/高度

利用 left和right记录左右子树的个数,然后比较 选择较大的一个。

// 二叉树的深度/高度
int BinaryTreeDepth(BTNode* root)
{if (root == NULL){return 0;}int leftDep = BinaryTreeDepth(root->left);int rightDep = BinaryTreeDepth(root->right);return leftDep > rightDep ? leftDep + 1 : rightDep + 1;
}

查找值为x的结点

节点的查找,如果节点为NULL饭后NULL,如果此节点的data等于x,返回节点的地址。

// 二叉树查找值为x的结点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{if (root == NULL){return 0;}if (root->data == x){return 1;}BTNode* leftFind = BinaryTreeFind(root->left,x);if (leftFind){return leftFind;}BTNode* rightFind = BinaryTreeFind(root->right,x);if (leftFind){return rightFind;}return NULL;
}

销毁

// 二叉树销毁
void BinaryTreeDestory(BTNode** root)
{if (*root == NULL){return 0;}BinaryTreeDestory(&((*root)->left));BinaryTreeDestory(&((*root)->right));free(*root);*root = NULL;
}

判断是否为完整二叉树

除了最后一层,其它层的节点数达到最大,那么这个数就是完全二叉树

这里涉及到每层,那么这里还是要借助队列这么一个结构的

我们先取根节点放进队列,队列不为空,我们将队列中的节点取出来

然后将这个节点的左右孩子一起放进队列中去

我们再将队头取出,将队头的左右孩子放进去,如果孩子为空放个NULL进去

如果我们队列剩下的都是NULL的话,我们将队列中第一个NULL取出

那么我们取到的数据为空,取到为空的情况我们就跳出循环

//判断二叉树是否为完全二叉树
//借助队列
bool BinaryTreeComplete(BTNode* root)
{Queue q;QueueInit(&q);//进行初始化//将二叉树根节点入队列QueuePush(&q, root);//往队列中push根节点while (!Queuempty(&q))//队列不为空,我们就循环取队头{BTNode* front = QueueFront(&q);//将队头取出QueuePop(&q);//让队头出队,保证下次取到的是最新的队头数据//如果我们取到的front是空的话if (front == NULL)//如果此时的队头是空的,那么我们就取不到左右孩子{break;}//将队头的左右孩子取出放到队列中QueuePush(&q, front->left);QueuePush(&q, front->right);}//此时队列不一定为空while (!Queuempty(&q))//只要队列不为空{BTNode* front = QueueFront(&q);//取队头QueuePop(&q);//出队列//如果我们在队列中剩下的节点中遇到了节点的话,那么这个树就不是一个完全二叉树了if (front != NULL){QueueDestroy(&q);//销毁return false;}}QueueDestroy(&q);//销毁//到这里就说明没有找到完全二叉树return true;
}

总结

头文件Tree.h

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>//定义二叉树链式结构
//二叉树结点的结构
typedef int BTDataType;
typedef struct BinaryTreeNode
{BTDataType data;               //值域struct BinaryTreeNode* left;   //左孩子struct BinaryTreeNode* right;  //右孩子
}BTNode;//前序遍历
void PreOrder(BTNode* root);
//中序遍历
void InOrder(BTNode* root);
//后续遍历
void PostOrder(BTNode* root);// 二叉树结点个数
int BinaryTreeSize(BTNode* root);
// 二叉树叶子结点个数
int BinaryTreeLeafSize(BTNode* root);
// 二叉树第k层结点个数
int BinaryTreeLevelKSize(BTNode* root, int k);
// 二叉树的深度/高度
int BinaryTreeDepth(BTNode * root);
// 二叉树查找值为x的结点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);
// 二叉树销毁
void BinaryTreeDestory(BTNode** root);//层序遍历---借助数据结构(队列)
void Levelorder(BTNode* root);
//判断二叉树是否为完全二叉树
bool BinaryTreeComplete(BTNode* root);

Tree.c

#include"Tree.h"
#include"Queue.h"
//前序遍历--根左右
void PreOrder(BTNode* root)
{if (root == NULL){return;}printf("%d ", root->data);PreOrder(root->left);PreOrder(root->right);
}//中序遍历--左根右
void InOrder(BTNode* root)
{if (root == NULL){return;}InOrder(root->left);printf("%d ", root->data);InOrder(root->right);
}//后续遍历--左右根
void PostOrder(BTNode* root)
{if (root == NULL){return;}PostOrder(root->left);PostOrder(root->right);printf("%d ", root->data);}// 二叉树结点个数
int BinaryTreeSize(BTNode* root)
{if (root == NULL){return 0;}//递归return 1 + BinaryTreeSize(root->left) + BinaryTreeSize(root->right);
}// 二叉树叶子结点个数
int BinaryTreeLeafSize(BTNode* root)
{if (root == NULL){return 0;}if (root->left ==NULL && root->right ==NULL){return 1;}//进行递归return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}// 二叉树第k层结点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{if (root == NULL){return 0;}if (k == 1){return 1;}return BinaryTreeLevelKSize(root->left, (k - 1)) + BinaryTreeLevelKSize(root->right, (k - 1));
}// 二叉树的深度/高度
int BinaryTreeDepth(BTNode* root)
{if (root == NULL){return 0;}int leftDep = BinaryTreeDepth(root->left);int rightDep = BinaryTreeDepth(root->right);return leftDep > rightDep ? leftDep + 1 : rightDep + 1;
}// 二叉树查找值为x的结点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{if (root == NULL){return 0;}if (root->data == x){return 1;}BTNode* leftFind = BinaryTreeFind(root->left,x);if (leftFind){return leftFind;}BTNode* rightFind = BinaryTreeFind(root->right,x);if (leftFind){return rightFind;}return NULL;
}// 二叉树销毁
void BinaryTreeDestory(BTNode** root)
{if (*root == NULL){return 0;}BinaryTreeDestory(&((*root)->left));BinaryTreeDestory(&((*root)->right));free(*root);*root = NULL;
}//层序遍历
void Levelorder(BTNode* root)
{//创建一个队列结构Queue q;QueueInit(&q);//进行初始化//第一步:让根节点直接入队列QueuePush(&q, root);//往队列中push根节点while (!Queuempty(&q))//只要队列不为空,我们就一直取队头数据{//取队头数据BTNode* front = QueueFront(&q);//将队头取出,返回值是节点的地址//打印对头printf("%d ", front->data);//让队头出队列QueuePop(&q);//那么此时的队列是空的//将队头节点的左右孩子入队列if (front->left)//如果这个节点的左孩子不是空的,那么我们将这个节点往队列中入{QueuePush(&q, front->left);}if (front->right)//如果这个节点的右孩子不是空的,那么我们将这个节点往队列中入{QueuePush(&q, front->right);}}QueueDestroy(&q);//销毁
}//判断二叉树是否为完全二叉树
//借助队列
bool BinaryTreeComplete(BTNode* root)
{Queue q;QueueInit(&q);//进行初始化//将二叉树根节点入队列QueuePush(&q, root);//往队列中push根节点while (!Queuempty(&q))//队列不为空,我们就循环取队头{BTNode* front = QueueFront(&q);//将队头取出QueuePop(&q);//让队头出队,保证下次取到的是最新的队头数据//如果我们取到的front是空的话if (front == NULL)//如果此时的队头是空的,那么我们就取不到左右孩子{break;}//将队头的左右孩子取出放到队列中QueuePush(&q, front->left);QueuePush(&q, front->right);}//此时队列不一定为空while (!Queuempty(&q))//只要队列不为空{BTNode* front = QueueFront(&q);//取队头QueuePop(&q);//出队列//如果我们在队列中剩下的节点中遇到了节点的话,那么这个树就不是一个完全二叉树了if (front != NULL){QueueDestroy(&q);//销毁return false;}}QueueDestroy(&q);//销毁//到这里就说明没有找到完全二叉树return true;
}

测试文件test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"tree.h"BTNode* buyNode(BTDataType x)//创建一个节点
{BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));if (newnode == NULL){perror("malloc fail!");exit(1);}newnode->data = x;newnode->left = newnode->right = NULL;return newnode;
}
void test01()
{BTNode* node1 = buyNode(1);BTNode* node2 = buyNode(2);BTNode* node3 = buyNode(3);BTNode* node4 = buyNode(4);/*BTNode* node5 = buyNode(5);BTNode* node6 = buyNode(6);*/node1->left = node2;node1->right = node3;node2->left = node4;/*node2->right = node5;node3->left = node6;*///前序遍历PreOrder(node1);// 1 2 4 3printf("\n");//中序遍历InOrder(node1);// 4 2 1 3//二叉树节点的个数printf("size:%d\n", BinaryTreeSize(node1));//4printf("size:%d\n", BinaryTreeSize(node2));//2// 二叉树叶子结点的个数printf("leaf size:%d\n", BinaryTreeLeafSize(node1));//第k层节点的个数printf("k size:%d\n", BinaryTreeLevelKSize(node1, 3));//二叉树的高度printf("depth/height :%d\n", BinaryTreeDepth(node1));//查找值为x的节点BTNode*find=BinaryTreeFind(node1, 5);printf("%s\n", find == NULL ? "没找到":"找到了");//层序遍历Levelorder(node1);//判断是否为完全二叉树bool ret = BinaryTreeComplete(node1);printf("%s\n", ret == false ? "不是完全二叉树" : "是完全二叉树");//二叉树的销毁BinaryTreeDestory(&node1);}
int main()
{test01();return 0;
}

补充文件Queue.h

#pragma once#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>//定义队列结构
//typedef int QDataType;typedef struct BinaryTreeNode* QDataType;
//struct BinaryTreeNode*这个就是我们要保存在队列中的数据类型
//struct BinaryTreeNode*这个是个数据类型,和之前的
//之前的在队列中保存的数据类型是int类型
//因为我们在tree.h中将结构体类型重命名了
//那么我们可以这么写
//typedef struct BTNode* QDataType;typedef struct QueueNode
{QDataType data;struct QueueNode* next;}QueueNode;typedef struct Queue
{QueueNode* phead;//指向头节点的指针---队头--删除数据QueueNode* ptail;//指向尾节点的指针---队尾--插入数据int size;//保存队列有效个数
}Queue;//初始化
void QueueInit(Queue* pq);//入队列,队尾   插入数据
void QueuePush(Queue* pq, QDataType x);//出队列,队头    删除数据
void QueuePop(Queue* pq);//判断队列是否为空
bool Queuempty(Queue* pq);//取队头数据
QDataType QueueFront(Queue* pq);//取队尾数据
QDataType QueueBack(Queue* pq);//队列有效元素个数
int QueueSize(Queue* pq);//队列的销毁
void QueueDestroy(Queue* pq);

补充文件Queue.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"Queue.h"//初始化
void QueueInit(Queue* pq)
{assert(pq);//传过来的不能是空指针 pq->phead = pq->ptail = NULL;//空的队列pq->size = 0;
}//判断队列是否为空
bool Queuempty(Queue* pq)
{assert(pq);return pq->phead == NULL && pq->ptail == NULL;//如果后面的表达式成立,那么就是真,返回的是true//就是说如果这里的是空队列的话,那么就返回的是true
}//入队列,队尾   插入数据
void QueuePush(Queue* pq, QDataType x)
{assert(pq);//申请新节点QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));//申请一个节点大小的空间if (newnode == NULL){perror("malloc dail!");exit(1);}//对newnode进行初始化操作newnode->data = x;newnode->next = NULL;if (pq->phead == NULL)//说明队列为空{pq->phead = pq->ptail = newnode;//那么此时的newnode不仅是头结点也是尾节点}else//队列不为空{pq->ptail->next = newnode;//那么此时的newnode 就是新的ptailpq->ptail = newnode;}pq->size++;
}//出队列,队头    删除数据    从头结点开始删除数据
void QueuePop(Queue* pq)
{assert(pq);//队列为空(不可删除数据,因为没有数据)//队列不为空(可删除数据)assert(!Queuempty(pq));//队列为空白的话就报错//处理只有一个节点的情况,避免ptail变成野指针//判断只有一个节点的情况if (pq->ptail == pq->phead)//头尾指针相同,说明只有一个节点{free(pq->phead);//随便释放pq->phead = pq->ptail = NULL;}else//处理多个节点的情况{//删除队头元素//那么我们现将下个节点的位置进行保存QueueNode* next = pq->phead->next;//存储好之后我们直接将头结点进行释放free(pq->phead);pq->phead = next;//那么之前存的next就是新的头结点了}pq->size--;
}//取队头数据
QDataType QueueFront(Queue* pq)//返回队头数据
{assert(pq);assert(!Queuempty(pq));//队列不为空return pq->phead->data;//将队头里面的数据直接返回就行了
}//取队尾数据
QDataType QueueBack(Queue* pq)
{assert(pq);assert(!Queuempty(pq));//队列不为空return pq->ptail->data;
}//队列有效元素个数
int QueueSize(Queue* pq)
{assert(pq);//下面这种遍历的话效率太低了//int size = 0;//定义一个指针进行遍历//QueueNode* pcur = pq->phead;//指向队列的头结点//while (pcur)//pcur不为空就往后走//{//  size++;//  pcur = pcur->next;//}//return size;return pq->size;
}//队列的销毁
void QueueDestroy(Queue* pq)
{assert(pq);//assert(!Queuempty(pq));//队列不为空//遍历QueueNode* pcur = pq->phead;while (pcur){//销毁之前先把下个节点进行保存QueueNode* next = pcur->next;free(pcur);//将Pcur销毁之后,那么之前保存的next就是新的头结点pcur = next;}pq->phead = pq->ptail = NULL;pq->size = 0;
}

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

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

相关文章

Open GL ES ->GLSurfaceView在正交投影下的图片旋转、缩放、位移

XML文件 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:o…

Day78 | 灵神 | 反转链表 两两交换链表中的节点

Day78 | 灵神 | 反转链表 两两交换链表中的节点 24.两两交换链表中的节点 24. 两两交换链表中的节点 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 这道题就是下面这道题的k2的情况 25. K 个一组翻转链表 - 力扣&#xff08;LeetCode&#xff09; 基本思路和…

滤波---卡尔曼滤波

卡尔曼滤波概览 一、定义 卡尔曼滤波是一种基于线性系统和高斯噪声假设的递归最优状态估计算法。其核心目标是通过融合系统模型预测值与传感器测量值&#xff0c;在噪声环境中实时估计系统的动态状态&#xff08;如位置、速度、加速度等&#xff09;。 数学基础&#xff1a; …

23种设计模式-结构型模式-桥接器

文章目录 简介问题解决方案示例总结 简介 桥接器是一种结构型设计模式&#xff0c;可将一个大类或一系列紧密相关的类拆分为抽象和实现两个独立的层次结构&#xff0c;从而能在开发时分别使用。 问题 假如你有一个几何形状Shape类&#xff0c;它有两个子类&#xff1a;圆形C…

手工排查后门木马的常用姿势

声明&#xff01;本文章所有的工具分享仅仅只是供大家学习交流为主&#xff0c;切勿用于非法用途&#xff0c;如有任何触犯法律的行为&#xff0c;均与本人及团队无关&#xff01;&#xff01;&#xff01; 1. 检查异常文件 &#xff08;1&#xff09;查找最近修改的文件 # 查…

工业机器人核心算法体系解析:从感知到决策的技术演进

工业机器人作为智能制造的核心装备,其技术竞争力的本质是算法体系的优化与创新。从静态轨迹执行到动态环境适应,从单一任务控制到复杂场景决策,工业机器人的算法体系涵盖环境感知、运动控制、路径规划、行为决策四大核心模块。本文将深入解析各模块的关键算法及其技术演进,…

当 EcuBus-Pro + UTA0401 遇上 NSUC1500

文章目录 1.前言2.EcuBus-Pro简介2.1 官方地址2.2 概览 3.纳芯微NSUC1500简介3.1 NSUC1500概述3.2 产品特性 4.测试环境5.基础功能5.1 数据发送5.2 数据监控 6.自动化功能6.1 脚本创建6.2 脚本编辑6.3 脚本编辑与测试 7.音乐律动7.1 导入例程7.2 效果展示 ECB工程 1.前言 最近…

说说Redis的内存淘汰策略?

大家好&#xff0c;我是锋哥。今天分享关于【说说Redis的内存淘汰策略?】面试题。希望对大家有帮助&#xff1b; 说说Redis的内存淘汰策略? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Redis的内存淘汰策略用于管理当内存达到最大限制时&#xff0c;如何处理过…

Python实现音频数字水印方法

数字水印技术可以将隐藏信息嵌入到音频文件中而不明显影响音频质量。下面我将介绍几种在Python中实现音频数字水印的方法。 方法一&#xff1a;LSB (最低有效位) 水印 import numpy as np from scipy.io import wavfile def embed_watermark_lsb(audio_path, watermark, ou…

Altium Designer 24 PCB 走线倒圆弧方法

Altium Designer 24 PCB 走线倒圆弧方法 问题描述解决方法设置倒圆弧参数选择需要优化的走线进行走线优化 优化效果展示 在 PCB 设计中&#xff0c;走线转角过于尖锐不仅影响美观&#xff0c;还可能引起信号完整性问题。本文介绍如何在 Altium Designer 24 中通过倒圆弧优化走线…

Cookie与Token详解及测试需重点关注点

在现代Web应用中&#xff0c;Cookie 和 Token 是两种常见的身份验证与会话管理机制。它们分别在不同的场景下扮演着重要的角色&#xff0c;在性能、灵活性和安全性方面具有各自的特点。作为测试人员&#xff0c;理解它们的工作原理以及如何对其进行有效的测试&#xff0c;是保证…

Unity 2022.3.x部分Android设备播放视频黑屏问题

Android平台视频兼容性问题很多…类似的黑屏问题真的很头大&#xff0c;总结一些常见问题&#xff1a; 1. 视频文件不支持压缩 如果使用AssetBundle加载视频&#xff0c;这个AssetBundle压缩格式要选None。有人可能会说最新版Unity已经支持bundle压缩下播放视频&#xff0c;稳…

Redis - 概述

目录 ​编辑 一、什么是redis 二、redis能做什么&#xff08;有什么特点&#xff09;&#xff1f; 三、redis有什么优势 四、Redis与其他key-value存储有什么不同 五、Redis命令 六、Redis数据结构 1、基础数据结构 2、高级数据结构 一、什么是redis 1、redis&#x…

数据库部署在服务器表不存在解决方案

MySQL 数据库表不存在错误解决方案 MySqlException (0x80004005): Table store.SysLogOperate doesnt exist 服务器用的mysql5.6 用这个表syslogoperate只是全是小写 看起来你在使用 Pomelo.EntityFrameworkCore.MySql 作为 MySQL 数据库的提供程序&#xff0c;并且在初始化…

图灵完备——游戏中进行实践

图灵完备 简述结构一、基本逻辑电路1、低电平2、高电平3、非门4、与门5、三路与门6、或门7、三路或门8、与非门9、或非门10、异或门11、同或门 二、算数运算&&存储器1、二进制速算2、成对的麻烦 简述 这周就要学习计算机组成原理了&#xff0c;为了学起来不那么吃力&am…

踏过强化学习的每一步推导

给定 l [ a n , . . . , a 0 ] l[a_n, ..., a_0] l[an​,...,a0​]&#xff0c;现在 for idx in range(len(l)-2, -1, -1):l[idx] l[idx1] * ld注&#xff1a;这里的ld就是 λ \lambda λ&#xff0c;定义 λ 0 1 \lambda^01 λ01 证明变换后&#xff1a; l [ ∑ i 0 n …

AI小白的第七天:必要的数学知识(概率)

概率 Probability 1. 概率的定义 概率是一个介于 0 和 1 之间的数&#xff0c;表示某个事件发生的可能性&#xff1a; 0&#xff1a;事件不可能发生。1&#xff1a;事件必然发生。0 到 1 之间&#xff1a;事件发生的可能性大小。 例如&#xff0c;掷一枚公平的硬币&#xf…

UE5 + Rider + VsCode 接入腾讯的 Puerts 脚本

学习了一段时间 U&#xff0c;写点啥就得等编译&#xff0c;体验真的是一言难尽。。。。。。 然后就想着给自己找个脚本好了&#xff0c;调研了一下 AngelScript&#xff0c;puerts 的可行性。 AngelScript 看着真的诱人&#xff0c;但是发现连官方提供的都是 UE 的预编译版本…

凸包构造算法—Graham 扫描法

1. 理论原理推导 核心思想 Graham 扫描法基于以下基本思想&#xff1a; 极角排序&#xff1a; 选取一个参考点&#xff08;通常选择 y 坐标最小的点&#xff0c;若存在多个&#xff0c;则选 x 坐标最小的&#xff09;&#xff0c;将其他点按照与该参考点构成的极角进行升序排…

如何在 Windows 上安装与配置 Tomcat

Apache Tomcat 是一个开源的 Servlet 容器和 Web 服务器&#xff0c;广泛用于 Java Web 应用的开发和部署。它是实现 Java EE&#xff08;现称 Jakarta EE&#xff09;规范中的 Servlet 和 JSP 的官方参考实现。在本文中&#xff0c;我们将详细介绍如何在 Windows 系统上安装并…