【数据结构】第八节:链式二叉树

个人主页: NiKo

数据结构专栏: 数据结构与算法

 源码获取:Gitee——数据结构

一、二叉树的链式结构

typedef int BTDataType;
typedef struct BinaryTreeNode {BTDataType data;struct BinaryTreeNode* left;  // 左子树根节点struct BinaryTreeNode* right; // 右子树根节点
}BTNode;

        每一颗二叉树都是由左子树、根、右子树构成的,在实现二叉树的链式结构时我们也要将二叉树看作这三部分。

二、二叉树的遍历

学习二叉树结构,最简单的方式就是遍历。所谓 二叉树遍历(Traversal)是按照某种特定的规则,依次对二叉树中的结点进行相应的操作,并且每个结点只操作一次。访问结点所做的操作依赖于具体的应用问题。 遍历是二叉树上最重要的运算之一,也是二叉树上进行其它运算的基础。 遍历是通过递归实现的。
按照规则,二叉树的遍历有: 前序/中序/后序的递归结构遍历
  1. 前序遍历(Preorder Traversal 亦称先序遍历)——访问根结点的操作发生在遍历其左右子树之前。
  2. 中序遍历(Inorder Traversal)——访问根结点的操作发生在遍历其左右子树之中(间)。
  3. 后序遍历(Postorder Traversal)——访问根结点的操作发生在遍历其左右子树之后。

图1-1

已经创建的二叉树如图1-1。

1.前序遍历 

        前序遍历访问根结点的操作发生在遍历其左右子树之前,访问顺序为根、左子树、右子树。根据概念,在访问二叉树时,需要将二叉树看作根、左子树、右子树,左右子树又可以分为根、左子树、右子树,直到访问的节点为空(NULL)即证明访问到了二叉树的最底层。

        如图1-1所示,首先访问的根是1,这是第一层递归,然后递归访问此根的左子树,根节点为2,这是第二层递归;而以2为根的子树又可以分为以3为根的左子树、NULL,访问完根节点2后应继续递归访问左子树根节点3,这是第三层递归;此时根节点3的左子树为空,右子树为空无法再递归下去,以3为根节点的子树访问完毕,结束第三层递归返回到第二层递归并访问根节点2的右子树,右子树为空无法递归,以2为根节点的子树访问完毕结束第二层递归返回到第一层递归并访问根节点1的右子树,同理根据遍历左子树的方式遍历右子树。

void PrevOrder(BTNode* root) {// 不符合递归条件,结束此层递归if (root == NULL) {printf("N ");return;}printf("%d ", root->data); // 访问根节点PrevOrder(root->left);     // 访问根节点的左子树PrevOrder(root->right);    // 访问根节点的右子树
}

        根据代码前序遍历的结果示意图:

 

2.中序遍历

        中序遍历访问根结点的操作发生在遍历其左右子树之中(间)。访问顺序为左子树、根、右子树。同前序遍历的分析方式一样,访问一棵树应从他的左子树开始访问,然后再访问根和右子树。

        如图1-1,首先访问以1为根的左子树(根节点2),进入第一层递归;以根节点为2的左子树又可以分为左子树(根节点3)、右子树(NULL),进入第二层递归;此时正在访问的是根节点为3的子树,根据中序遍历的规则应按照左子树、根、右子树的顺序访问,进入第三层递归。3的左右子树都为空不符合递归条件结束第三层递归,返回到第二层递归并访问根节点2,然后访问根节点2的右子树,右子树为空结束第二层递归,返回到第一层递归并访问根节点1,随后访问根节点1的右子树,同理根据遍历左子树的方式遍历右子树。

void InOrder(BTNode* root) {if (root == NULL) {printf("N ");return;}InOrder(root->left);        // 访问根的左子树printf("%d ", root->data);  // 访问根InOrder(root->right);       // 访问根的右子树
}

      根据代码中序遍历的结果示意图:


3.后序遍历

        后序遍历访问根结点的操作发生在遍历其左右子树之后。访问顺序为左子树、右子树、根,后序遍历访问一棵树时,根节点是最后访问的。

        如图1-1,首先访问根节点1的左子树(根节点2)进入第一层递归,这颗子树还可以分为左右子树,则进入第二层递归访问根节点2的左右子树。随后进入第三层递归先访问根节点3的左子树,然后是右子树,最后是根节点3,结束第三层递归返回第二层递归并访问根节点2的右子树之后在访问根节点2,结束第二层递归返回第一层递归,访问根节点1的右子树,最后访问根节点1。

void PostOrder(BTNode* root) {if (root == NULL) {printf("N ");return;}PostOrder(root->left);      // 访问左子树PostOrder(root->right);     // 访问右子树printf("%d ", root->data);  // 访问根
}

        根据代码后序遍历的结果示意图:

 三、节点个数


  • 对于一棵树而言,他的节点分为两种情况:
  1. 根节点为空,返回0。
  2. 根节点不为空,这颗树的节点数=左子树节点个数+右子树节点个数+根节点(1)。
  • 根据这两种情况写出的代码如下:
int TreeSize(BTNode* root) {return root == NULL ? 0 :TreeSize(root->left) + TreeSize(root->right) + 1;
}

  • 分析:第一个访问的根节点1不为空根据表达式先计算左子树的节点个数,通过TreeSize(root->left)进入第一层递归访问到根节点2,在第二层递归中通过TreeSize(root->left)进入第二层递归访问根节点3,根节点3不为空通过TreeSize(root->left)访问左子树进入第三层递归,左子树为空返回0,右子树为空返回0,第三层递归的返回值为0+0+1=1结束第三层递归,返回到第二层递归的TreeSize(root->left)的值就是1,然后在第二层递归中通过TreeSize(root->right)访问根节点2的右子树,右子树为空返回0,第二层递归的返回值1+0+1=2,结束第二层递归并将值返回到第一层递归的TreeSize(root->left),这样左子树的节点个数计算完毕为2,紧接着再计算第一层递归的TreeSize(root->right),同理可得TreeSize(root->right)的值为3,最后得出这棵树的节点个数是6。

四、叶子节点个数

        叶子节点是指不含有任何子树的节点(度为0),即root->left和root->right均为NULL。判断叶子节点的个数需要我们找到度为0的节点。


  • 对于一颗子树,它的叶子节点有三种情况:
  1. 根节点为空,返回0
  2. 根节点不为空,左右子树均为空,它本身就是叶子节点,返回1
  3. 根节点不为空,左右子树至少有一个不为空,这棵树的叶子节点树=左子树叶子节点数+右子树叶子节点数
  • 根据这三种情况写出的代码如下:
int TreeLeafSize(BTNode* root) {if (root == NULL) {return 0;}else if (root->left == NULL && root->right == NULL) {return 1;}else {return TreeLeafSize(root->left) + TreeLeafSize(root->right);}
}

  • 分析:进入第一层递归访问根节点1,根节点1不为空且左右子树不为空,通过TreeLeafSize(root->left)进入第二层递归访问根节点2,根节点2不为空且左子树不为空,通过TreeLeafSize(root->left)进入第三层递归访问根节点3,根节点3不为空但是此时左右子树为空,说明节点3是叶子节点,结束第三层递归返回1到第二层递归,在第二层递归中通过TreeLeafSize(root->right)访问根节点2的右子树,为空返回0,则以2为根节点的子树叶子节点个数0+1=1,结束第二层递归返回1到第一层递归,同理可得右子树的叶子节点为1+1=2,则这棵树的叶子节点数1+2=3。

五、高度

        树的高度是指树中节点的最大层次,在二叉树中,左右两棵子树的高度较大者作为这棵树的高度。


  • 求树的高度有两种情况:
  1. 根节点为空,返回0
  2. 根节点不为空,这棵树的高度=max(左子树高度,右子树高度)+1
  • 根据这两种情况写出的代码如下:
int TreeHeight(BTNode* root) {if (root == NULL) {return 0;}else {return max(TreeHeight(root->left), TreeHeight(root->right)) + 1;}
}

  • 分析:进入第一层递归访问根节点1,不为空通过TreeHeight(root->left)进入第二层递归访问根节点2,不为空通过TreeHeight(root->left)访问根节点3进入第三层递归,此时TreeHeight(root->left)和TreeHeight(root->right)的返回值都为0,第三层递归返回0+0+1=1到第二层递归并结束第三层递归。第二层递归返回1+0+1=2到第一层递归,同理再访问右子树得TreeHeight(root->right)的返回值为2,max(TreeHeight(root->left),TreeHeight(root->right))+1的结果为3,故此树的高度就是3。

六、第k层的节点个数

        求二叉树的第k层节点可以向下转化为求这棵树的左右子树的第k-1层节点,当k=1时就到达了这棵树的第k层。


  • 在二叉树中每次向下递归一层的情况有三种:
  1. 根节点为空,返回0
  2. 根节点不为空且k不等于1,继续向下递归直到k等于1
  3. 根节点不为空且k等于1,说明到达目标层,返回1
  • 根据这三种情况写出的代码如下:
int TreeLevelKSize(BTNode* root, int k) {if (root == NULL) {return 0;}if (k == 1) {return 1;}else {return TreeLevelKSize(root->left, k - 1) + TreeLevelKSize(root->right, k - 1);}
}

  • 分析:假设k=3,进入第一层递归访问根节点1,不为空且k不等于1(k=3);通过TreeLevelKSize(root->left, k - 1)进入第二层递归访问根节点2,不为空且k不等于1(k=2);通过TreeLevelKSize(root->left, k - 1)进入第三层递归访问根节点3,不为空,此时k=1说明到达目标层,返回1结束第三层递归。在第二层递归中通过TreeLevelKSize(root->right, k - 1)访问右子树,为空返回0,结束第二层递归返回1到第一层递归,同理通过TreeLevelKSize(root->right, k - 1)可到达根节点1的右子树且第k层节点数是2,所以这棵树的第三层有1+2=3个节点。

七、查找值为x的节点

        遍历二叉树找到值为x的节点返回即可。


  • 遍历的结果有四种情况:
  1. 根节点为空,返回NULL
  2. 根节点不为空,节点的值等于x,返回这个节点(地址)
  3. 如果在左子树中找到了目标节点,不用再遍历右子树
  4. 左右子树都没有找到这个节点,返回NULL
  • 根据这四种情况写出的代码如下:
BTNode* TreeFind(BTNode* root, BTDataType x) {if (root == NULL) {return NULL;}if (root->data == x) {return root;}BTNode* ptr = TreeFind(root->left, x);if (ptr != NULL) {return ptr;}else {BTNode* ptr = TreeFind(root->right, x);if (ptr == NULL) {return NULL;}else {return ptr;}}
}

  • 分析:假设x=6,进入第一层递归访问根节点1,1不等于6且不为空通过TreeFind(root->left, x)进入第二层递归访问根节点2,2不等于6且不为空进入第三层递归访问根节点3,3不等于6,此时结束第三层递归返回值NULL,根节点2的左子树没有找到,向右子树遍历,右子树也没有找到结束第二层递归返回NULL,说明在左子树中没有找到目标节点,这时候查找右子树,在右子树中找到了就返回这个节点。

八、创建二叉树

        已知一个字符数组,根据这个字符数组创建二叉树;创建二叉树的顺序应该是根、左子树、右子树。


  • 假设给出这样一个数组:"abc##de#g##f###",其中"#"表示NULL,字母代表树中节点存储的值,还是用递归的思想,根据这个数组建立一个二叉树。
  • 首先需要遍历这个数组,遍历的结果有两种:
  1. 指针指向的元素为"#",代表这个节点为NULL(左子树或右子树建立完成)
  2. 指针指向非"#"元素,将值赋给这个节点后继续建立这个节点的左子树和右子树
  • 根据这两种情况写出的代码如下:
// abc##de#g##f###
BTNode* CreateTree(BTDataType* arr, int* pi) {if (arr[*pi] == '#') {(*pi)++;return NULL;}BTNode* node = (BTNode*)malloc(sizeof(BTNode));if (node == NULL) {perror("malloc fail!");exit(-1);}node->data = arr[(*pi)++];node->left = CreateTree(arr, pi);node->right = CreateTree(arr, pi);return node;
}

  • 分析:定义一个指针,代表数组的下标,每当创建一个节点或遇到NULL就后移。创建好一个节点后,给节点赋值,然后进入递归,当函数返回NULL时说明这颗子树创建完成,以此类推。

九、销毁二叉树

        销毁二叉树时,采用后序遍历销毁节点,原因是如果采用前序遍历或中序遍历会导致根节点销毁后无法销毁他的左子树或右子树。


  • 销毁二叉树步骤:
  1. 如果当前节点为NULL,直接结束
  2. 不为空,先销毁左子树,再销毁右子树,最后销毁根
  • 代码如下:
void TreeDestory(BTNode* root) {if (root == NULL) {return;}// 采用后序遍历销毁树TreeDestory(root->left);TreeDestory(root->right);free(root);
}

  • 分析:进入函数后先判断这个节点是不是空,如果是代表已经销毁,不是通过递归依次销毁左子树和右子树,最后销毁根。

十、层序遍历 

        层序遍历(广度优先遍历)指的是在一棵二叉树中,依次遍历访问每一层的节点,直到最后一层。层序遍历需要使用到队列结构,相关代码在gitte中。


  • 层序遍历基本步骤:
  1. 如果节点为空,不进队列;节点不为空,进队列
  2. 进入循环,取队列的头节点,头节点的左右节点(非空)入队列,头节点出队列,这时访问了一层节点
  3. 当队列为空时,结束循环
  • 代码如下:
void TreeLevelOrder(BTNode* root) {Queue q;QueueInit(&q);// 不为空进队列if (root) {QueuePush(&q, root);}// 如果队列是空的,代表已经访问完所有元素while (!QueueEmpty(&q)) {BTNode* front = QueueFront(&q);QueuePop(&q);printf("%c ", front->data);if (front->left) {QueuePush(&q, front->left);}if (front->right) {QueuePush(&q, front->right);}}QueueDestroy(&q);
}

  • 分析:初始化队列,如上图,节点1入队列,进入循环,取队头节点并打印在控制台,节点1的左右节点2,4入队列,节点1出队列(队列中剩2,4);开始第二次循环,取队头节点2,2的左节点3入队列,2出队列(队列中剩4,3),以此类推,开始第三次循环后节点4的左右节点进队列,完成层序遍历。

十一、判断完全二叉树

        完全二叉树:完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。 要注意的是满二叉树是一种特殊的完全二叉树。 完全二叉树就是这样一种特殊的非满二叉树:除了最后一层外其他每一层都是填满的,并且最后一层的节点都尽可能地靠左排列。如上图。


  • 具体实现步骤:判断完全二叉树不能利用递归实现,需要利用队列的相关知识(广度优先遍历)实现。
  1. 创建队列,无论树中的节点是否为空,都进入队列,根据层序遍历,将队头节点的左右子节点带入队列,在进入队列时如果遇到了第一个空节点就停止将节点带入队列,开始判断队列中的节点是否都为空。如果是,代表这棵树是完全二叉树;如果不是,代表这棵树是完全二叉树。
  • 代码:
bool TreeComplete(BTNode* root)
{Queue q;QueueInit(&q);if (root)QueuePush(&q, root);while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);QueuePop(&q);// 遇到第一个空,就可以开始判断,如果队列中还有非空,就不是完全二叉树if (front == NULL){break;}QueuePush(&q, front->left);QueuePush(&q, front->right);}while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);QueuePop(&q);// 如果有非空,就不是完全二叉树if (front){QueueDestroy(&q);return false;}}QueueDestroy(&q);return true;
}

  • 队列的源码可到博主的个人码云中获取(Project_Queue)

十二、补充二叉树的性质

  1. 若规定根结点的层数为1,则一棵非空二叉树的第i层上最多有2的i-1次方个结点.

  2. 若规定根结点的层数为1,则深度为h的二叉树的最大结点数是2的h次方减1.
  3. 对任何一棵二叉树, 如果度为0其叶结点个数为 n0, 度为2的分支结点个数为n2 ,则有n0 =n2 +1​​​​​​​
  4. 若规定根结点的层数为1,具有n个结点的满二叉树的深度h=log2(n+1). (ps:log2(n+1)是log以2为底,n+1为对数)
  5. 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有结点从0开始编号,则对于序号为i的结点有:​​​​​​​
  • ​​​​​​​若i>0,i位置结点的双亲序号:(i-1)/2;i=0,i为根结点编号,无双亲结点  
  • 若2i+1<n,左孩子序号:2i+1,2i+1>=n否则无左孩子
  • 若2i+2<n,右孩子序号:2i+2,2i+2>=n否则无右孩子

针对性质3:

/*
* 假设二叉树有N个结点
* 从总结点数角度考虑:N = n0 + n1 + n2 ①
* 
* 从边的角度考虑,N个结点的任意二叉树,总共有N-1条边
* 因为二叉树中每个结点都有双亲,根结点没有双亲,每个节点向上与其双亲之间存在一条边
* 因此N个结点的二叉树总共有N-1条边
* 
* 因为度为0的结点没有孩子,故度为0的结点不产生边; 度为1的结点只有一个孩子,故每个度为1的结
点* * 产生一条边; 度为2的结点有2个孩子,故每个度为2的结点产生两条边,所以总边数为:
n1+2*n2 
* 故从边的角度考虑:N-1 = n1 + 2*n2 ②
* 结合① 和 ②得:n0 + n1 + n2 = n1 + 2*n2 - 1
* 即:n0 = n2 + 1
*/

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

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

相关文章

day01 - Java基础语法

第一章 Java概述 1995年美国Sun推出Java&#xff0c;2009年Sun公司被甲骨文收购 Java之父&#xff1a;詹姆斯高斯林&#xff08;James Gosling&#xff09; Java编译器将源程序编译成与平台无关的字节码文件(class文件),然后由JVM对字节码文件解释执行。不同操作系统&#xf…

71、哪吒开发板试用结合oak深度相机进行评测

基本思想:收到intel的开发板-小挪吒,正好手中也有oak相机,反正都是openvino一套玩意,进行评测一下,竟然默认是个window系统,哈哈

鸿蒙媒体开发系列01——资源分类访问

如果你也对鸿蒙开发感兴趣&#xff0c;加入“Harmony自习室”吧&#xff01;扫描下方名片&#xff0c;关注公众号&#xff0c;公众号更新更快&#xff0c;同时也有更多学习资料和技术讨论群。 1、概述 应用开发过程中&#xff0c;经常需要用到颜色、字体、间距、图片等资源&am…

Vue3+Element Plus:使用el-dialog,对话框可拖动,且对话框弹出时仍然能够在背景页(对话框外部的页面部分)上进行滚动以及输入框输入信息

【需求】 使用Element Plus中的el-dialog默认是模态的&#xff08;即它会阻止用户与对话框外部的元素进行交互&#xff09;&#xff0c;对话框弹出时仍然能够在背景页&#xff08;对话框外部的页面部分&#xff09;上进行滚动以及输入框输入信息&#xff0c;且对话框可拖动 【…

双三次插值及MATLAB实现

一、双三次插值的概念 双三次插值&#xff08;Bicubic interpolation&#xff09;&#xff0c;又叫双立方插值。在数值分析这个数学分支中&#xff0c;双三次插值是二维空间中最常用的插值方法。在这种方法中&#xff0c;函数f在点 (x0 ,y0) 的值不仅考虑其直接邻接点对其的影响…

mybatis开启日志

步骤很详细&#xff0c;直接上教程 配置文件的文件格式可能有所不同&#xff0c;这里列举两种 配置方法 一. application.properties&#xff08;默认 # 配置mybatis的日志信息 mybatis.configuration.log-implorg.apache.ibatis.logging.stdout.StdOutImpl二. application.y…

基于python+django+vue的在线学习资源推送系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于协同过滤pythondjangovue…

工程师 - ACPI介绍_2

Advanced Configuration and Power Interface (ACPI) Introduction and Overview Version 1.4 : 26 April 2016 Copyright © 2016 Intel Corporation. All rights reserved. *Other names and brands may be claimed as the property of others. 本章提供了高级配置和电源…

【ACM出版,录用检索快】2024年第四届工商管理与数据科学国际学术会议 (BADS 2024,10月25-27)

2024年第四届工商管理与数据科学国际学术会议(BADS 2024)将于2024年10月25-27日在中国重庆召开&#xff0c;大会由喀什大学支持。 在当今全球化与数字化迅速发展的时代&#xff0c;工商管理与数据科学作为推动经济增长和技术进步的重要力量&#xff0c;正以前所未有的速度交叉融…

ROS学习笔记1.Mapping

为了执行自主导航&#xff0c;机器人必须拥有环境地图。机器人将使用此地图进行许多操作&#xff0c;例如规划轨迹、避开障碍物等。 您可以为机器人提供预先构建的环境地图&#xff08;在极少数情况下&#xff0c;您已经拥有具有正确格式的地图&#xff09;&#xff0c;也可以…

Go语言开发im-websocket服务和vue3+ts开发类似微信pc即时通讯

前言 IM即时通讯聊天, 为软件开发者打造&#xff0c;不依赖第三方sdk&#xff0c;完全用Go语言开发即时通讯服务&#xff0c;支持H5、Electron、Wails 、Uniapp和各种小程序的IM即时通讯, 快速实现私聊、群聊、在线客服&#xff01;让你快速搭建一个微信聊天系统&#xff0c;打…

浅谈住房城乡建设部科技创新平台布局重点方向

最近住房建设部组织开展住房城乡建设部科技创新平台&#xff08;以下简称部科技创新平台&#xff09;申报工作。详细内容见住房城乡建设部科技创新平台开始申报了 (qq.com)。在这里有4大方向共15个课题。内容见下图&#xff1a; 虽然我是做技术的&#xff0c;但是如何体现创新还…

mycat双主高可用架构部署-水评分表-枚举分片配置

MySQL5.7服务器IP是192.168.31.209及192.168.31.210 vi /usr/local/mycat/conf/schema.xml <?xml version"1.0"?> <!DOCTYPE mycat:schema SYSTEM "schema.dtd"> <mycat:schema xmlns:mycat"http://io.mycat/"><schema n…

AI赋能:无人直播新赛道,防封号、不限流,打造24小时流量引擎!

AI赋能&#xff1a;无人直播新赛道&#xff0c;防封号、不限流&#xff0c;打造24小时流量引擎&#xff01; 在数字化浪潮的推动下&#xff0c;直播行业正经历着前所未有的变革。传统直播模式受限于主播的实时参与、时间和地域的局限&#xff0c;难以满足日益增长的多元化需求。…

java技术栈介绍

Java技术栈是一个庞大而丰富的生态系统&#xff0c;它包含了从基础语言特性到高级框架、库和工具的整个集合。这个技术栈为开发者提供了构建各种类型应用&#xff08;包括企业级应用、Web应用、移动应用、大数据应用等&#xff09;所需的全部组件。以下是对Java技术栈的一个更详…

Windows 上下载、编译 OpenCV 并配置系统环境变量的详细步骤

创作不易&#xff0c;您的打赏、关注、点赞、收藏和转发是我坚持下去的动力&#xff01; 在 Windows 上下载并编译 OpenCV&#xff0c;然后配置系统环境变量的步骤如下&#xff1a; 1. 下载 OpenCV 打开 OpenCV 官方下载页面。找到最新的 Windows 版本&#xff0c;点击下载&…

[产品管理-23]:NPDP新产品开发 - 21 - 产品创新中的市场调研 - 市场调研对创新产品开发的意义

目录 前言&#xff1a; 一、市场调研概述 1.1 客户与市场的区别 1、定义与范围 2、关注焦点 3、作用与影响 4、总结 1.2 销售与市场的区别 1、对象与范围 2、工作方式 3、工作内容 4、目标 5、考核标准 6、在企业运营中的角色 1.3 什么是市场调研 1、市场调研的…

[Python]用Nuitka将 Python 脚本打造为独立高效的可执行文件

nuitka --onefile --ltoyes --standalone --show-modules --show-memory --nofollow-import-tomatplotlib --nofollow-import-toscipy --nofollow-import-topygame --nofollow-import-topyarrow --nofollow-import-tosqlalchemy --nofollow-import-topandas PDF信息提取-含界面…

GUI编程13:JDialog弹窗

视频链接&#xff1a;15、JDialog弹窗_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1DJ411B75F?p15&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5 package com.yundait.lesson04;import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; im…

双亲委派机制知识点

类加载器 双亲委派模型 为什么采用双亲委派模型 打破双亲委派机制的场景 Tomcat 打破双亲委派机制:目的是可以加载不同版本的jar包 实现类隔离&#xff1a;在Tomcat中&#xff0c;每个Web应用使用独立的类加载器加载类文件&#xff0c;这样做的好处在于&#xff0c;当在同一T…