数据结构——二叉树
好,上一篇我们已经讲过了堆,也已经了解了二叉树的基础知识后,我们今天来实现二叉树的相关代码。
由于初始二叉树,由于现在对二叉树结构掌握还不够深入,为了降低学习成本,此处我们来手动快速创建一棵简单的二叉树,快速进入二叉树操作学习,等二叉树结构了解的差不多时,我们反过头再来研究二叉树真正的创建方式。
我们已经了解了树的结构基本是下面框架了:
所以我们可以根据上面框架写出以下的结构代码:
定义
typedef int BTDataType;
typedef struct BinaryTreeNode
{数据BTDataType data;充当左子树struct BinaryTreeNode* left;充当右子树struct BinaryTreeNode* right;
}BTNode;
在编写简单的二叉树之前,我们首先得知道下面的类型定义:
以上面这幅图来举例:
简单来说,这几个用到的都要递归的方法。
注意说明:若根左右子树没有数字,即为空的话,用NULL来显示(更直观地看出其中的结论)。
1.前序遍历:根->左子树->右子树。
1)按照上图的例子,这里得到的顺序就是:
1,2,3,NULL,NULL,NULL,4,5,NULL,NULL,6,NULL,NULL.
为什么呢?现在我们来具体讲解:
把它分别看作整体,即上面划分出来的。
因为,它的顺序是根,左子树,右子树
首先,1就是根,接着到2是1的左子树,而2又是单独的根。
是不是有得按照它规定的顺序来,根2的左子树是3,3又是单独的根,再寻找3的左子树,即NULL
然后到找3的右子树==NULL,这是不是就意味着2的左子树找完了,之后,才到2的右子树==NULL
完了,到1的右子树==4,4是单独的根,到找4左子树==5,5是单独根,找5左子树==NULL,
到5右子树==NULL,完了就回到4的右子树6,6是单独根,找6左子树==NULL,6的右子树==NULL
最后返回最开始==结束。
根据上面颜色我们可以发现:每种颜色文字出现的顺序都是:根->左子树->右子树
同时,同种颜色不相邻--->这就是递归的原因。其实这也可以发现明白递归的一下规律了。
2.中序遍历:左子树->根->右子树:
有了上面的具体讲解,这里就不过多的讲解了,下面给出它的顺序,可以自己来验证一下:
NULL,3,NULL,2,NULL,1,NULL,5,NULL,4,NULL,6,NULL
3.后序遍历:左子树->右子树->根
同样:
NULL,NULL,3,NULL,2,NULL,NULL,5,NULL,NULL,6,4,1
层序遍历:一层一层算过去
1,2,3,4,5,6
好了,了解了之后,我们来用代码实现一下。
我们还是得malloc一下
BuyNode部分
BTNode* BuyNode(BTDataType x)
{BTNode* node = (BTNode*)malloc(sizeof(BTNode));if (node == NULL){perror("malloc fail");return NULL;}node->data = x;node->left = NULL;node->right = NULL;return node;
}
这相当于初始化嘛,先malloc,创建好开始的。相当于:
初步之后,我们开始搭建树的结构了。
CreatTree部分
BTNode* CreatTree()
{BTNode* node1 = BuyNode(1);BTNode* node2 = BuyNode(2);BTNode* node3 = BuyNode(3);BTNode* node4 = BuyNode(4);BTNode* node5 = BuyNode(5);BTNode* node6 = BuyNode(6);BTNode* node7 = BuyNode(7);node1->left = node2;node1->right = node4;node2->left = node3;node4->left = node5;node4->right = node6;node3->right = node7;return node1;
}
即
搭建好树的结构后,再想要是前序还是中序或是后序都变得非常简单了。
前序遍历:
void PreOrder(BTNode* root) {if (root == NULL) {printf("NULL ");return;}printf("%d ", root->data);PreOrder(root->left);PreOrder(root->right);
}
但是呢,如果有疑惑的话,不妨我们画出它的递归展开图:
上面就是它递归的全过程。
这里是不是就是前序的规则得出:
1,2,4,NULL,NULL,5,NULL,NULL,3,6,NULL,NULL,7,NULL,NULL.
上面我们写的对了。
中序遍历
void InOrder(BTNode* root) {if (root == NULL) {printf("NULL ");return;}InOrder(root->left);printf("%d ", root->data);InOrder(root->right);
}
它的递归展开图:
后序遍历
void PostOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}PostOrder(root->left);PostOrder(root->right);printf("%d ", root->data);
}
同样的递归图,就不一一画了,可以试试画,你会更清楚的。
求节点的个数
怎么求呢?
就以学校的关系来举例吧:
一个校长要求算出整个学校的人数总数,那么会有:
1)校长亲自去一个一个班去数人头个数。
2)吩咐各级领导统计,逐级上报。
这样上报人数明显更加方便,对吧?
同样方法一,就像是第一种情况,能不能干?可以干,但是效率太低了。
方法一:
int size = 0;
void TreeSize(BTNode* root)
{if (root == NULL)return;++size;TreeSize(root->left);TreeSize(root->right);
}
如果不想把size弄外面的话也可以下面:
void TreeSize(BTNode* root, int* psize)
{if (root == NULL)return;++(*psize);TreeSize(root->left, psize);TreeSize(root->right, psize);
}
所以我们第二种方法:
int TreeSize(BTNode* root)
{return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
}
加1是要把它本身也要加上。
它的递归展开图可以看出它的全过程。
求树的高度
比如说上图: 得出:
当前树的高度=左右子树高的那个+1
int TreeHeight(BTNode* root)
{if (root == NULL)return 0;return TreeHeight(root->left) > TreeHeight(root->right)? TreeHeight(root->left) + 1 : TreeHeight(root->right) + 1;
}
有人可能会写出这样的一种代码,它虽然行,但是效率低。
为什么呢?这相当于你每次当每级人员把自己级的数据报给上级领导后,他没有记录下来,等到他要真正记录上报给他上级时,忘了数据,又要重新问,而你之前上报时也没有记录下来,也忘记了,这样每个人都忘记了,所以会造成每次一个级的领导要的时候,又要重新来一遍。这样的数据累计起来就非常多了。
所以,真正的是要把每次的数据记录下来,避免效率低下。
int TreeHeight(BTNode* root)
{if (root == NULL)return 0;int leftHeight = TreeHeight(root->left);int rightHeight = TreeHeight(root->right);return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}
求在k层的个数
当前树第k层个数=左子树的第k-1层个数+右子树的第k-1层个数
int TreeKLevel(BTNode* root, int k)
{assert(k > 0);if (root == NULL)return 0;if (k == 1)return 1;return TreeKLevel(root->left, k - 1)+ TreeKLevel(root->right, k - 1);
}
递归展开图:
Find部分
BTNode* TreeFind(BTNode* root, BTDataType x)
{if (root == NULL)return NULL;if (root->data == x)return root;BTNode* lret = TreeFind(root->left, x);if (lret) //返回的不为空就进return lret;BTNode* rret = TreeFind(root->right, x);if (rret)return rret;return NULL;
}
它的递归展开图:
找下图中的6数字
层序遍历
这里需要用到队列的代码,因为,之前在堆那里讲到我们树实质是数组
而队列的规则:先进先出, 这符合我们的层序遍历。
这里,我们就只要把之前写过的Queue队列的代码形成文件,拿过来就可以了 。
但是呢:需要注意的是:
一定一定要更改*********不然就会错!!!!!(问就是我没改,找了好久没找到!!!!)
因为你不同类型了,现在是树,之前只是整形
原来的
//typedef int QDatatype;
改后的
typedef struct BinaryTreeNode* QDatatype;typedef struct QueueNode
{struct QueueNode* next;QDatatype data;
}QNode;
这里的原理就是:
出一层,带入下一层
void LevelOrder(BTNode* root)
{Queue q;//初始化QueueInit(&q);if (root)QueuePush(&q, root);while (!QueueEmpty(&q)){注意: 这里不是int*BTNode* front = QueueFront(&q);QueuePop(&q);printf("%d ", front->data);if(front->left)QueuePush(&q, front->left);if (front->right)QueuePush(&q, front->right);}QueueDestroy(&q);
}
解读:
1.首先,肯定是要把一开始的根push进去队列
2.正式进入循环(不为空)
3.要记录下对头的数据,防止之后Pop删除之后,找不到,而无法打印出这个数字。
4.接着Push左子树,右子树。
5.队列要进行开始初始化,结束要销毁,防止内存泄漏。
判断是否是完全二叉树
这里的方法也是要使用到队列的知识点
我们之前了解过,完全二叉树的概念:除了最后一层,都是满的二叉树,且最后一层从做开始,是连续的,中间不能为空。
按照这种情况,我们不妨有以下思路:
利用层序遍历,(出一层,带入下一层),直到出现空的前一个数,再进行循环,如果后面空中出现了非空,则证明不是。
如上图,5和6出完之后,剩下的全都是空,说明它是完全二叉树的。
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;}else{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;
}
最后给出代码:
test部分
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>#include "Queue.h"typedef int BTDataType;
typedef struct BinaryTreeNode
{BTDataType data;struct BinaryTreeNode* left;struct BinaryTreeNode* right;
}BTNode;BTNode* BuyNode(BTDataType x)
{BTNode* node = (BTNode*)malloc(sizeof(BTNode));if (node == NULL){perror("malloc fail");return NULL;}node->data = x;node->left = NULL;node->right = NULL;return node;
}BTNode* CreatTree()
{BTNode* node1 = BuyNode(1);BTNode* node2 = BuyNode(2);BTNode* node3 = BuyNode(3);BTNode* node4 = BuyNode(4);BTNode* node5 = BuyNode(5);BTNode* node6 = BuyNode(6);BTNode* node7 = BuyNode(7);node1->left = node2;node1->right = node4;node2->left = node3;node4->left = node5;node4->right = node6;node2->right = node7;return node1;
}void PreOrder(BTNode* root) {if (root == NULL) {printf("NULL ");return;}printf("%d ", root->data);PreOrder(root->left);PreOrder(root->right);
}void InOrder(BTNode* root) {if (root == NULL) {printf("NULL ");return;}InOrder(root->left);printf("%d ", root->data);InOrder(root->right);
}void PostOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}PostOrder(root->left);PostOrder(root->right);printf("%d ", root->data);
}int TreeSize(BTNode* root)
{return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
}int TreeHeight(BTNode* root)
{if (root == NULL)return 0;int leftHeight = TreeHeight(root->left);int rightHeight = TreeHeight(root->right);return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}int TreeKLevel(BTNode* root, int k)
{assert(k > 0);if (root == NULL)return 0;if (k == 1)return 1;return TreeKLevel(root->left, k - 1)+ TreeKLevel(root->right, k - 1);
}// 二叉树查找值为x的结点
BTNode* TreeFind(BTNode* root, BTDataType x)
{if (root == NULL)return NULL;if (root->data == x)return root;BTNode* lret = TreeFind(root->left, x);if (lret)return lret;BTNode* rret = TreeFind(root->right, x);if (rret)return rret;return NULL;
}void LevelOrder(BTNode* root)
{Queue q;QueueInit(&q);if (root)QueuePush(&q, root);while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);QueuePop(&q);printf("%d ", front->data);if(front->left)QueuePush(&q, front->left);if (front->right)QueuePush(&q, front->right);}printf("\n");QueueDestroy(&q);
}// 判断二叉树是否是完全二叉树
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;}else{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;
}// 二叉树销毁
void TreeDestory(BTNode* root)
{if (root == NULL)return;TreeDestory(root->left);TreeDestory(root->right);free(root);
}int main()
{BTNode* root = CreatTree();PreOrder(root);printf("\n");InOrder(root);printf("\n");PostOrder(root);printf("\n");/*size = 0;TreeSize(root);printf("TreeSize:%d\n", size);size = 0;TreeSize(root);printf("TreeSize:%d\n", size);*//*int size1 = 0;TreeSize(root, &size1);printf("TreeSize:%d\n", size1);int size2 = 0;TreeSize(root, &size2);printf("TreeSize:%d\n", size2);*/printf("TreeSize:%d\n", TreeSize(root));printf("TreeSize:%d\n", TreeSize(root));printf("TreeSize:%d\n", TreeSize(root));printf("TreeHeight:%d\n", TreeHeight(root));printf("TreeKLevel:%d\n", TreeKLevel(root, 3));printf("TreeKLevel:%d\n", TreeKLevel(root, 4));printf("TreeFind:%p\n", TreeFind(root, 5));printf("TreeFind:%p\n", TreeFind(root, 50));LevelOrder(root);printf("TreeComplete:%d\n", TreeComplete(root));TreeDestory(root);root = NULL;return 0;
}
Queue.c部分
#include"Queue.h"void QueueInit(Queue* pq)
{assert(pq);pq->head = pq->tail = NULL;pq->size = 0;
}void QueueDestroy(Queue* pq)
{assert(pq);QNode* cur = pq->head;while (cur){QNode* next = cur->next;free(cur);cur = next;}pq->head = pq->tail = NULL;pq->size = 0;
}void QueuePush(Queue* pq, QDatatype x)
{QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("malloc fail");return;}newnode->data = x;newnode->next = NULL;if (pq->head == NULL){assert(pq->tail == NULL);pq->head = pq->tail = newnode;}else{pq->tail->next = newnode;pq->tail = newnode;}pq->size++;
}void QueuePop(Queue* pq)
{assert(pq);assert(pq->head != NULL);/*QNode* next = pq->head->next;free(pq->head);pq->head = next;if (pq->head == NULL)pq->tail = NULL;*/if (pq->head->next == NULL){free(pq->head);pq->head = pq->tail = NULL;}else{QNode* next = pq->head->next;free(pq->head);pq->head = next;}pq->size--;
}int QueueSize(Queue* pq)
{assert(pq);return pq->size;
}bool QueueEmpty(Queue* pq)
{assert(pq);return pq->size == 0;
}QDatatype QueueFront(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));return pq->head->data;
}QDatatype QueueBack(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));return pq->tail->data;
}
Queue.h部分
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>typedef struct BinaryTreeNode* QDatatype;typedef struct QueueNode
{struct QueueNode* next;QDatatype data;
}QNode;typedef struct Queue
{QNode* head;QNode* tail;int size;
}Queue;void QueueInit(Queue* pq);
void QueueDestroy(Queue* pq);
void QueuePush(Queue* pq, QDatatype x);
void QueuePop(Queue* pq);
int QueueSize(Queue* pq);
bool QueueEmpty(Queue* pq);
QDatatype QueueFront(Queue* pq);
QDatatype QueueBack(Queue* pq);
每次鸡汤部分:
最后,新的一年,希望大家都学有所成,勇敢飞。
相关文章:
数据结构——二叉树
好,上一篇我们已经讲过了堆,也已经了解了二叉树的基础知识后,我们今天来实现二叉树的相关代码。 由于初始二叉树,由于现在对二叉树结构掌握还不够深入,为了降低学习成本,此处我们来手动快速创建一棵简单的二…...
六、 通用异步收发器UART
6.1 UART简介 UART(Universal Asynchronous Receiver/Transmitter,通用异步收发传输器)是一种用于异步串行通信的硬件设备。它通过两根信号线(TX 和 RX)实现全双工通信,广泛应用于微控制器、计算机和外设之…...
基于Kotlin中Flow扩展重试方法
最近项目中统一采用Kotlin的Flow来重构了网络请求相关代码。 目前的场景是,接口在请求的时候需要一个accessToken值,因为此值会过期或者不存在,需要刷新,因此最终方案是在使用Flow请求的时候先获取accessToken值然后再进行接口请求…...
在 Open WebUI+Ollama 上运行 DeepSeek-R1-70B 实现调用
在 Open WebUI Ollama 上运行 DeepSeek-R1-70B 实现调用 您可以使用 Open WebUI 结合 Ollama 来运行 DeepSeek-R1-70B 模型,并通过 Web 界面进行交互。以下是完整的部署步骤。 1. 安装 Ollama Ollama 是一个本地化的大模型管理工具,它可以在本地运行 …...
速度超越DeepSeek!Le Chat 1100tok/s闪电回答,ChatGPT 4o和DeepSeek R1被秒杀?
2023年,当全球科技界还在ChatGPT引发的AI狂潮中沉浮时,一场来自欧洲的"静默革命"正悄然改变游戏规则。法国人工智能公司Mistral AI推出的聊天机器人Le Chat以"比ChatGPT快10倍"的惊人宣言震动业界,其背后承载的不仅是技术…...
如何使用C++将处理后的信号保存为PNG和TIFF格式
在信号处理领域,我们常常需要将处理结果以图像的形式保存下来,方便后续分析和展示。C提供了多种库来处理图像数据,本文将介绍如何使用stb_image_write库保存为PNG格式图像以及使用OpenCV库保存为TIFF格式图像。 1. PNG格式保存 使用stb_ima…...
2 CXX-Qt #[cxx_qt::bridge] 宏指南
#[cxx_qt::bridge] 宏是用于在 Rust 中创建一个模块,该模块能够桥接 Rust 和 Qt(通过 C)之间的交互。它允许你将 Rust 类型暴露给 Qt 作为 QObject、Q_SIGNAL、Q_PROPERTY 等,同时也能够将 Qt 的特性和类型绑定到 Rust 中…...
PHP函数介绍—get_headers(): 获取URL的响应头信息
概述:在PHP开发中,我们经常需要获取网页或远程资源的响应头信息。PHP函数get_headers()能够方便地获取目标URL的响应头信息,并以数组形式返回。本文将介绍get_headers()函数的用法,以及提供一些相关的代码示例。 get_headers()函…...
C#树图显示目录下所有文件以及文件大小(使用Stack元组来替换递归)
接上篇 C#树图显示目录下所有文件以及文件大小_c# 查看文件夹里面有多少文件-CSDN博客 上一篇我们使用递归的方法来实现绑定目录和文件到树图中,关键程序代码如下: 这里我们使用Stack的方式非递归方法来实现绑定目录和文件到树图: /// <summary>/// 递归方法ÿ…...
计算机毕业设计Python+Spark知识图谱医生推荐系统 医生门诊预测系统 医生数据分析 医生可视化 医疗数据分析 医生爬虫 大数据毕业设计 机器学习
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
机器学习:朴素贝叶斯分类器
贝叶斯决策论是概率框架下实施决策的基本方法,对分类任务来说,在所有相关概率都已知的理想情形下,贝叶斯决策论考虑如何基于这些概率和误判损失来选择最优的类别标记。 贝叶斯定理是贝叶斯决策论的基础,描述了如何根据新的证据更新先验概率,贝叶斯定理&…...
解决 keep-alive 缓存组件中定时器干扰问题
当使用 keep-alive 缓存组件时,组件中的定时器可能会在组件被缓存后继续运行,从而干扰其他组件的逻辑。为了避免这种情况,可以通过以下方法解决: 1. 在组件的 deactivated 钩子中清理定时器 keep-alive 为缓存的组件提供了 acti…...
1-portal认证功能
很多时候公共网络需要提供安全认证功能,比如我们去星巴克或者商场、酒店,我们连接wifi上网的时候, 需要认证后才可以上网。 用户可以主动访问已知的Portal认证网站,输入用户名和密码进行认证,这种开始Portal认证的方式…...
Kafka 的消费offset原来是使用ZK管理,现在新版本是怎么管理的?
目录 基于 ZooKeeper 管理消费 offset 原理 缺点 新版本基于内部主题管理消费 offset 原理 优点 示例代码(Java) 在 Kafka 早期版本中,消费者的消费偏移量(offset)是存储在 ZooKeeper 中的,但由于 ZooKeeper 并不适合高频读写操作,从 Kafka 0.9 版本开始,消费偏…...
LabVIEW图像水印系统
图像水印技术在数字图像处理中起着重要作用,它能够保护图像的版权、确保图像的完整性,并提供额外的信息嵌入。本项目旨在利用LabVIEW开发一个图像水印系统,实现图像水印的嵌入和提取功能,为数字图像处理提供便捷的工具。 一、项目…...
Bash (Bourne-Again Shell)、Zsh (Z Shell)
文章目录 1. 历史背景2. 主要区别3. 功能对比自动补全插件和主题路径扩展提示符定制 4. 性能5. 使用场景6. 如何切换 Shell7. 总结 以下是 Bash 和 Zsh 之间的主要区别,列成表格方便对比: 特性BashZsh默认Shell大多数Linux发行版默认ShellmacOS默认She…...
iOS AES/CBC/CTR加解密以及AES-CMAC
感觉iOS自带的CryptoKit不好用,有个第三方库CryptoSwift还不错,好巧不巧,清理过Xcode缓存后死活下载不下来,当然也可以自己编译个Framework,但是偏偏不想用第三方库了,于是研究了一下,自带的Com…...
蓝桥杯算法日记|贪心、双指针
3412 545 2928 2128 贪心学习总结: 1、一般经常用到sort(a,an);【a[n]】排序,可以给整数排,也可以给字符串按照字典序排序 2、每次选最优 双指针 有序数组、字符串、二分查找、数字之和、反转字…...
浅谈Java Spring Boot 框架分析和理解
Spring Boot是一个简化Spring开发的框架,它遵循“约定优于配置”的原则,通过内嵌的Tomcat、Jetty或Undertow等容器,使得开发者能够快速构建独立运行的、生产级别的基于Spring框架的应用程序。Spring Boot包含了大量的自动配置功能,…...
【系统架构设计师】操作系统 ③ ( 存储管理 | 页式存储弊端 - 段式存储引入 | 段式存储 | 段表 | 段表结构 | 逻辑地址 的 合法段地址判断 )
文章目录 一、页式存储弊端 - 段式存储引入1、页式存储弊端 - 内存碎片2、页式存储弊端 - 逻辑结构不匹配3、段式存储引入 二、段式存储 简介1、段式存储2、段表3、段表 结构4、段内地址 / 段内偏移5、段式存储 优缺点6、段式存储 与 页式存储 对比 三、逻辑地址 的 合法段地址…...
网络编程-day4-TPC之文件传输
服务器 #include <stdio.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <pthread.h> #include <semaphore.h> #includ…...
定制化APP:开启企业数字化转型新未来
在当今快速发展的数字时代,企业的生存与发展不仅依赖于其传统的运营模式,更需要借助创新的技术手段来提升效率、优化服务并创造价值。而定制化的移动应用程序(简称“定制化APP”)正是实现这一目标的重要工具之一。通过量身定制的应用程序,企业能够更好地满足自身独特的业务…...
JS宏进阶:XMLHttpRequest对象
一、概述 XMLHttpRequest简称XHR,它是一个可以在JavaScript中使用的对象,用于在后台与服务器交换数据,实现页面的局部更新,而无需重新加载整个页面,也是Ajax(Asynchronous JavaScript and XML)…...
点大商城V2-2.6.6源码全开源uniapp +搭建教程
一.介绍 点大商城V2独立开源版本,版本更新至2.6.6,系统支持多端,前端为UNiapp,多端编译。 二.搭建环境: 系统环境:CentOS、 运行环境:宝塔 Linux 网站环境:Nginx 1.21 MySQL 5.…...
Docker的深入浅出
目录 Docker引擎 Docker镜像 (镜像由多个层组成,每层叠加之后,从外部看来就如一个独立的对象。镜像内部是一个精简的操作系统(OS),同时还包含应用运行所必须的文件和依赖包) Docker容器 应用容器化--Docker化 最佳…...
导航守卫router.beforeEach
router.beforeEach 是一个全局前置守卫,在每次路由跳转之前都会触发。 //index.jsrouter.beforeEach((to, from, next) > {// 打印即将要进入的目标路由信息console.log(即将要进入的目标路由信息:, to)// 打印当前正要离开的路由信息console.log(当前正要离开的…...
Perl语言的软件开发工具
Perl语言的软件开发工具 引言 在当今软件开发的世界中,随着互联网的快速发展和信息技术的不断进步,编程语言和开发工具的选择变得尤为重要。特别是在处理大量数据、实现快速原型以及网络编程等领域,Perl语言凭借其独特的优势而受到广泛青睐…...
在 Linux 系统下,解压 `.tar.gz`
在 Linux 系统下,解压 .tar.gz 文件通常使用 tar 命令。.tar.gz 文件是一种压缩归档文件,它首先使用 tar 命令将多个文件打包为一个 .tar 文件,然后再使用 gzip 压缩生成 .tar.gz 文件。 解压 .tar.gz 文件的命令 要解压 .tar.gz 文件,可以使用以下命令: tar -xzvf fil…...
Deepseek
1.Deepseek是什么? deepseek是一家人工智能科技公司所开发的能够进行人工智能对话的一个应用,它的主要目标是大规模的研发与应用。deepseek-R1是它的开源推理模型,主要负责处理复杂任务并且可以免费使用。 2.Deepseek可以做什么? Deepseek…...
oracle如何查询历史最大进程数?
oracle如何查询历史最大进程数? SQL> desc dba_hist_resource_limitName Null? Type---------------------------------------------------- -------- ------------------------------------SNAP_ID …...
强一致性算法:Raft
目录 什么是 Raft 算法? Leader的选举 投票分裂后的选举过程 Raft算法日志复制过程 修复不一样的日志 数据安全性的保证 什么是 Raft 算法? Raft 算法是一种是一种用于管理复制日志的强一致性算法,用于保证分布式系统中节点数据的一致…...
8.flask+websocket
http是短连接,无状态的。 websocket是长连接,有状态的。 flask中使用websocket from flask import Flask, request import asyncio import json import time import websockets from threading import Thread from urllib.parse import urlparse, pars…...
是德科技 | PCIe 7.0 互连— PCIe的尽头会是光吗?
伴随大语言模型和相关训练系统迅猛增长、对非结构化数据处理的需求急剧上升,市场对算力的需求也是呈指数级增加。PCIe作为计算机和服务器中使用广泛的高速数据传输技术发展迅猛,今年4月份PCI-SIG已经批准 Draft 0.5版基础规范,目前0.7版本基础…...
Aitken 逐次线性插值
Aitken 逐次线性插值 用 Lagrange 插值多项式 L n ( x ) L_n(x) Ln(x)计算函数近似值时,如需增加插值节点,那么原来算出的数据均不能利用,必须重新计算。为克服这个缺点,可用逐次线性插值方法求得高次插值。 令 I i 1 , i 2…...
Orange 开源项目介绍
Orange 开源项目 项目兼容单体架构与微服务架构两种模式,集成了包括部门管理、用户管理、菜单配置、角色分配、字典维护以及日志记录在内的多种系统管理功能。 项目体验 Orange 官网: http://hengzq.cn在线体验: http://tiny.hengzq.cn项目文档: http://hengzq.cn/…...
【高级架构师】多线程和高并发编程(三):锁(下)深入ReentrantReadWriteLock
文章目录 4、深入ReentrantReadWriteLock4.1 为什么要出现读写锁4.2 读写锁的实现原理4.3 写锁分析4.3.1 写锁加锁流程概述4.3.2 写锁加锁源码分析4.3.3 写锁释放锁流程概述&释放锁源码 4.4 读锁分析4.4.1 读锁加锁流程概述4.4.1.1 基础读锁流程4.4.1.2 读锁重入流程4.4.1.…...
如何在Node.js中使用中间件处理请求
Node.js作为一种基于事件驱动、非阻塞I/O模型的运行环境,广泛用于构建高性能的Web应用。在Node.js中,处理中间件是处理HTTP请求和响应的一个常见方式,特别是在使用Express框架时,中间件扮演着至关重要的角色。本文将介绍如何在Nod…...
Kotlin 2.1.0 入门教程(十三)异常、Nothing
创建自定义异常 可以通过创建继承内置 Exception 类来定义自定义异常。这允许你创建更符合应用程序需求的特定错误类型。 要创建一个自定义异常,可以定义一个继承 Exception 的类: class MyException : Exception("My message")在这个例子中…...
Unity 打造游戏资源加密解密系统详解
在游戏开发中,保护游戏资源不被轻易破解和盗用至关重要。本文将详细介绍如何在 Unity 中打造一个游戏资源加密解密系统,并提供技术详解和代码实现。 一、加密方案选择 1.1 对称加密 优点: 加密解密速度快,适合加密大量数据。 缺点: 密钥管…...
HarmonyOS Next 方舟字节码文件格式介绍
在开发中,可读的编程语言要编译成二进制的字节码格式才能被机器识别。在HarmonyOS Next开发中,arkts会编译成方舟字节码。方舟字节码长什么样呢?我们以一个demo编译出的abc文件: 二进制就是长这样,怎么去理解呢&…...
二层、三层小总结
一、网络隔离 1、物理隔离。搭建两套完全独立的网络,这也是最土豪最安全的做法。 2、二层隔离。使用Vlan隔离,使用不同Vlan或者Pvlan等。 3、三层隔离。路由隔离。 4、设备特性隔离。比如端口隔离swichport protected,或者ACL等。 5、安全…...
Window系统通过Docker本地安装ollama和deepseek
在 Windows 系统上安装 Ollama 和 DeepSeek 的步骤如下: 安装 Ollama 安装 WSL(Windows Subsystem for Linux): 如果还没有安装 过WSL的(安装过的你直接跳过就行了),可以按照以下步骤进行安装&…...
云原生后端|实践?
云原生(Cloud Native)是一种构建和运行应用程序的方法,它充分利用云计算的优势,包括弹性、可扩展性、高可用性和自动化运维。云原生后端开发通常涉及微服务架构、容器化、持续集成/持续部署(CI/CD)、服务网…...
1.1 Spring生态全景解读
1.1 Spring生态全景解读 1.1.1 Spring Framework发展历程与技术演进(深度解析版) 技术演进路线图与里程碑事件: 2003.10 - Spring 1.0 发布→ 核心特性:XML Bean配置、AOP基础支持→ 企业痛点:解决EJB复杂性问题&am…...
跨境商家系统搭建||反向海淘系统的搭建
反向海淘系统的搭建主要涉及以下几个方面的工作: 一、需求分析 在搭建反向海淘系统之前,首先需要进行需求分析。这包括明确系统的目标用户群体,了解他们的购物习惯、需求和期望。同时,还需要分析市场上的竞争对手,了…...
LeetCode数学相关算法题(1)【C语言版】
2520. 统计能整除数字的位数 给你一个整数 num ,返回 num 中能整除 num 的数位的数目。 如果满足 nums % val 0 ,则认为整数 val 可以整除 nums 。 示例 1: 输入:num 7 输出:1 解释:7 被自己整除&…...
云消息队列 ApsaraMQ Serverless 演进:高弹性低成本、更稳定更安全、智能化免运维
如今,消息队列已成为分布式架构中不可或缺的关键服务,为电商、物联网、游戏和教育等行业,提供了异步解耦、集成、高性能和高可靠的核心价值。 过去一年,我们发布了云消息队列 ApsaraMQ 全系列产品 Serverless 化,面向…...
github - 使用
注册账户以及创建仓库 要想使用github第一步当然是注册github账号了, github官网地址:https://github.com/。 之后就可以创建仓库了(免费用户只能建公共仓库),Create a New Repository,填好名称后Create,之后会出现一些仓库的配置信息,这也是一个git的简单教程。 Git…...
cmos晶体管
CMOS晶体管 一、PMOS和NMOS介绍 PN结: P-type和N-type组合在一起,变成一个PN结(二极管)。在P端给高电压,N端给低电压时,可以导通。否则不导通。 NMOS:有四个端口:gate、source、…...
pip3命令全解析:Python3包管理工具的详细使用指南
pip3命令全解析:Python3包管理工具的详细使用指南 一、基本使用二、升级和更新三、其他常用命令四、换源操作五、注意事项六、帮助信息pip3命令使用说明 pip3 是 Python 3 的包管理工具,用于安装、升级和卸载 Python 3 的包。以下是 pip3 的常用命令及详细说明: 一、基本使…...