C++最易读手撸神经网络两隐藏层(任意Nodes每层)梯度下降230821a
// c++神经网络手撸20梯度下降22_230820a.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
#include<iostream>
#include<vector>
#include<iomanip> // setprecision
#include<sstream> // getline stof()
#include<fstream>
using namespace std;
//
float Loss误差损失之和001 = 0.0;
class NN神经网络NN {
private:
const int inputNode输入层之节点数s, hidden01Node隐藏层01结点数s, hidden22Nodes, outputNode输出层结点数s;
/*
vector<vector<float>> 输入层到第1隐藏层之权重矩阵, 隐藏层1到第二隐藏层2之权重矩阵1to2, 隐藏22到输出层de权重矩阵; //这些变量为矩阵
vector<float> 隐藏层1偏置1, 隐藏层2偏置2, O输出层偏置;
vector<float>隐藏层1数据1, 隐藏层2数据2, 输出数据output; */
void initLayer每一层的WeightsAndBiases(vector<vector<float>>& weights权重, vector<float>& biases偏置)
{
for (size_t i = 0; i < weights权重.size(); ++i) {//for110i
for (size_t j = 0; j < weights权重[0].size(); ++j) { weights权重[i][j] = ((rand() % 2) - 1) / 1.0; }
biases偏置[i] = ((rand() % 2) - 1) / 1.0;
}//for110i
}//void initLayerWeightsAndBiases(
void initWeightsAndBiases初始化权重和偏置矩阵() {
initLayer每一层的WeightsAndBiases(输入层到第1隐藏层之权重矩阵, 隐藏层1偏置1);
initLayer每一层的WeightsAndBiases(隐藏层1到第二隐藏层2之权重矩阵1to2, 隐藏层2偏置2);
initLayer每一层的WeightsAndBiases(隐藏22到输出层de权重矩阵 , O输出层偏置);
}
//激活函数-激活的过程
vector<float> activate(const vector<float>& inputs, const vector< vector<float>>& weights, const vector<float>& biases) {
vector<float> layer_output(weights.size(), 0.0);
for (size_t i = 0; i < weights.size(); i++) {
for (size_t j = 0; j < inputs.size(); j++) {
layer_output[i] += inputs[j] * weights[i][j];
}//for220j
layer_output[i] += biases[i];
layer_output[i] = sigmoid(layer_output[i]);
}//for110i
return layer_output;
}//vector<float> activate
//subtract求差:两个 向量的差
vector<float> subtract(const vector<float>& a, const vector<float>& b) {
vector<float> result(a.size(), 0.0);
for (size_t i = 0; i < a.size(); i++) {
result[i] = a[i] - b[i];
}
return result;
}//vector<float>subtract
//dotT点乘
vector<float> dotT(const vector<float>& a, const vector< vector<float>>& b) {
vector<float> result(b[0].size(), 0.0);
for (size_t i = 0; i < b[0].size(); i++) {
for (size_t j = 0; j < a.size(); j++) {
result[i] += a[j] * b[j][i];
}
}
return result;
}
//更新权重矩阵s(们), 和偏置(向量)S们
void updateWeights(const vector<float>& inputs, const vector<float>& errors, const vector<float>& outputs,
vector< vector<float>>& weights, vector<float>& biases, float lr) {
for (size_t i = 0; i < weights.size(); i++) {
for (size_t j = 0; j < weights[0].size(); j++) {
weights[i][j] += lr * errors[i] * sigmoid导函数prime(outputs[i]) * inputs[j];
}
biases[i] += lr * errors[i] * sigmoid导函数prime(outputs[i]);
}
}//void updateWeights(
public:
vector<vector<float>> 输入层到第1隐藏层之权重矩阵, 隐藏层1到第二隐藏层2之权重矩阵1to2, 隐藏22到输出层de权重矩阵; //这些变量为矩阵
vector<float> 隐藏层1偏置1, 隐藏层2偏置2, O输出层偏置;
vector<float>隐藏层1数据1, 隐藏层2数据2, 输出数据output;
NN神经网络NN(int inputNode输入层之节点数s, int hidden01Node隐藏层01结点数s, int hidden22Nodes, int outputNode输出层结点数s)
:inputNode输入层之节点数s(inputNode输入层之节点数s), hidden01Node隐藏层01结点数s(hidden01Node隐藏层01结点数s), hidden22Nodes(hidden22Nodes), outputNode输出层结点数s(outputNode输出层结点数s)
{
srand(time(NULL));
//初始换权重矩阵
输入层到第1隐藏层之权重矩阵.resize(hidden01Node隐藏层01结点数s, vector<float>(inputNode输入层之节点数s));
隐藏层1到第二隐藏层2之权重矩阵1to2.resize(hidden22Nodes, vector<float>(hidden01Node隐藏层01结点数s));
隐藏22到输出层de权重矩阵.resize(outputNode输出层结点数s, vector<float>(hidden22Nodes));//
隐藏层1偏置1.resize(hidden01Node隐藏层01结点数s);
隐藏层2偏置2.resize(hidden22Nodes);
O输出层偏置.resize(outputNode输出层结点数s);
initWeightsAndBiases初始化权重和偏置矩阵();
}//NN神经网络NN(i
//sigmoid激活函数及导数
float sigmoid(float x){ return 1.0 / (1.0 + exp(-x)); }
float sigmoid导函数prime(float x) { return x * (1 - x); }
//Forward前向传播
vector<float> predict(const vector<float>& input输入数据) {
//用激活函数sigmoid-激活的过程
隐藏层1数据1 = activate(input输入数据, 输入层到第1隐藏层之权重矩阵, 隐藏层1偏置1); //激活函数
// 第一隐藏层到第二隐藏层
隐藏层2数据2 = activate(隐藏层1数据1, 隐藏层1到第二隐藏层2之权重矩阵1to2, 隐藏层2偏置2);//hidden1, wh1h2, bias_h2);
// 第二隐藏层到输出层
输出数据output = activate(隐藏层2数据2, 隐藏22到输出层de权重矩阵, O输出层偏置);// , wh2o, bias_o);
return 输出数据output;
}//vector<float>predict(
// 反向传播//Backpropagation
void train(const vector<float>& inputs, const vector<float>& target目标数据s, float lr学习率) {
vector<float> output尝试的输出数据s = predict(inputs);
// 输出层误差
vector<float> output_error输出误差s = subtract(target目标数据s, output尝试的输出数据s);//
Loss误差损失之和001 = 0.0;
for (int ii = 0; ii < outputNode输出层结点数s; ++ii) { Loss误差损失之和001 += fabs(output_error输出误差s[ii]); }
//=========================================================================
// 隐藏层2误差
vector<float> hidden2_errors = dotT(output_error输出误差s, 隐藏22到输出层de权重矩阵);
// 隐藏层1误差
vector<float> hidden1_errors = dotT(hidden2_errors, 隐藏层1到第二隐藏层2之权重矩阵1to2);
// 更新权重: 隐藏层2到输出层(的权重矩阵
updateWeights(隐藏层2数据2, output_error输出误差s, output尝试的输出数据s, 隐藏22到输出层de权重矩阵, O输出层偏置, lr学习率);
// 更新权重: 隐藏层1到隐藏层2
updateWeights(隐藏层1数据1, hidden2_errors, 隐藏层2数据2, 隐藏层1到第二隐藏层2之权重矩阵1to2, 隐藏层2偏置2, lr学习率);
// 更新权重: 输入层到隐藏层1的权重矩阵)
updateWeights(inputs, hidden1_errors, 隐藏层1数据1, 输入层到第1隐藏层之权重矩阵, 隐藏层1偏置1, lr学习率);
}// void train(
// // 反向传播//Backpropagation
};//class NN神经网络NN {
//----------------------------------------------------------------------------------------
void writeVectorToFile(const std::vector<float>& A, const std::string& fileName) {
std::ofstream outFile(fileName);
if (outFile.is_open()) {
for (float value : A) {
outFile << value << std::endl;
}
outFile.close();
}
else {
std::cerr << "Unable to open file for writing: " << fileName << std::endl;
}
}//writeVectorToFile
void readVectorFromFile(std::vector<float>& B, const std::string& fileName) {
std::ifstream inFile(fileName);
float value;
if (inFile.is_open()) {
while (inFile >> value) {
B.push_back(value);
}
inFile.close();
}
else {
std::cerr << "Unable to open file for reading: " << fileName << std::endl;
}
}//readVectorFromFile
#include <iostream>
#include <vector>
#include <fstream>
#include <string>
#include <sstream>
void writeToFile( const std::vector<std::vector<float>>& A , const std::string& filename) {
std::ofstream file(filename);
if (!file) {
std::cerr << "Error opening file for writing: " << filename << std::endl;
return;
}
for (const auto& row : A) {
for (size_t i = 0; i < row.size(); ++i) {
file << row[i];
if (i != row.size() - 1) {
file << ",";
}
}
file << "\n";
}
file.close();
}//void writeToFile
std::vector<std::vector<float>> readFromFile(const std::string& filename) {
std::vector<std::vector<float>> B;
std::ifstream file(filename);
if (!file) {
std::cerr << "Error opening file for reading: " << filename << std::endl;
return B;
}
std::string line;
while (std::getline(file, line)) {
std::vector<float> row;
std::stringstream ss(line);
std::string value;
while (std::getline(ss, value, ',')) {
row.push_back(std::stof(value));
}
B.push_back(row);
}
file.close();
return B;
}//readFromFile(
//----------------------------------------------------------------------------------------
#define Num训练数据的个数s 4
int main()
{
NN神经网络NN nn(2, 4, 3, 1);// 2, 3, 2, 1);// 11, 10, 4);
// Example
int 训练数据的个数s = Num训练数据的个数s;
vector<float> input[Num训练数据的个数s];
/* input[0] = {0,1,0, 0,1,0, 0,1,0}; //1“竖线”或 “1”字{ 1.0, 0.5, 0.25, 0.125 };
input[1] = { 0,0,0, 1,1,1,0,0,0 }; //-“横线”或 “-”减号{ 1.0, 0.5, 0.25, 0.125 };
input[2] = { 0,1,0, 1,1,1, 0,1,0 }; //+“+”加号{ 1.0, 0.5, 0.25, 0.125 };
input[3] = { 0,1,0, 0,1.2, 0, 0,1, 0 }; // '1'或 '|'字型{ 1.0, 0.5, 0.25, 0.125 };
input[4] = { 1,1,0, 1,0,1.2, 1,1,1 }; //“口”字型+{ 1.0, 0.5, 0.25, 0.125 };
vector<float> target[Num训练数据的个数s];
target[0] = { 1.0, 0,0,0 };// , 0};//1 , 0}; //0.0, 1.0, 0.5}; //{ 0.0, 1.0 };
target[1] = { 0, 1.0 ,0,0 };// , 0};//- 91.0, 0};// , 0, 0}; //
target[2] = { 0,0,1.0,0 };// , 0};//+ 1.0, 0.5};
target[3] = { 1.0 ,0,0, 0.5 };// , 0}; //1
target[4] = { 0,0,0,0 };// , 1.0}; //“口”
*/
vector<float> target[Num训练数据的个数s];
input[0] = { 0,0 }; target[0] = { 0 }; //"-"
input[1] = { 1,0 }; target[1] = { 1 };
input[2] = { 1,1}; target[2] = { 0};
input[3] = { 0,1 }; target[3] = { 1 };
string str0001;
LabeStart001:
//--------------------------------------------------------------------------------------
cout << "1_Trainning;" << endl;
cout << "2_Test;" << endl;
cout << "3_quit." << endl;
getline(cin, str0001);
stringstream s01s001(str0001);
string temp;
getline(s01s001, temp, ',');
int choice = (float)stof(temp); //
switch (choice) {
case 1:
goto LabeTraining;
case 2:
goto LabeTest;
case 3:
return 0;
}
LabeTraining:
for (int i = 0; i < 90000; ++i) {//for110i
for (int jj = 0; jj < Num训练数据的个数s ; ++jj) {
//for (auto& val: input ) {
nn.train(input[jj], target[jj], 0.001);
if (0 ==i % 10000) { std::cout << "[Lost:" << Loss误差损失之和001 << endl; }
}//for220jj
}//for110i
// writeToFile( nn.输入层到第1隐藏层之权重矩阵 , "/file输入层到第1隐藏层之权重矩阵Name220101.txt");
writeToFile(nn.输入层到第1隐藏层之权重矩阵, "/file输入层到第1隐藏层之权重矩阵Name220101.txt");
writeToFile(nn.隐藏22到输出层de权重矩阵, "/file隐藏22到输出层de权重矩阵Name220101.txt");
writeToFile(nn.隐藏层1到第二隐藏层2之权重矩阵1to2, "/file隐藏层1到第二隐藏层2之权重矩阵1to2Name220101.txt");
writeVectorToFile( nn.隐藏层1偏置1, "/file隐藏层1偏置1.txt");
writeVectorToFile(nn.隐藏层2偏置2, "/file隐藏层2偏置2.txt");
writeVectorToFile(nn.O输出层偏置, "/fileO输出层偏置.txt");
std::cout << endl;
LabeTest:
//--------------------------------------
input[1] = { 0,1 };// 0, 0, 1, 1, 0.98, 0, 0, 0}; //1/
vector<float> outpu输出数据001t = nn.predict(input[0]);
for (auto& val : outpu输出数据001t)
std::cout << fixed << setprecision(9) << val << " ";
std::cout << endl;
//-------------------------------------------------------------
// do {
std::cout << endl << "请输入一个字符串(要求字符串是包含9个由逗号分隔的数字的字符串,如 1,2,0,0,5,0,0,8,9等): " << endl;
getline( cin, str0001);
stringstream
s01s002(str0001);
for (int i = 0; i < 2;++i) {//
//9; ++i) {
string temp;
getline(s01s002, temp, ',');
input[1][i] = (float) stof(temp); // 将字符串转化为整数
}
std::cout << "数字数组为: ";
for (int i = 0; i < 2;++i) {// 9; ++i) {
std::cout << input[1][i] << " ";
}
//
readVectorFromFile(nn.隐藏层1偏置1, "/file隐藏层1偏置1.txt");
readVectorFromFile(nn.隐藏层2偏置2, "/file隐藏层2偏置2.txt");
readVectorFromFile(nn.O输出层偏置, "/fileO输出层偏置.txt");
nn.输入层到第1隐藏层之权重矩阵 = readFromFile("/file输入层到第1隐藏层之权重矩阵Name220101.txt");
nn.隐藏层1到第二隐藏层2之权重矩阵1to2 = readFromFile("/file隐藏层1到第二隐藏层2之权重矩阵1to2Name220101.txt");
nn.隐藏22到输出层de权重矩阵 = readFromFile("/file隐藏22到输出层de权重矩阵Name220101.txt");
//
outpu输出数据001t = nn.predict(input[1]);
std::cout << endl;
for (auto& val : outpu输出数据001t)
std::cout << fixed << setprecision(9) << val << " ";
cout << endl;
// } while (true);// 1 == 1);
//======================================
std::cout << "Hello World!请继续……您可以继续训练网络,或者测试网络!\n";
goto LabeStart001;
}//main
相关文章:
C++最易读手撸神经网络两隐藏层(任意Nodes每层)梯度下降230821a
// c神经网络手撸20梯度下降22_230820a.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 #include<iostream> #include<vector> #include<iomanip> // setprecision #include<sstream> // getline stof() #include<fstream…...
Leetcode 2235.两整数相加
一、两整数相加 给你两个整数 num1 和 num2,返回这两个整数的和。 示例 1: 输入:num1 12, num2 5 输出:17 解释:num1 是 12,num2 是 5 ,它们的和是 12 5 17 ,因此返回 17 。示例…...
Postman —— postman实现参数化
什么时候会用到参数化 比如:一个模块要用多组不同数据进行测试 验证业务的正确性 Login模块:正确的用户名,密码 成功;错误的用户名,正确的密码 失败 postman实现参数化 在实际的接口测试中,部分参数每…...
LeetCode--HOT100题(41)
目录 题目描述:102. 二叉树的层序遍历(中等)题目接口解题思路代码 PS: 题目描述:102. 二叉树的层序遍历(中等) 给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地&am…...
微信小程序教学系列(6)
第六章:小程序商业化 第一节:小程序的商业模式 在这一节中,我们将探讨微信小程序的商业模式,让你了解如何将你的小程序变成一个赚钱的机器! 1. 广告收入 小程序的商业模式之一是通过广告收入赚钱。你可以在小程序中…...
小程序中的全局配置以及常用的配置项(window,tabBar)
全局配置文件和常用的配置项 app.json: pages:是一个数组,用于记录当前小程序所有页面的存放路径,可以通过它来创建页面 window:全局设置小程序窗口的外观(导航栏,背景,页面的主体) tabBar:设置小程序底部的 tabBar效果 style:是否…...
数据工厂调研及结果展示
数据工厂 一、背景 在开发自测、测试迭代测试、产品验收的过程中,都需要各种各样的前置数据,大致分为如下几类: 账号(实名、权益等级、注册等) 货源(优货、急走、相似、一手、普通货源等) …...
抓包相关,抓包学习
检查网络流量 - 提琴手经典 (telerik.com) Headers Reference - Fiddler Classic (telerik.com) 以上是fiddler官方文档 F12要勾选保留日志 不勾选的话跳转到新页面之前页面的日志不会在下方显示 会保留所有抓到的包 如果重定向到别的页面 F12抓包可能看不到响应信息,但是…...
云原生之使用Docker部署SSCMS内容管理系统
云原生之使用Docker部署SSCMS内容管理系统 一、SSCMS介绍二、本地环境介绍2.1 本地环境规划2.2 本次实践介绍 三、本地环境检查3.1 检查Docker服务状态3.2 检查Docker版本3.3 检查docker compose 版本 四、下载SSCMS镜像五、部署SSCMS内容管理系统5.1 创建SSCMS容器5.2 检查SSC…...
uniapp -- 在组件中拿到pages.json下pages设置navigationBarTitleText这个值?
1:在 pages.json 文件中设置 navigationBarTitleText,例如: {"pages": [{"path": "pages/home/index","style": {"navigationBarTitleText": "首页",&...
Java获取环境变量和运行时环境信息和自定义配置信息
System.getenv() 获取系统环境变量 public static void main1() {Map<String, String> envMap System.getenv();envMap.entrySet().forEach(x-> System.out.println(x.getKey() "" x.getValue())); } System.getenv() 获取的是操作系统环境变量列表&…...
React入门 组件学习笔记
项目页面以组件形式层层搭起来,组件提高复用性,可维护性 目录 一、函数组件 二、类组件 三、 组件的事件绑定 四、获取事件对象 五、事件绑定传递额外参数 六、组件状态 初始化状态 读取状态 修改状态 七、组件-状态修改counter案例 八、this问…...
Windows商店引入SUSE Linux Enterprise Server和openSUSE Leap
在上个月的Build 2017开发者大会上,微软宣布将SUSE,Ubuntu和Fedora引入Windows 商店,反应出微软对开放源码社区的更多承诺。 该公司去年以铂金会员身份加入Linux基金会。现在,微软针对内测者的Windows商店已经开始提供 部分Linux发…...
[NLP]深入理解 Megatron-LM
一. 导读 NVIDIA Megatron-LM 是一个基于 PyTorch 的分布式训练框架,用来训练基于Transformer的大型语言模型。Megatron-LM 综合应用了数据并行(Data Parallelism),张量并行(Tensor Parallelism)和流水线并…...
软考高级系统架构设计师系列论文七十八:论软件产品线技术
软考高级系统架构设计师系列论文七十八:论软件产品线技术 一、摘要二、正文三、总结一、摘要 本人作为某软件公司负责人之一,通过对位于几个省的国家甲级、乙级、丙级设计院的考查和了解,我决定采用软件产品线方式开发系列《设计院信息管理平台》产品。该产品线开发主要有如…...
yolov5中添加ShuffleAttention注意力机制
ShuffleAttention注意力机制简介 关于ShuffleAttention注意力机制的原理这里不再详细解释.论文参考如下链接here yolov5中添加注意力机制 注意力机制分为接收通道数和不接受通道数两种。这次属于接受通道数注意力机制,这种注意力机制由于有通道数要求,所示我们添加的时候…...
Effective C++条款17——以独立语句将newed 对象置入智能指针(资源管理)
假设我们有个函数用来揭示处理程序的优先权,另一个函数用来在某动态分配所得的widget上进行某些带有优先权的处理: void priority(); void processWidget(std::tr1::shared_ptr<Widget>pw, int priority);由于谨记“以对象管理资源”(条款13&…...
奇迹MU服务器如何选择配置?奇迹MU服务器租用
不同的服务器,根据其特点与性能适用于不同的应用场景,为了让你们更好的理解,我们对服务器进行了分类归纳,结合了服务器不同的特点以及价位进行一个区分,帮助我们更好的选择合适的服务器配置。 VPS服务器 VPS服务器又…...
如何远程管理服务器详解
文章目录 前言一、远程管理类型二、远程桌面三、telnet 命令行远程四、查看本地开放端口 前言 很多公司是有自己的机房的,机房里面会有若干个服务器为员工和用户提供服务。大家可以想想:假设这家公司有上百台服务器,我们作为网络工程师&…...
JavaScript——为什么静态方法不能调用非静态方法
个人简介 👀个人主页: 前端杂货铺 🙋♂️学习方向: 主攻前端方向,正逐渐往全干发展 📃个人状态: 研发工程师,现效力于中国工业软件事业 🚀人生格言: 积跬步…...
19c补丁后oracle属主变化,导致不能识别磁盘组
补丁后服务器重启,数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后,存在与用户组权限相关的问题。具体表现为,Oracle 实例的运行用户(oracle)和集…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
在四层代理中还原真实客户端ngx_stream_realip_module
一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡(如 HAProxy、AWS NLB、阿里 SLB)发起上游连接时,将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后,ngx_stream_realip_module 从中提取原始信息…...
Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...
k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...
IT供电系统绝缘监测及故障定位解决方案
随着新能源的快速发展,光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域,IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选,但在长期运行中,例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...
SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...
