数据结构编程实践20讲(Python版)—03栈
本文目录
- 03 栈 Stack
- S1 说明
- S2 示例
- 基于列表的实现
- 基于链表的实现
- S3 问题:复杂嵌套结构的括号匹配问题
- 求解思路
- Python3程序
- S4 问题:基于栈的阶乘计算VS递归实现
- 求解思路
- Python3程序
- S5 问题:逆波兰表示法(后缀表达式)求值
- 求解思路
- Python3程序
往期链接
| 01 数组 | 02 链表 |
|---|
03 栈 Stack
S1 说明
栈是一种线性数据结构,具有后进先出(LIFO, Last In First Out)的特点。栈的主要操作包括插入(压栈)和删除(弹栈),这些操作只能在栈的顶端进行。
基本操作
- 压栈(Push):将一个元素添加到栈顶。
- 弹栈(Pop):从栈顶移除并返回一个元素。
- 查看栈顶元素(Peek/Top):返回栈顶元素,但不删除它。
- 检查栈是否为空(IsEmpty):判断栈中是否还有元素。
- 获取栈的大小(Size):返回栈中元素的数量。
性质
- 后进先出(LIFO):最后压入栈的元素最先弹出。
- 只能在栈顶进行操作,无法直接访问栈中间或底部的元素。
S2 示例
基于列表的实现
class Stack:def __init__(self):self.items = [] # 使用列表存储栈元素def push(self, item):"""压栈操作"""self.items.append(item)def pop(self):"""弹栈操作"""if not self.is_empty():return self.items.pop()raise IndexError("弹栈失败,栈为空")def peek(self):"""查看栈顶元素"""if not self.is_empty():return self.items[-1]raise IndexError("查看栈顶元素失败,栈为空")def is_empty(self):"""检查栈是否为空"""return len(self.items) == 0def size(self):"""获取栈的大小"""return len(self.items)# 使用示例
if __name__ == "__main__":stack = Stack()stack.push(1)stack.push(2)stack.push(3)print("栈顶元素:", stack.peek()) # 输出 3print("弹出元素:", stack.pop()) # 输出 3print("当前栈大小:", stack.size()) # 输出 2
输出
栈顶元素: 3
弹出元素: 3
当前栈大小: 2
基于链表的实现
class Node:"""链表节点类"""def __init__(self, value):self.value = value # 节点存储的值self.next = None # 指向下一个节点的指针class LinkedListStack:"""基于链表的栈类"""def __init__(self):self.top = None # 栈顶指针def push(self, value):"""压栈操作"""new_node = Node(value) # 创建新节点new_node.next = self.top # 新节点指向当前栈顶self.top = new_node # 更新栈顶为新节点def pop(self):"""弹栈操作"""if self.is_empty():raise IndexError("弹栈失败,栈为空")popped_value = self.top.value # 保存栈顶值self.top = self.top.next # 更新栈顶为下一个节点return popped_value # 返回弹出的值def peek(self):"""查看栈顶元素"""if self.is_empty():raise IndexError("查看栈顶元素失败,栈为空")return self.top.value # 返回栈顶值def is_empty(self):"""检查栈是否为空"""return self.top is None # 栈顶指针为空则栈为空def size(self):"""获取栈的大小"""count = 0current = self.topwhile current:count += 1current = current.nextreturn count# 使用示例
if __name__ == "__main__":stack = LinkedListStack()stack.push(10)stack.push(20)stack.push(30)print("栈顶元素:", stack.peek()) # 输出 30print("弹出元素:", stack.pop()) # 输出 30print("当前栈大小:", stack.size()) # 输出 2print("栈是否为空:", stack.is_empty()) # 输出 False# 弹出剩余元素print("弹出元素:", stack.pop()) # 输出 20print("弹出元素:", stack.pop()) # 输出 10print("栈是否为空:", stack.is_empty()) # 输出 True
输出
栈顶元素: 30
弹出元素: 30
当前栈大小: 2
栈是否为空: False
弹出元素: 20
弹出元素: 10
栈是否为空: True
S3 问题:复杂嵌套结构的括号匹配问题
括号匹配问题是一个在算法和数据结构中常见的问题,主要目标是通过检查输入的括号序列是否平衡和闭合,以确定它们是否匹配。这个问题涉及到各种类型的括号,如圆括号、花括号和大括号。
括号匹配问题的核心在于检查输入的括号序列中的左括号和右括号是否能够正确配对,并且配对的顺序是否正确。例如,在算术表达式中,需要确保每一个左括号(如“(”或“[”)都有一个相应的右括号(如“)”或“]”)来闭合它,并且这些括号必须按照正确的顺序闭合。如果输入的括号序列无法满足这些条件,则称该序列不匹配。
要判断的括号字符串:
expressions = ["({[()]}{[()]})", # 匹配"{([()][()])}{[()]()}", # 匹配"({[()]}{[(])})", # 不匹配"({[()]}([]{}))" # 不匹配
]
求解思路
- 使用一个栈(用Python的列表实现)来跟踪开放的括号。
- 定义开放括号和闭合括号的集合,以及一个配对字典。
- 遍历输入字符串中的每个字符:
- 如果是开放括号,将其推入栈中。
- 如果是闭合括号,检查栈是否为空(如果为空,则不平衡),然后检查栈顶元素是否与当前闭合括号匹配。如果匹配,则弹出栈顶元素;如果不匹配,则表达式不平衡。
- 最后,如果栈为空,则表达式平衡;否则不平衡。
Python3程序
def is_balanced(expression):# 初始化一个空栈,用于存储开放括号stack = []# 定义开放括号的集合opening = "({["# 定义闭合括号的集合closing = ")}]"# 定义括号对应关系的字典pairs = {")": "(", "}": "{", "]": "["}# 遍历表达式中的每个字符for char in expression:# 如果是开放括号,将其压入栈中if char in opening:stack.append(char)# 如果是闭合括号elif char in closing:# 如果栈为空,说明闭合括号没有对应的开放括号,返回Falseif not stack:return False# 如果栈顶的开放括号与当前闭合括号匹配if stack[-1] == pairs[char]:# 弹出栈顶元素stack.pop()else:# 如果不匹配,返回Falsereturn False# 遍历结束后,如果栈为空,说明所有括号都匹配,返回True;否则返回Falsereturn len(stack) == 0# 测试样例
expressions = ["({[()]}{[()]})", # 匹配"{([()][()])}{[()]()}", # 匹配"({[()]}{[(])})", # 不匹配"({[()]}([]{}))" # 不匹配
]# 遍历所有测试样例
for expr in expressions:# 调用is_balanced函数检查是否平衡,并打印结果print(f"'{expr}'是{'匹配的' if is_balanced(expr) else '不匹配的'}")
输出
'({[()]}{[()]})'是匹配的
'{([()][()])}{[()]()}'是匹配的
'({[()]}{[(])})'是不匹配的
'({[()]}([]{}))'是匹配的
S4 问题:基于栈的阶乘计算VS递归实现
求解思路
使用栈实现的非递归版本。它的工作原理如下:
- 初始化一个栈和结果变量。
- 将初始值n压入栈中。
- 当栈不为空时,循环处理:
- 弹出栈顶元素。
- 如果是0或1,直接继续(因为0!和1!都等于1)。
- 否则,将当前值乘到结果中,并将下一个要处理的值(当前值-1)压入栈中。
- 循环结束后,返回最终结果。
Python3程序
# 递归版本的阶乘计算
def factorial_recursive(n):if n == 0 or n == 1:return 1else:return n * factorial_recursive(n - 1)# 使用栈的非递归版本的阶乘计算
def factorial_iterative(n):# 初始化一个栈来模拟递归调用stack = []result = 1# 将初始值压入栈中stack.append(n)# 当栈不为空时,继续处理while stack:# 从栈顶取出当前要处理的值current = stack.pop()if current == 0 or current == 1:# 0!和1!的值都是1,不需要further处理continueelse:# 将当前值乘到结果中result *= current# 将下一个要处理的值压入栈中stack.append(current - 1)return result# 测试两个版本的阶乘函数
test_numbers = [100]print("递归版本结果:")
for num in test_numbers:print(f"{num}! = {factorial_recursive(num)}")print("\n非递归版本结果:")
for num in test_numbers:print(f"{num}! = {factorial_iterative(num)}")
输出
递归版本结果:
100! = 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000非递归版本结果:
100! = 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
S5 问题:逆波兰表示法(后缀表达式)求值
逆波兰表示法(Reverse Polish Notation, RPN)是一种数学表达式的表示方式,其中运算符跟在操作数后面。这种表示法的优点是可以不使用括号来明确运算的优先级,因为操作数的顺序和运算符的顺序自然决定了计算的顺序。逆波兰表示法的特点
- 无括号:在逆波兰表示法中,运算符总是位于操作数之后,因此不需要括号来改变运算顺序。
- 后进先出(LIFO)原则:通常使用栈来计算逆波兰表达式。操作数被压入栈中,运算符则从栈中弹出操作数进行计算。
为什么要将看似简单的中缀表达式转换为复杂的逆波兰式?原因就在于对计算机而言 中序表达式(中缀表达式,我们常用的数学表达式的表示方式,带有括号,并且有运算优先级) 是非常复杂的结构。相对的,逆波兰式在计算机看来却是比较简单易懂的结构。因为计算机普遍采用的内存结构是栈式结构,它执行先进后出的顺序。
中缀表达式:3 + (51 * 2) - 80 / (4 - 2)
后缀表达式:转换后的形式为 3 51 2 * + 80 4 2 - / -
后缀表达式的计算
从左到右开始读取后缀表达式:
(1) 读到 3,入栈。此时栈:[3]
(2) 读到 51,入栈。此时栈:[3, 51]
(3) 读到 2,入栈。此时栈:[3, 51, 2]
(4) 读到 ∗ * ∗,取出栈顶两个数字进行乘法运算:51 * 2 = 102,结果入栈。此时栈:[3, 102]
(5) 读到 + + +,取出栈顶两个数字进行加法运算:3 + 102 = 105,结果入栈。此时栈:[105]
(6) 读到 80,入栈。此时栈:[105, 80]
(7) 读到 4,入栈。此时栈:[105, 80, 4]
(8) 读到 2,入栈。此时栈:[105, 80, 4, 2]
(9) 读到 − - −,取出栈顶两个数字进行减法运算:4 - 2 = 2,结果入栈。此时栈:[105, 80, 2]
(10) 读到 / / /,取出栈顶两个数字进行除法运算:80 / 2 = 40,结果入栈。此时栈:[105, 40]
(11) 读到 − - −,取出栈顶两个数字进行减法运算:105 - 40 = 65,结果入栈。此时栈:[65]
计算结束,栈中只剩下一个数字,这就是最终结果。因此,表达式 3 51 2 * + 80 4 2 - / - 的计算结果是65。
现在计算下面中缀表达式的后缀表达并求值:

求解思路
- 使用正则表达式将输入字符串分割成 tokens。
['(', '-', '5', '+', '3', ')', '*', '2', '-', '4', '/', '(', '2', '-', '√', '(', '16', '-', '2', ')', ')', '+', '3', '^', '2']
遍历 tokens,使用栈来处理运算符和括号。
- 定义运算优先级,并根据运算符优先级决定何时将运算符加入输出或压入栈。
def precedence(op):"""定义运算符优先级"""if op in {'+', '-'}:return 1if op in {'*', '/'}:return 2if op == '^':return 3if op == '√':return 4return 0
- 将运算符号和数学计算对应起来
operators = {'+': lambda x, y: x + y,'-': lambda x, y: x - y,'*': lambda x, y: x * y,'/': lambda x, y: x / y if y != 0 else float('inf'), # 处理除以零的情况'^': lambda x, y: math.pow(x, y),'√': lambda x: math.sqrt(x) if x >= 0 else float('nan') # 处理负数开方的情况}
- 计算得到的后缀表达式的值
Python3程序
import re
import mathdef infix_to_postfix(expression):def precedence(op):"""定义运算符优先级"""if op in {'+', '-'}:return 1if op in {'*', '/'}:return 2if op == '^':return 3if op == '√':return 4return 0def is_operator(token):"""检查token是否为运算符"""return token in {'+', '-', '*', '/', '^', '√'}output = [] # 用于存储后缀表达式stack = [] # 用于临时存储运算符# 使用正则表达式分割表达式为tokentokens = re.findall(r'√|\d+\.?\d*|\+|\-|\*|\/|\^|\(|\)', expression)i = 0while i < len(tokens):token = tokens[i]if token.replace('.', '').isdigit():# 处理数字if i > 0 and (tokens[i-1] == ')' or tokens[i-1].replace('.', '').isdigit()):# 在两个数字或右括号和数字之间插入乘号(处理隐式乘法)while stack and precedence(stack[-1]) >= precedence('*'):output.append(stack.pop())stack.append('*')output.append(token)elif token == '(':# 处理左括号if i > 0 and (tokens[i-1] == ')' or tokens[i-1].replace('.', '').isdigit()):# 在数字和左括号之间插入乘号(处理隐式乘法)while stack and precedence(stack[-1]) >= precedence('*'):output.append(stack.pop())stack.append('*')stack.append(token)elif token == ')':# 处理右括号while stack and stack[-1] != '(':output.append(stack.pop())if stack and stack[-1] == '(':stack.pop() # 弹出左括号else:raise ValueError("括号不匹配")elif is_operator(token):# 处理运算符if token == '√':# 处理根号if i + 1 < len(tokens) and tokens[i+1] == '(':# 如果根号后面跟着左括号,找到匹配的右括号bracket_count = 1j = i + 2while j < len(tokens) and bracket_count > 0:if tokens[j] == '(':bracket_count += 1elif tokens[j] == ')':bracket_count -= 1j += 1if bracket_count != 0:raise ValueError("括号不匹配")# 递归处理根号内的表达式sub_expr = ''.join(tokens[i+2:j-1])sub_postfix = infix_to_postfix(sub_expr)output.extend(sub_postfix)output.append(token)i = j - 1 # 更新索引到右括号的位置else:# 如果根号后面不是左括号,按普通运算符处理while stack and precedence(stack[-1]) >= precedence(token):output.append(stack.pop())stack.append(token)else:# 处理一元减号if token == '-' and (i == 0 or tokens[i-1] == '(' or is_operator(tokens[i-1])):output.append('0')while stack and precedence(stack[-1]) >= precedence(token):output.append(stack.pop())stack.append(token)i += 1# 将栈中剩余的运算符添加到输出while stack:if stack[-1] == '(':raise ValueError("括号不匹配")output.append(stack.pop())return outputdef evaluate_rpn(tokens):"""计算后缀表达式的值"""stack = []operators = {'+': lambda x, y: x + y,'-': lambda x, y: x - y,'*': lambda x, y: x * y,'/': lambda x, y: x / y if y != 0 else float('inf'), # 处理除以零的情况'^': lambda x, y: math.pow(x, y),'√': lambda x: math.sqrt(x) if x >= 0 else float('nan') # 处理负数开方的情况}for token in tokens:if token in operators:if token == '√':# 处理一元运算符(开方)if not stack:raise ValueError("无效的表达式:√ 缺少操作数")a = stack.pop()result = operators[token](a)else:# 处理二元运算符if len(stack) < 2:raise ValueError(f"无效的表达式:{token} 缺少操作数")b = stack.pop()a = stack.pop()result = operators[token](a, b)stack.append(result)else:# 将数字转换为浮点数并压入栈try:stack.append(float(token))except ValueError:raise ValueError(f"无效的token: {token}")# 确保最后栈中只剩一个数(结果)if len(stack) != 1:raise ValueError("无效的表达式")return stack[0]def calculate(expression):"""主计算函数,处理异常并返回结果"""try:postfix = infix_to_postfix(expression)result = evaluate_rpn(postfix)return resultexcept Exception as e:return f"错误: {str(e)}"if __name__ == '__main__':# 测试expressions = '(-5 + 3) * 2 - 4 / (2 - √(16-2)) + 3^2'postfix = infix_to_postfix(expressions)result = evaluate_rpn(postfix)print(f"中缀表达式: {expressions}")print(f"后缀表达式: {' '.join(postfix)}")print(f"计算结果: {result}")
结果
中缀表达式: (-5 + 3) * 2 - 4 / (2 - √(16-2)) + 3^2
后缀表达式: 0 5 - 3 + 2 * 4 2 16 2 - √ - / - 3 2 ^ +
计算结果: 7.296662954709577
相关文章:
数据结构编程实践20讲(Python版)—03栈
本文目录 03 栈 StackS1 说明S2 示例基于列表的实现基于链表的实现 S3 问题:复杂嵌套结构的括号匹配问题求解思路Python3程序 S4 问题:基于栈的阶乘计算VS递归实现求解思路Python3程序 S5 问题:逆波兰表示法(后缀表达式)求值求解思路Python3程…...
【注册/登录安全分析报告:孔夫子旧书网】
前言 由于网站注册入口容易被黑客攻击,存在如下安全问题: 暴力破解密码,造成用户信息泄露短信盗刷的安全问题,影响业务及导致用户投诉带来经济损失,尤其是后付费客户,风险巨大,造成亏损无底洞…...
PMP--二模--解题--141-150
文章目录 14.敏捷--创建敏捷环境--团队构成--混合项目环境,通常是自组织团队,即团队成员自己决定谁做什么,而不是项目经理决定。易混--常见场景--一个新人加入141、 [单选] 在一个混合项目的执行过程中,不得不更换一个开发人员。新…...
我的领域-关怀三次元成长的二次元虚拟陪伴 | OPENAIGC开发者大赛高校组AI创作力奖
在第二届拯救者杯OPENAIGC开发者大赛中,涌现出一批技术突出、创意卓越的作品。为了让这些优秀项目被更多人看到,我们特意开设了优秀作品报道专栏,旨在展示其独特之处和开发者的精彩故事。 无论您是技术专家还是爱好者,希望能带给…...
个人账号(学校+个人)申请专利过程中遇见的问题
一、请指定一位申请人作为代表人 因为是拿个人账号申请的专利,同时要求学校是第一申请人,所以可以再添加一个第二申请人,然后勾选第二申请人为代表人就可以提交申请了(注意:两个申请人只能减免75%,也就是要…...
在ubuntu系统中,如何让其按下物理关机键时,系统不处理,但qt程序能检测到关机键按下的事件,并处理信号
要让 Ubuntu 系统在按下物理关机键时,系统不直接处理该事件,但让你的 Qt 程序能够检测到并处理关机键的按下事件,可以参考以下步骤: 1. 禁用系统对关机键的默认处理 Ubuntu 系统默认会捕获电源键的按下事件并执行关机操作。首先你…...
先进制造aps专题二十六 基于强化学习的人工智能ai生产排程aps模型简介
基于强化学习的人工智能ai生产排程模型简介 人工智能ai能不能做生产排程? 答案是肯定的。 ai的算法分两类,一类是学习,一类是搜索。 而生产排程问题,它是一个搜索问题,本质上,它和下围棋是一样的 我们…...
各领域/行业硬件一览表
专班硬件装备制造agv小车、机械臂、PDA、服务器、大屏、扭矩传感器、温湿度检测仪、粉尘传感器、陀螺仪传感器、3D打印设备、在线质量检测仪器、新能源水表、电表、气表、汽表、服务器、大屏、温度传感器、压力传感器、光照度传感器、RTU医药化工温湿度传感器、压力传感器、流量…...
机器学习-SVM
线性感知机分类 支持向量机 线性感知机(Perceptron) 感知机是线性二值分类器。 注意:什么是线性?线性分割面就是,就是在分割面中,任意两个的连线也在分割面中,这个分割面,就是线…...
翻译器在线翻译:开启多语言交流新时代
随着国际交流、商务合作、文化交融以及互联网的飞速发展,人们对于跨越语言鸿沟的需求日益迫切。翻译工具成为了我们必备的一个工具,这篇文章我们一起来探讨一些好用的翻译器在线翻译工具吧。 1.在线福昕翻译 链接直达>>https://fanyi.pdf365.cn/…...
网络编程(10)——json序列化
十、day10 今天学习如何使用jsoncpp将json数据解析为c对象,将c对象序列化为json数据。jsoncp经常在网络通信中使用,也就是服务器和客户端的通信一般使用json(可视化好);而protobuf一般在服务器之间的通信中使用 json…...
基于FreeRTOS的STM32多功能手表设计
在智能穿戴设备迅速发展的今天,多功能手表因其便携性和实用性而受到广泛关注。本项目旨在设计一款基于FreeRTOS操作系统的STM32多功能手表,通过实时多任务处理,实现时间显示、多级菜单、万年历、模拟手电筒、温湿度显示、电子闹钟和设置等功能…...
18.Linux-配置DNF仓库
DNF仓库产生背景 在现实的场景中,我们经常要安装一些软件包,但由于现场不提供网络。 需要使用光盘或文件下载的方式去安装。 对于linux有两种离线安装方式:二进制文件安装和源码安装 其中二进制文件是比较简单的安装方式,不同的l…...
GeoPB:高效处理地理空间数据的Protobuf解决方案
在地理信息系统(GIS)和地理空间数据处理的领域,数据的交换和存储格式至关重要。随着技术的不断发展,如何高效、安全地处理和转换地理空间数据成为了一个核心问题。本文将详细介绍GeoPB——一个基于Protobuf(Protocol B…...
华为仓颉语言入门(6):if条件表达式
解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 仓颉语言中的 if 表达式用于根据条件的值来决定是否执行相关代码逻辑。if 表达式有三种形式:单分支的 if 表达式、双分支的 if 表达式和嵌套的 if 表达式。 单分支的 if 表达式 单分支的 …...
openlayers中一些问题的解决方案
一、使用地图时可能会出现的需求 1、定位:需要将地图的中心视野,定位到研究区域的中心点; 2、地图蒙版:只研究特定区域,将其他部分区域用蒙层遮罩,突显重点; 3、变色:设置整体的地图…...
java通过redis完成幂等性操作
4 幂等 产生 “重复数据或数据不一致”( 假定程序业务代码没问题 ),绝大部分就是发生了重复的请求,重复请求是指"同一个请求因为某些原因被多次提交"。导致这个情况会有几种场景: 微服务场景,在…...
48 旋转图像
解题思路: \qquad 这道题同样需要用模拟解决,原地算法要求空间复杂度尽量小,最好为 O ( 1 ) O(1) O(1)。模拟的关键是找到旋转的内在规律,即旋转前后的位置坐标的变化规律。 \qquad 正方形矩阵类似洋葱,可以由不同大小…...
TDengine 签约青山钢铁,实现冶金全流程质量管控智能化
在不锈钢生产领域,企业面临着信息孤岛和数据分散的挑战,尤其在冶炼、连铸和轧钢等关键工艺以及能源管理上,这种现象导致生产要素(人、机、料、法、环)的分析管理模型难以全面、深入地实施。为了应对这一挑战࿰…...
__pycache__文件夹
__pycache__ 文件夹是 Python 在运行时自动生成的目录,用于存储已编译的字节码文件。这些字节码文件以 .pyc 扩展名结尾,用于加速程序的启动时间,因为不需要每次运行时都重新编译源代码。 主要特点 自动生成:__pycache__ 文件夹…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...
Oracle查询表空间大小
1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...
智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
ios苹果系统,js 滑动屏幕、锚定无效
现象:window.addEventListener监听touch无效,划不动屏幕,但是代码逻辑都有执行到。 scrollIntoView也无效。 原因:这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作,从而会影响…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...
