C/C++ 数据结构与算法【哈夫曼树】 哈夫曼树详细解析【日常学习,考研必备】带图+详细代码

哈夫曼树(最优二叉树)

1)基础概念

**路径:**从树中一个结点到另一个结点之间的分支构成这两个结点间的路径。

**结点的路径长度:**两结点间路径上的分支数。

在这里插入图片描述

**树的路径长度:**从树根到每一个结点的路径长度之和。记作:TL。

在这里插入图片描述

结点数目相同的二叉树中,完全二叉树是路径长度最短的二叉树。

**权:**将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。

**结点的带权路径长度:**从根结点到该结点之间的路径长度与该结点的权的乘积。

**树的带权路径长度:**树中所有叶子结点的带权路径长度之和。

在这里插入图片描述

在这里插入图片描述

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

在这里插入图片描述

2)构造哈夫曼树

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

顺序存储结构——一维结构数组

(1)定义结构

在这里插入图片描述

typedef struct {int weight; int parent, lch, rch;
}HTNode, * HuffmanTree;HuffmanTree H;
(2)步骤:

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

  1. 初始化HT [1…2n-1]:lch = rch = parent = 0;
  2. 输入初始几个叶子结点:置HT[1…n]的 weight 值;
  3. 进行以下n-1次合并,依次产生n-1个结点HT[i],i = n + 1…2n-1:
    • 在HT[1…i-1]中选两个未被选过(从parent ==0 的结点中选)的weight最小的两个结点 HT[S1] 和 HT[S2],s1、s2为两个最小结点下标;
    • 修改 HT[s1] 和 HT[s2] 的parent值:HT[s1].parent = i; HT[s2] .parent = i;
    • 修改新产生的HT[i]:
HT[i].weight = HT[s1].weight + HT[s2].weight;
HTli].Ich = s1; 
HT[i].rch = s2;
void CreatHuffmanTree(HuffmanTree& HT, int n) { //构造哈夫曼树--哈夫曼算法if (n <= 1) return;int m = 2 * n - 1; // 数组共2n-1个元素HT = new HTNode[m + 1]; // 动态分配内存,0号单元未用,HT[m]表示根结点// 初始化2n-1个元素的lch、rch、parent为0for (int i = 1; i <= m; ++i) {HT[i].lch = HT[i].rch = HT[i].parent = 0;}// 输入前n个元素的weight值cout << "请输入" << n << "个字符的频率:" << endl;for (int i = 1; i <= n; ++i) {cin >> HT[i].weight;}// 构建哈夫曼树for (int i = n + 1; i <= m; i++) {int s1, s2;Select(HT, i - 1, s1, s2);HT[s1].parent = i;HT[s2].parent = i;HT[i].lch = s1;HT[i].rch = s2;HT[i].weight = HT[s1].weight + HT[s2].weight;}
}
(3)总代码:
权值为整数:
#include <iostream>
#include <limits.h>using namespace std;// 定义哈夫曼树节点结构
typedef struct {int weight;int parent, lch, rch;
} HTNode;typedef HTNode* HuffmanTree;// 选择两个双亲域为0且权值最小的结点
void Select(const HTNode* HT, int i, int& s1, int& s2) {s1 = s2 = -1;int min1 = INT_MAX, min2 = INT_MAX;for (int j = 1; j <= i; ++j) {if (HT[j].parent == 0 && HT[j].weight < min1) {min2 = min1;s2 = s1;min1 = HT[j].weight;s1 = j;}else if (HT[j].parent == 0 && HT[j].weight < min2) {min2 = HT[j].weight;s2 = j;}}
}void CreatHuffmanTree(HuffmanTree& HT, int n) { //构造哈夫曼树--哈夫曼算法if (n <= 1) return;int m = 2 * n - 1; // 数组共2n-1个元素HT = new HTNode[m + 1]; // 动态分配内存,0号单元未用,HT[m]表示根结点// 初始化2n-1个元素的lch、rch、parent为0for (int i = 1; i <= m; ++i) {HT[i].lch = HT[i].rch = HT[i].parent = 0;}// 输入前n个元素的weight值cout << "请输入" << n << "个字符的频率:" << endl;for (int i = 1; i <= n; ++i) {cin >> HT[i].weight;}// 构建哈夫曼树for (int i = n + 1; i <= m; i++) {int s1, s2;Select(HT, i - 1, s1, s2);HT[s1].parent = i;HT[s2].parent = i;HT[i].lch = s1;HT[i].rch = s2;HT[i].weight = HT[s1].weight + HT[s2].weight;}
}int main() {int n;cout << "请输入叶子节点的数量:";cin >> n;HuffmanTree HT;CreatHuffmanTree(HT, n);// 打印哈夫曼树(示例)cout << "哈夫曼树构造完成,打印结果如下:" << endl;for (int i = 1; i < 2 * n; ++i) {cout << "Node " << i << ": Weight=" << HT[i].weight<< ", Parent=" << HT[i].parent<< ", Left Child=" << HT[i].lch<< ", Right Child=" << HT[i].rch << endl;}delete[] HT; // 释放动态分配的内存return 0;
}
权值为浮点数
#include <iostream>
#include <limits.h> // 如果不再使用 INT_MAX,可以不需要这个头文件using namespace std;// 定义哈夫曼树节点结构,将 weight 改为 double 类型
typedef struct {double weight;  // 权值改为 double 类型int parent, lch, rch;
} HTNode;typedef HTNode* HuffmanTree;// 选择两个双亲域为0且权值最小的结点
void Select(const HTNode* HT, int i, int& s1, int& s2) {s1 = s2 = -1;double min1 = DBL_MAX, min2 = DBL_MAX; // 使用 DBL_MAX 作为最大值初始化for (int j = 1; j <= i; ++j) {if (HT[j].parent == 0 && HT[j].weight < min1) {min2 = min1;s2 = s1;min1 = HT[j].weight;s1 = j;}else if (HT[j].parent == 0 && HT[j].weight < min2) {min2 = HT[j].weight;s2 = j;}}
}void CreatHuffmanTree(HuffmanTree& HT, int n) { //构造哈夫曼树--哈夫曼算法if (n <= 1) return;int m = 2 * n - 1; // 数组共2n-1个元素HT = new HTNode[m + 1]; // 动态分配内存,0号单元未用,HT[m]表示根结点// 初始化2n-1个元素的lch、rch、parent为0for (int i = 1; i <= m; ++i) {HT[i].lch = HT[i].rch = HT[i].parent = 0;HT[i].weight = 0.0; // 初始化 weight 为 0.0}// 输入前n个元素的weight值cout << "请输入" << n << "个字符的小数频率:" << endl;for (int i = 1; i <= n; ++i) {cin >> HT[i].weight;}// 构建哈夫曼树for (int i = n + 1; i <= m; i++) {int s1, s2;Select(HT, i - 1, s1, s2);HT[s1].parent = i;HT[s2].parent = i;HT[i].lch = s1;HT[i].rch = s2;HT[i].weight = HT[s1].weight + HT[s2].weight;}
}int main() {int n;cout << "请输入叶子节点的数量:";cin >> n;HuffmanTree HT;CreatHuffmanTree(HT, n);// 打印哈夫曼树(示例)cout << "哈夫曼树构造完成,打印结果如下:" << endl;for (int i = 1; i <= 2 * n - 1; ++i) { // 注意这里应该是 2*n-1 而不是 2*ncout << "Node " << i << ": Weight=" << HT[i].weight<< ", Parent=" << HT[i].parent<< ", Left Child=" << HT[i].lch<< ", Right Child=" << HT[i].rch << endl;}delete[] HT; // 释放动态分配的内存return 0;
}
(4)运行结果:

在这里插入图片描述

3)哈夫曼编码

在远程通讯中,要将待传字符转换成由二进制的字符串:
在这里插入图片描述

若将编码设计为长度不等的二进制编码,即让待传字符串中出现次数较多的字符采用尽可能短的编码,则转换的二进制字符串便可能减少。
在这里插入图片描述

问题1 :什么样的前缀码能使得电文总长最短?

——哈夫曼编码

方法:

1、统计字符集中每个字符在电文中出现的平均概率(概率越大要求编码越短)。

2、利用哈夫曼树的特点:权越大的叶子离根越近;将每个字符的概率值作为权值,构造哈夫曼树。 则概率越大的结点,路径越短。

3、在哈夫曼树的每个分支上标上0或1:

  • 结点的左分支标0,右分支桥 1。
  • 把从根到每个吐子的路径上的标号连接起来,作为该叶子代表的字符的编码。

在这里插入图片描述

问题2 :为什么哈夫曼编码能够保证是前缀编码?

因为没有一片树叶是另一片树叶的祖先,所以每个叶结点的编码就不可能是其它叶结点编码的前缀。

问题 3 :为什么哈夫曼编码能够保证字符编码总长最短?

因为哈夫曼树的带权路径长度最短,故字符编码的总长最短。

  • 性质1 哈夫曼编码是前缀码
  • 性质2 哈夫曼编码是最优前缀码
算法实现:
// 从叶子到根逆向求每个字符的哈夫曼编码,存储在编码表HC中
void CreatHuffmanCode(const HuffmanTree& HT, HuffmanCode& HC, int n) {HC = new char*[n + 1]; // 分配n个字符编码的头指针数组char* cd = new char[n]; // 分配临时存放编码的动态数组空间cd[n - 1] = '\0'; // 编码结束符for (int i = 1; i <= n; ++i) {int start = n - 1;int c = i;int f = HT[i].parent;// 从叶子结点开始向上回溯,直到根结点while (f != 0) {--start;if (HT[f].lch == c)cd[start] = '0'; // 结点c是f的左孩子,则生成代码0elsecd[start] = '1'; // 结点c是f的右孩子,则生成代码1c = f;f = HT[f].parent;}// 计算编码长度并分配适当的空间int codeLength = n - start;HC[i] = new char[codeLength];strncpy(HC[i], &cd[start], codeLength);HC[i][codeLength - 1] = '\0'; // 确保字符串以空字符终止}delete[] cd; // 释放临时空间
}

strncpy(HC[i], &cd[start], codeLength);语句在C++中确实可以用于复制字符数组,但它有一些潜在的问题和局限性。特别是当你使用strncpy时,如果目标缓冲区没有足够的空间来包含源字符串加上终止空字符(\0),它不会自动添加终止空字符,这可能会导致后续操作出现问题。

此外,在现代C++中,更推荐使用std::string来处理字符串,因为它们更安全、更方便,并且可以避免手动管理内存的复杂性和风险。

// 从叶子到根逆向求每个字符的哈夫曼编码,存储在编码表HC中
void CreatHuffmanCode(const HuffmanTree& HT, HuffmanCode& HC, int n) {HC.resize(n + 1); // 分配n个字符编码的空间for (int i = 1; i <= n; ++i) {string code = "";int c = i;int f = HT[i].parent;// 从叶子结点开始向上回溯,直到根结点while (f != 0) {if (HT[f].lch == c)code = '0' + code; // 结点c是f的左孩子,则生成代码0elsecode = '1' + code; // 结点c是f的右孩子,则生成代码1c = f;f = HT[f].parent;}HC[i] = code;}
}
总代码实现:

在这里插入图片描述

#include <iostream>
#include <cstring> // 用于 strcpy 和 strlen
#include <limits>  // 用于 std::numeric_limitsusing namespace std;// 定义哈夫曼树节点结构
typedef struct HTNode {double weight; // 权重改为 double 类型int parent, lch, rch;
} HTNode;typedef HTNode* HuffmanTree;// 定义哈夫曼编码结构
typedef char** HuffmanCode;// 选择两个双亲域为0且权值最小的结点
void Select(const HTNode* HT, int i, int& s1, int& s2) {s1 = s2 = -1;double min1 = numeric_limits<double>::max(), min2 = numeric_limits<double>::max();for (int j = 1; j <= i; ++j) {if (HT[j].parent == 0 && HT[j].weight < min1) {min2 = min1;s2 = s1;min1 = HT[j].weight;s1 = j;} else if (HT[j].parent == 0 && HT[j].weight < min2) {min2 = HT[j].weight;s2 = j;}}
}// 构造哈夫曼树--哈夫曼算法
void CreatHuffmanTree(HuffmanTree &HT, int n) {if (n <= 1) return;int m = 2 * n - 1; // 数组共2n-1个元素HT = new HTNode[m + 1]; // 动态分配内存,0号单元未用,HT[m]表示根结点// 初始化2n-1个元素的lch、rch、parent为0for (int i = 1; i <= m; ++i) {HT[i].lch = HT[i].rch = HT[i].parent = 0;HT[i].weight = 0.0; // 初始化权重为 0.0}// 输入前n个元素的weight值cout << "请输入" << n << "个字符的频率(浮点数):" << endl;for (int i = 1; i <= n; ++i) {cin >> HT[i].weight;}// 构建哈夫曼树for (int i = n + 1; i <= m; i++) {int s1, s2;Select(HT, i - 1, s1, s2);HT[s1].parent = i;HT[s2].parent = i;HT[i].lch = s1;HT[i].rch = s2;HT[i].weight = HT[s1].weight + HT[s2].weight;}
}// 从叶子到根逆向求每个字符的哈夫曼编码,存储在编码表HC中
void CreatHuffmanCode(HuffmanTree HT, HuffmanCode& HC, int n) {HC = new char*[n + 1]; // 分配n个字符编码的头指针数组char* cd = new char[n]; // 分配临时存放编码的动态数组空间cd[n - 1] = '\0'; // 编码结束符for (int i = 1; i <= n; ++i) {int start = n - 1;int c = i;int f = HT[i].parent;// 从叶子结点开始向上回溯,直到根结点while (f != 0) {--start;if (HT[f].lch == c)cd[start] = '0'; // 结点c是f的左孩子,则生成代码0elsecd[start] = '1'; // 结点c是f的右孩子,则生成代码1c = f;f = HT[f].parent;}// 计算编码长度并分配适当的空间int codeLength = n - start;HC[i] = new char[codeLength];strncpy(HC[i], &cd[start], codeLength);HC[i][codeLength - 1] = '\0'; // 确保字符串以空字符终止}delete[] cd; // 释放临时空间
}// 测试函数
int main() {int n;cout << "请输入叶子节点的数量:";cin >> n;HuffmanTree HT;CreatHuffmanTree(HT, n);HuffmanCode HC;CreatHuffmanCode(HT, HC, n);// 打印哈夫曼编码cout << "哈夫曼编码如下:" << endl;for (int i = 1; i <= n; ++i) {cout << "Character " << i << ": " << HC[i] << endl;}// 清理资源for (int i = 1; i <= n; ++i) {delete[] HC[i];}delete[] HC;delete[] HT;return 0;
}

改进后的代码:

#include <iostream>
#include <vector>
#include <string>
#include <limits>using namespace std;// 定义哈夫曼树节点结构
typedef struct HTNode {double weight; // 权重改为 double 类型int parent, lch, rch;
} HTNode;typedef HTNode* HuffmanTree;// 选择两个双亲域为0且权值最小的结点
void Select(const vector<HTNode>& HT, int i, int& s1, int& s2) {s1 = s2 = -1;double min1 = numeric_limits<double>::max(), min2 = numeric_limits<double>::max();for (int j = 1; j <= i; ++j) {if (HT[j].parent == 0 && HT[j].weight < min1) {min2 = min1;s2 = s1;min1 = HT[j].weight;s1 = j;} else if (HT[j].parent == 0 && HT[j].weight < min2) {min2 = HT[j].weight;s2 = j;}}
}// 构造哈夫曼树--哈夫曼算法
void CreatHuffmanTree(vector<HTNode>& HT, int n) {if (n <= 1) return;int m = 2 * n - 1; // 数组共2n-1个元素// 初始化2n-1个元素的lch、rch、parent为0,权重为0.0HT.resize(m + 1);for (int i = 1; i <= m; ++i) {HT[i] = {0.0, 0, 0, 0};}// 输入前n个元素的weight值cout << "请输入" << n << "个字符的频率(浮点数):" << endl;for (int i = 1; i <= n; ++i) {cin >> HT[i].weight;}// 构建哈夫曼树for (int i = n + 1; i <= m; i++) {int s1, s2;Select(HT, i - 1, s1, s2);HT[s1].parent = i;HT[s2].parent = i;HT[i].lch = s1;HT[i].rch = s2;HT[i].weight = HT[s1].weight + HT[s2].weight;}
}// 从叶子到根逆向求每个字符的哈夫曼编码,存储在编码表HC中
void CreatHuffmanCode(const vector<HTNode>& HT, vector<string>& HC, int n) {HC.resize(n + 1); // 分配n个字符编码的空间for (int i = 1; i <= n; ++i) {string code = "";int c = i;int f = HT[i].parent;// 从叶子结点开始向上回溯,直到根结点while (f != 0) {if (HT[f].lch == c)code = '0' + code; // 结点c是f的左孩子,则生成代码0elsecode = '1' + code; // 结点c是f的右孩子,则生成代码1c = f;f = HT[f].parent;}HC[i] = code;}
}// 测试函数
int main() {int n;cout << "请输入叶子节点的数量:";cin >> n;vector<HTNode> HT;CreatHuffmanTree(HT, n);vector<string> HC;CreatHuffmanCode(HT, HC, n);// 打印哈夫曼编码cout << "哈夫曼编码如下:" << endl;for (int i = 1; i <= n; ++i) {cout << "Character " << i << ": " << HC[i] << endl;}return 0;
}

改进后:

#include <iostream>
#include <cstring> // 用于 strcpy 和 strlen
#include <limits>  // 用于 std::numeric_limitsusing namespace std;// 定义哈夫曼树节点结构
typedef struct HTNode {double weight; // 权重改为 double 类型int parent, lch, rch;
} HTNode;typedef HTNode* HuffmanTree;// 定义哈夫曼编码结构
typedef char** HuffmanCode;// 选择两个双亲域为0且权值最小的结点
void Select(const HTNode* HT, int i, int& s1, int& s2) {s1 = s2 = -1;double min1 = numeric_limits<double>::max(), min2 = numeric_limits<double>::max();for (int j = 1; j <= i; ++j) {if (HT[j].parent == 0 && HT[j].weight < min1) {min2 = min1;s2 = s1;min1 = HT[j].weight;s1 = j;} else if (HT[j].parent == 0 && HT[j].weight < min2) {min2 = HT[j].weight;s2 = j;}}
}// 构造哈夫曼树--哈夫曼算法
void CreatHuffmanTree(HuffmanTree &HT, int n) {if (n <= 1) return;int m = 2 * n - 1; // 数组共2n-1个元素HT = new HTNode[m + 1]; // 动态分配内存,0号单元未用,HT[m]表示根结点// 初始化2n-1个元素的lch、rch、parent为0for (int i = 1; i <= m; ++i) {HT[i].lch = HT[i].rch = HT[i].parent = 0;HT[i].weight = 0.0; // 初始化权重为 0.0}// 输入前n个元素的weight值cout << "请输入" << n << "个字符的频率):" << endl;for (int i = 1; i <= n; ++i) {cin >> HT[i].weight;}// 构建哈夫曼树for (int i = n + 1; i <= m; i++) {int s1, s2;Select(HT, i - 1, s1, s2);HT[s1].parent = i;HT[s2].parent = i;HT[i].lch = s1;HT[i].rch = s2;HT[i].weight = HT[s1].weight + HT[s2].weight;}
}// 从叶子到根逆向求每个字符的哈夫曼编码,存储在编码表HC中
void CreatHuffmanCode(HuffmanTree HT, HuffmanCode& HC, int n) {HC = new char*[n + 1]; // 分配n个字符编码的头指针数组for (int i = 1; i <= n; ++i) {string code = ""; // 使用string来构建编码int c = i;int f = HT[i].parent;// 从叶子结点开始向上回溯,直到根结点while (f != 0) {if (HT[f].lch == c)code = '0' + code; // 结点c是f的左孩子,则生成代码0elsecode = '1' + code; // 结点c是f的右孩子,则生成代码1c = f;f = HT[f].parent;}// 将string转换为C风格字符串并分配适当的空间HC[i] = new char[code.length() + 1];strcpy(HC[i], code.c_str());}
}// 测试函数
int main() {int n;cout << "请输入叶子节点的数量:";cin >> n;if (n <= 0) {cerr << "叶子节点数量必须大于0." << endl;return 1;}HuffmanTree HT;CreatHuffmanTree(HT, n);HuffmanCode HC;CreatHuffmanCode(HT, HC, n);// 打印哈夫曼编码cout << "哈夫曼编码如下:" << endl;for (int i = 1; i <= n; ++i) {cout << "Character " << i << ": " << HC[i] << endl;}// 清理资源for (int i = 1; i <= n; ++i) {delete[] HC[i];}delete[] HC;delete[] HT;return 0;
}
运行结果:

在这里插入图片描述

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

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

相关文章

Nginx的性能分析与调优简介

Nginx的性能分析与调优简介 一、Nginx的用途二、Nginx负载均衡策略介绍与调优三、其他调优方式简介四、Nginx的性能监控 一、Nginx的用途 ‌Nginx是一种高性能的HTTP和反向代理服务器&#xff0c;最初作为HTTP服务器开发&#xff0c;主要用于服务静态内容如HTML文件、图像、视…

uniapp使用live-pusher实现模拟人脸识别效果

需求&#xff1a; 1、前端实现模拟用户人脸识别&#xff0c;识别成功后抓取视频流或认证的一张静态图给服务端。 2、服务端调用第三方活体认证接口&#xff0c;验证前端传递的人脸是否存在&#xff0c;把认证结果反馈给前端。 3、前端根据服务端返回的状态&#xff0c;显示在…

基于SpringBoot的“房产销售平台”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“房产销售平台”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统整体模块图 登录窗口界面 房源信息管理窗口界…

EMC——射频场感应的传导骚扰抗扰度(CS)

术语和定义 AE&#xff08;辅助设备&#xff09; 为受试设备正常运行提供所需信号的设备和检验受试设备性能的设备&#xff1b; 钳注入 是用电缆上的钳合式“电流”注入装置获得的钳注入&#xff1b; 电流钳 由被注入信号的电缆构成的二次绕组实现的电流变换器&#xff1b; 电磁…

探究音频丢字位置和丢字时间对pesq分数的影响

丢字的本质 丢字的本质是在一段音频中一小段数据变为0 丢字对主观感受的影响 1. 丢字位置 丢字的位置对感知效果有很大影响。如果丢字发生在音频信号的静音部分或低能量部分&#xff0c;感知可能不明显&#xff1b;而如果丢字发生在高能量部分或关键音素上&#xff0c;感知…

WordPress网站中如何修复504错误

504网关超时错误是非常常见的一种网站错误。这种错误发生在上游服务器未能在规定时间内完成请求的情况下&#xff0c;对访问者而言&#xff0c;出现504错误无疑会对访问体验大打折扣&#xff0c;从而对网站的转化率和收入造成负面影响。 504错误通常源于服务器端或网站本身的问…

自学记录HarmonyOS Next的HMS AI API 13:语音合成与语音识别

在完成图像处理项目后&#xff0c;我打算研究一下API 13的AI其中的——语音技术。HarmonyOS Next的最新API 13中&#xff0c;HMS AI Text-to-Speech和HMS AI Speech Recognizer提供了语音合成与语音识别的强大能力。 语音技术是现代智能设备的重要组成部分&#xff0c;从语音助…

从百度云网盘下载数据到矩池云网盘或者服务器内

本教程教大家如何快速将百度云网盘数据集或者模型代码文件下载到矩池云网盘或者服务器硬盘上。 本教程使用到了一个开源工具 BaiduPCS-Go&#xff0c;官方地址 &#xff1a; https://github.com/qjfoidnh/BaiduPCS-Go 这个工具可以实现“仿 Linux shell 文件处理命令的百度网…

2024基于大模型的智能运维(附实践资料合集)

基于大模型的智能运维是指利用人工智能技术&#xff0c;特别是大模型技术&#xff0c;来提升IT运维的效率和质量。以下是一些关键点和实践案例&#xff1a; AIOps的发展&#xff1a;AIOps&#xff08;人工智能在IT运维领域的应用&#xff09;通过大数据分析和机器学习技术&…

通过Js动态控制Bootstrap模态框-弹窗效果

目的&#xff1a;实现弹出窗、仅关闭弹窗之后才能操作&#xff08;按ESC可退出&#xff09;。自适应宽度与高度、当文本内容太多时、添加滚动条效果。 效果图 源码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8">…

文档解析丨高效准确的PDF解析工具,赋能企业非结构化数据治理

在数据为王的时代浪潮中&#xff0c;企业数据治理已成为组织优化运营、提高竞争力的关键。随着数字化进程的加速&#xff0c;企业所积累的数据量呈爆炸式增长&#xff0c;数据类型也愈发多样化&#xff0c;这些数据构成了现代企业数据资产的重要组成部分。 然而&#xff0c;传…

Maven项目中不修改 pom.xml 状况下直接运行OpenRewrite的配方

在Java 的Maven项目中&#xff0c;可以在pom.xml 中配置插件用来运行OpenRewrite的Recipe&#xff0c;但是有一些场景是希望不修改pom.xml 文件就可以运行Recipe&#xff0c;比如&#xff1a; 因为不需要经常运行 OpenRewrite&#xff0c;所以不想在pom.xml 加入不常使用的插件…

windows使用zip包安装MySQL

windows通过zip包安装MySQL windows通过zip包安装MySQL下载MySQL的zip安装包创建安装目录和数据目录解压zip安装包创建配置目录 etc 和 配置文件 my.ini安装MySQL进入解压后的bin目录执行命令初始化执行命令安装 验证安装查看服务已安装 启动MySQL查看服务运行情况修改密码创建…

书签管理工具的使用技巧

分类与筛选技巧 多层级分类&#xff1a;创建多层级的文件夹结构&#xff0c;如先按大的主题分类&#xff0c;再在每个主题下细分小类。例如&#xff0c;先创建 “工作”“学习”“生活” 等大文件夹&#xff0c;在 “工作” 文件夹下再细分 “项目文档”“办公软件”“行业资讯…

Spring API 接口加密/解密

API 接口加密/解密 为了安全性需要对接口的数据进行加密处理&#xff0c;不能明文暴露数据。为此应该对接口进行加密/解密处理&#xff0c;对于接口的行为&#xff0c;分别有&#xff1a; 入参&#xff0c;对传过来的加密参数解密。接口处理客户端提交的参数时候&#xff0c;…

CKA认证 | Day7 K8s存储

第七章 Kubernetes存储 1、数据卷与数据持久卷 为什么需要数据卷&#xff1f; 容器中的文件在磁盘上是临时存放的&#xff0c;这给容器中运行比较重要的应用程序带来一些问题。 问题1&#xff1a;当容器升级或者崩溃时&#xff0c;kubelet会重建容器&#xff0c;容器内文件会…

C/C++ 数据结构与算法【树和森林】 树和森林 详细解析【日常学习,考研必备】带图+详细代码

一、树的存储结构 1&#xff09;双亲表示法实现&#xff1a; 定义结构数组存放树的结点&#xff0c;每个结点含两个域: 数据域&#xff1a;存放结点本身信息。双亲域&#xff1a;指示本结点的双亲结点在数组中的位置。 特点&#xff1a;找双亲简单&#xff0c;找孩子难 C语…

flask后端开发(11):User模型创建+注册页面模板渲染

目录 一、数据库创建和配置信息1.新建数据库2.数据库配置信息3.User表4.ORM迁移 二、注册页面模板渲染1.导入静态文件2.蓝图注册路由 一、数据库创建和配置信息 1.新建数据库 终端中 CREATE DATABASE zhiliaooa DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;2…

通过 Ansys Electronics Desktop 中的高级仿真优化 IC 设计

半导体行业继续通过日益复杂的集成电路 (IC) 设计突破技术界限。随着工艺节点缩小和电路密度达到前所未有的水平&#xff0c;电磁效应对设备性能和可靠性变得越来越重要。现代 IC 设计面临着来自复杂的布局相关耦合机制、信号完整性问题和功率分布问题的挑战&#xff0c;这些问…

Android OpenGl(二) Shader

一、Shader 1、什么是Shader&#xff0c;为什么要使用Shder &#xff08;1&#xff09;shader运行在gpu上的小程序 &#xff08;2&#xff09;以前使用固定管线&#xff0c;但缺点是灵活度不够&#xff0c;无法满足复杂需求&#xff0c;为了解决固定管线的缺点&#xff0c;出…