当前位置: 首页 > news >正文

AI大模型从0到1记录学习 day17

第 2 章 数据结构与算法基础
2.1 数据结构基础
2.1.1 什么是数据结构
数据结构是为了高效访问数据而设计出的一种数据的组织和存储方式。更具体的说,一个数据结构包含一个数据元素的集合、数据元素之间的关系以及访问和操作数据的方法。
像前面我们接触到的list、set、dict、tuple其实已经是一种python封装的高级数据结构了,里面封装了对基本数据类型数据的存储以及组织方式。
2.1.2 数据结构的分类
1)逻辑结构
数据的逻辑结构反映了数据元素之间的逻辑关系。逻辑结构可分为线性和非线性两大类。
线性数据结构中的元素之间是一对一的顺序关系,在一对一的顺序关系中,除了第一个元素没有前驱元素,最后一个元素没有后继元素外,其余每个元素都有且仅有一个直接前驱元素和一个直接后继元素。这种关系使得数据元素可以按照一个线性的顺序依次排列,就像排成一列的队伍,每个成员前后都有明确的相邻成员(队首和队尾除外)如数组、链表、栈、队列等。
非线性数据结构中的元素之间具有多个对应关系,如树、图等。

2)物理结构
数据的物理结构反映了数据在计算机内存中的存储结构。一般而言,数据结构针对的是内存中的数据。内存由许多存储单元组成,每个存储单元可以存储一个固定大小的数据块,通常以字节(Byte)为单位。每个存储单元都有一个唯一的地址,操作系统正是根据这一地址去访问内存中的数据的。我们讨论的数据结构中的数据元素就保存在这一个个的内存单元中。数据在内存中的存储结构可分为连续存储(数组)与分散存储(链表)。
连续存储借助数据之间的相对位置来表示数据元素之间的逻辑关系。
分散存储借助指示数据位置的指针来表示数据元素之间的逻辑关系。

所有数据结构都是基于数组、链表或二者的组合实现的。例如,栈和队列既可以使用数组实现,也可以使用链表实现;而哈希表的实现可能同时包含数组和链表。
2.2 算法基础
2.2.1 什么是算法
算法是一个用于解决特定问题的有限指令序列(计算机可以执行的操作)。通俗的理解就是可以解决特定问题的方法。
算法的五大特性:
 输入:算法具有0个或多个输入。
 输出:算法至少有1个输出。
 有穷性:算法在有限的步骤之后会自动结束而不会无限循环,并且每一个步骤可以在可接受的时间内完成。
 确定性:算法中的每一步都有确定的含义,不会出现二义性。
 可行性:算法的每一步都是清楚且可行的,能让用户用纸笔计算而求出答案。
2.2.2 算法的分类
按照应用目的分类:搜索算法(深度优先搜索、广度优先搜索等)、排序算法(冒泡排序、插入排序、选择排序、快速排序、归并排序等)、最优化算法等。
按照实现策略分类:暴力法、增量法、分治算法、动态规划算法、贪心算法等。
2.2.3 时间复杂度
1)时间复杂度定义
时间复杂度用来描述运行一个算法所需时间资源的多少。为了屏蔽计算机硬件差异对评估结果的影响,我们不使用算法运行的绝对运行时间,而是使用运行算法时执行的基本指令数量来衡量其所需的时间资源。
常见的计算机基本指令有:
 赋值指令:用于为变量赋值。
 算术运算指令:包括加法、减法、乘法和除法等基本的数值运算。
 逻辑运算指令:包括与、或、非等逻辑操作。
 比较指令:用于比较两个值的大小或相等性。
我们假定计算机执行算法每一个基本操作的时间是固定的一个时间单位,对于不同的机器环境而言,确切的单位时间是不同的,但是对于算法进行多少个基本操作(即花费多少时间单位)在规模数量级上却是相同的。那么一个算法的所需时间 T 就可以表达为一个与输入规模 n 相关的函数:T(n)。
例如下面这个求和的算法,其所需时间 T(n) = 5n+5。其中 n 表示算法的输入规模,这里代表数组长度。
def sum(nums):
sum_num = 0 # 1次赋值操作
i = -1 # 1次赋值操作
while (i := i + 1) < len(nums): # n+1次加法运算 + n+1次赋值操作 + n+1次比较运算
sum_num += nums[i] # n次加法运算 + n次赋值操作
return sum_num
而下面这个寻找最大值的算法,其所需时间由于条件判断而变得不确定,若输入数组中的最大值位于首位,那么 T(n) = 4n+1;如果最大值位于末位,那么 T(n) = 5n。
def find_max(nums):
max_num = nums[0] # 1次赋值操作
i = 0 # 1次赋值操作
while (i := i + 1) < len(nums): # n次加法运算 + n次赋值操作 + n次比较运算
if nums[i] > max_num: # n-1次比较运算
max_num = nums[i] # 0~(n-1)次赋值操作
return max_num
我们注意到上述算法的运行时间还取决于具体数据,而不仅仅是问题规模。对于这种算法,我们把它们的执行情况分为:
 最优时间复杂度,即算法完成工作最少需要多少基本操作。
 最坏时间复杂度,即算法完成工作最多需要多少基本操作。
 平均时间复杂度,即算法完成工作平均需要多少基本操作。
对于最优时间复杂度,其价值不大,因为它没有提供什么有用信息,其反映的只是最乐观最理想的情况,没有参考价值;对于最坏时间复杂度,提供了一种保证,表明算法在此种程度的基本操作中一定能完成工作;对于平均时间复杂度,是对算法的一个全面评价,因此它完整全面的反映了这个算法的性质。但另一方面,这种衡量并没有保证,不是每个计算都能在这个基本操作内完成。此外,“平均”还依赖于所选的实例,以及这些实例出现的概率。因此,我们主要关注算法的最坏情况,亦即最坏时间复杂度。因此,上述寻找最大值的算法所需时间为 T(n) = 5n。
一般情况下,我们并不关心输入规模较小时算法的用时多少,并且其实上述的T(n)函数也并不是绝对的精确。所以我们通常只关注输入规模无限增大时,算法用时的增长趋势。也就是比较 T(n) 函数在 n 趋近于无穷大时的增长速度。
到目前为止,我们就已经能够对时间复杂度下一个准确的定义了:
 时间复杂度统计的是算法运行时执行的基本指令数,而非绝对运行时间。
 时间复杂度体现的是算法基本指令数随输入规模 n 增大时的变化趋势。
2)时间复杂度的大O表示法
由于时间复杂度只需要关注输入规模增大时,算法用时的增长趋势。而输入规模无限增大时,T(n) 函数中的低阶项和常数项,以及高阶项的常数系数,对于增长趋势的影响就会变得微乎其微,因此我们可以将其忽略掉,然后用最高阶项来表示 T(n) 函数的增长趋势。
例如我们现在有两个算法,分别是算法A:T(n) = 5n+5,算法B:T(n) = 2n2+2n-2,按照上述思路,算法A的时间复杂度可以表示为O(n),算法B的时间复杂度可以表示为O(n2)。
3)常见的时间复杂度
O(1) < O(logn) < O(n) < O(nlogn) < O(n2) < O(2n) < O(n!) < O(nn)
注意:表示时间复杂度时经常将log2n简写为logn。

下面给出几个常见的时间复杂度案例:
(1)O(1)
两数求和:
def add(a, b):
return a + b
如果算法的执行时间不随着问题规模 n 的增加而增长,即使算法中有上千条语句,其执行时间也不过是一个较大的常数。此类算法的时间复杂度是 O(1)。
(2)O(logn)
二分查找:
def binary_search(arr, target):
left, right = 0, len(arr) - 1

while left <= right:mid = left + (right - left) // 2if arr[mid] == target:return midelif arr[mid] < target:left = mid + 1else:right = mid - 1

return -1
对数阶反映了“每轮缩减到一半”的情况。
(3)O(n)
求数组中所有元素的和:
def sum(nums):
sum_num = 0
for num in nums:
sum_num += num
return sum_num
(4)O(nlogn)
归并排序:
def merge_sort(arr):
if len(arr) <= 1:
return arr

mid = len(arr) // 2left = merge_sort(arr[:mid])
right = merge_sort(arr[mid:])result = []
i = j = 0while i < len(left) and j < len(right):if left[i] < right[j]:result.append(left[i])i += 1else:result.append(right[j])j += 1result.extend(left[i:])
result.extend(right[j:])return result

(5)O(n2)
冒泡排序:
def bubble_sort(nums):
for i in range(len(nums) - 1):
for j in range(len(nums) - 1 - i):
if nums[j] > nums[j + 1]:
nums[j], nums[j + 1] = nums[j + 1], nums[j]
(6)O(2n)
枚举全部子集:
def subsets(nums):
“”“使用位运算来生成所有子集”“”
n = len(nums)
result = []
for i in range(1 << n):
subset = []
for j in range(n):
if i & (1 << j):
subset.append(nums[j])
result.append(subset)
return result
(7)O(n!)
全排列:
def permute(nums):
result = []

if len(nums) == 1:return [nums]for i in range(len(nums)):remaining = nums[:i] + nums[i + 1 :]for perm in permute(remaining):result.append([nums[i]] + perm)return result

2.2.4 空间复杂度
1)空间复杂度定义
空间复杂度用来描述一个算法运行所需内存空间的多少。同时间复杂度类似,空间复杂度并不代表算法运行时所使用的绝对内存空间,它描述的是算法使用的内存空间随输入规模变大时的变化趋势。
程序运行时占用内存空间的主要有以下内容:
 指令:程序编译后的二进制指令。
 数据:程序声明的变量、常量、对象等内容。
我们在计算空间复杂度时,一般只需关注数据所占用的内存空间即可。
2)常见的空间复杂度
(1)O(1)
常数阶常见于数量与输入数据大小无关的常量、变量、对象。
需要注意的是,在循环中初始化变量或调用函数而占用的内存,在进入下一循环后就会被释放,因此不会累积占用空间,空间复杂度仍为O(1)。
原地反转数组:
def reverse_array(arr):
left, right = -1, len(arr)
while (left := left + 1) < (right := right - 1):
arr[left], arr[right] = arr[right], arr[left]
(2)O(n)
判断数组中是否有重复元素:
def has_duplicates(arr):
seen = set()
for num in arr:
if num in seen:
return True
seen.add(num)
return False
(3)O(n2)
矩阵转置:
def transpose(matrix):
n = len(matrix)
result = [[0] * n for _ in range(n)]

for i in range(n):for j in range(n):result[j][i] = matrix[i][j]return result

第 3 章 常用数据结构
抽象数据类型(Abstract Data Type,简称 ADT)是计算机科学中一个重要的概念,它是对数据的一种抽象描述,关注数据的逻辑特性和操作,而不涉及具体的实现细节。
抽象数据类型通常由以下两部分组成:
 数据对象:描述了该数据类型所包含的数据元素以及它们之间的逻辑关系。例如,在一个栈的抽象数据类型中,数据对象是一系列按后进先出(LIFO)原则组织的元素。
 操作集合:定义了对数据对象可以执行的操作。对于栈来说,常见的操作包括入栈(push)、出栈(pop)、查看栈顶元素(peek)等。
抽象数据类型与数据结构的关系
 抽象数据类型:强调的是数据的逻辑特性和操作的功能,是一种抽象的概念,不涉及具体的实现细节。它是从用户的角度来描述数据和操作的。
 数据结构:是抽象数据类型的具体实现,它关注的是数据在计算机内存中的存储方式和操作的具体实现算法。例如,栈这种抽象数据类型可以用数组或链表等数据结构来实现。
3.1 数组
3.1.1 数组的概述
数组是一种线性数据结构,将相同类型的元素顺序地存储在连续的内存空间中,每个元素都有一个索引。

由于数组元素在内存中是连续存储的,所以只要知道数组的起始位置,以及数组元素的类型(单个元素的长度),就可以根据索引计算出任意元素的位置。
数组在创建时需要指定长度,并且数组一旦创建,长度就无法改变,如果需要扩容,只能创建一个更大的数组,再将原数据拷贝到新数组。并且由于数组的连续性,插入和删除数据可能需要移动其他元素。
在 Python 中,并没有像其他一些编程语言(如 C、Java)那样严格意义上的 “数组” 概念,但有多种数据结构可以用来模拟数组的功能,最常用的是列表(list),另外还有 array 模块的数组和 numpy 库的 ndarray。
通过Python 的list列表实现一个动态数组,它内部存储的实际上是对象的引用(指针),而不是对象本身。每个引用指向内存中存储实际对象的位置。
3.1.2 数组的功能定义
方法 说明
size() 返回数组中元素个数
is_empty() 判断数组是否为空
insert(index, item) 在指定位置插入元素
append(item) 在末尾插入元素
remove(index) 删除指定位置的元素
set(index, item) 修改指定位置的元素
get(index) 获取指定位置的元素
find(item) 查找数组中某个元素的位置
for_each(func) 遍历数组
3.1.3 数组的创建
实现一个动态数组。
class Array:
def init(self):
“”“初始化数组”“”
self.__capacity = 8
self.__size = 0
self.__items = [0] * 8

def __str__(self):"""打印数组"""arr_str = "["for i in range(self.__size):arr_str += str(self.__items[i])if i < self.__size - 1:arr_str += ", "arr_str += "]"return arr_str@property
def size(self):"""获取数组元素个数"""return self.__sizedef is_empty(self):"""判断数组是否为空"""return self.__size == 0

3.1.4 数组扩容
当数组容量占满后,我们可以创建一个新的数组,容量为之前数组的2倍,并将之前数组的元素拷贝到新数组中。
def __grow(self):
“”“数组扩容”“”
self.new___items = [0] * self.__capacity * 2
for i in range(self.__size):
self.new___items[i] = self.__items[i]
self.__items = self.new___items
self.__capacity *= 2
3.1.5 插入元素
在中间插入元素时,将指定位置及其之后的元素全部向后移动一个位置,并将指定位置改为新的元素。

def insert(self, index, item):"""插入元素"""if index < 0 or index > self.__size:raise IndexErrorif self.__size == self.__capacity:self.__grow()for i in range(self.__size, index, -1):self.__items[i] = self.__items[i - 1]self.__items[index] = itemself.__size += 1

在末尾插入元素时,使用insert()并将index设置为数组长度。
def append(self, item):
“”“末尾插入元素”“”
self.insert(self.__size, item)
3.1.6 删除元素
删除数组中指定位置的元素时,将该位置之后的所有元素向前移动一个位置。

def remove(self, index):"""删除元素"""if index < 0 or index >= self.__size:raise IndexErrorfor i in range(index, self.__size - 1):self.__items[i] = self.__items[i + 1]self.__size -= 1

3.1.7 修改元素
def set(self, index, item):
“”“修改元素”“”
if index < 0 or index >= self.__size:
raise IndexError
self.__items[index] = item
3.1.8 访问元素
def get(self, index):
“”“访问元素”“”
if index < 0 or index >= self.__size:
raise IndexError
return self.__items[index]
3.1.9 查找元素
def find(self, item):
“”“查找元素”“”
for i in range(self.__size):
if self.__items[i] == item:
return i
return -1
3.1.10 遍历数组
def for_each(self, func):
“”“遍历数组”“”
for i in range(self.__size):
func(self.__items[i])
3.1.11 完整代码
class Array:
def init(self):
“”“初始化数组”“”
self.__capacity = 8
self.__size = 0
self.__items = [0] * 8

def __str__(self):"""打印数组"""arr_str = "["for i in range(self.__size):arr_str += str(self.__items[i])if i < self.__size - 1:arr_str += ", "arr_str += "]"return arr_str@property
def size(self):"""获取数组元素个数"""return self.__sizedef is_empty(self):"""判断数组是否为空"""return self.__size == 0def __grow(self):"""数组扩容"""self.new___items = [0] * self.__capacity * 2for i in range(self.__size):self.new___items[i] = self.__items[i]self.__items = self.new___itemsself.__capacity *= 2def insert(self, index, item):"""插入元素"""if index < 0 or index > self.__size:raise IndexErrorif self.__size == self.__capacity:self.__grow()for i in range(self.__size, index, -1):self.__items[i] = self.__items[i - 1]self.__items[index] = itemself.__size += 1def append(self, item):"""末尾插入元素"""self.insert(self.__size, item)def remove(self, index):"""删除元素"""if index < 0 or index >= self.__size:raise IndexErrorfor i in range(index, self.__size - 1):self.__items[i] = self.__items[i + 1]self.__size -= 1def set(self, index, item):"""修改元素"""if index < 0 or index >= self.__size:raise IndexErrorself.__items[index] = itemdef get(self, index):"""访问元素"""if index < 0 or index >= self.__size:raise IndexErrorreturn self.__items[index]def find(self, item):"""查找元素"""for i in range(self.__size):if self.__items[i] == item:return ireturn -1def for_each(self, func):"""遍历数组"""for i in range(self.__size):func(self.__items[i])

3.2 链表
3.2.1 链表的概述
链表(Linked List)是一个线性结构,由一系列节点(Node)组成,每个节点包含一个数据元素和一个指向下一节点的指针(Pointer)。所有节点通过指针相连,形成一个链式结构。通常我们将链表中的第一个节点称为头结点,并将头结点的位置作为整个链表的位置标识。与数组不同,链表中每个节点分散的存储在内存中,每个节点都保存了当前节点的数据和下一节点的地址(指针)。

由于链表中节点通过指针相连,插入和删除节点只需要修改指针的指向即可,而不需要像数组那样移动数据。且链表不需要像数组那样预先指定大小,而是可以随时动态的增长或缩小。由于链表使用分散存储的方式,因而无需使用大段连续的内存空间。
由于链表中的节点不是连续存储的,无法像数组一样根据索引直接计算出每个节点的地址。必须从头节点开始遍历链表,直到找到目标节点,这导致了链表的随机访问效率较低。链表的每个节点都需要存储指向下一个节点的指针,这会占用额外的存储空间。相比于数组,链表需要更多的内存空间来存储相同数量的数据元素。
常见的链表包括三种:
 单向链表:单向链表的节点包含值和指向下一节点的引用。我们将首个节点称为头节点,将最后一个节点称为尾节点,尾节点指向空 None 。
 环形链表:将单向链表的尾节点指向头节点(首尾相接),则得到一个环形链表。在环形链表中,任意节点都可以视作头节点。
 双向链表:双向链表记录了两个方向的引用,同时包含指向后继节点(下一个节点)和前驱节点(上一个节点)的引用。
3.2.2 链表的功能定义
方法 说明
size() 返回链表中元素个数
is_empty() 判断链表是否为空
insert(index, item) 在指定位置插入元素
append(item) 在末尾插入元素
remove(index) 删除指定位置的元素
set(index, item) 修改指定位置的元素
get(index) 获取指定位置的元素
find(item) 查找链表中某个元素的位置
for_each(func) 遍历链表
3.2.3 链表的创建
实现一个单向链表。
class Node:
def init(self, data, next=None):
self.data = data
self.next = next

class LinkedList:
def init(self):
“”“初始化链表”“”
self.__head = None
self.__size = 0

def __str__(self):"""打印链表"""result = []current = self.__headwhile current:result.append(str(current.data))current = current.nextreturn " -> ".join(result)@property
def size(self):"""获取链表元素个数"""return self.__sizedef is_empty(self):"""判断链表是否为空"""return self.__size == 0

3.2.4 插入元素

def insert(self, index, item):"""插入元素"""if index < 0 or index > self.__size:raise IndexErrorif index == 0:# 插入到头部,需要新建一个节点,然后让新节点的next指向原来的head,然后让head指向新节点self.__head = Node(item, self.__head)else:# 插入到中间,先找到index-1位置的节点node = self.__headfor i in range(index - 1):node = node.next# 新节点的next指向index位置的节点,然后让index-1位置的节点的next指向新节点node.next = Node(item, node.next)self.__size += 1

在末尾插入元素时,使用insert()并将index设置为链表长度。
def append(self, item):
“”“末尾插入元素”“”
self.insert(self.__size, item)
3.2.5 删除元素

def remove(self, index):"""删除元素"""if index < 0 or index >= self.__size:raise IndexErrorif index == 0:self.__head = self.__head.nextelse:# 找到index-1位置的节点,然后让index-1位置的节点的next指向index位置的节点的nextnode = self.__headfor i in range(index - 1):node = node.nextnode.next = node.next.nextself.__size -= 1

3.2.6 修改元素
def set(self, index, item):
“”“修改元素”“”
if index < 0 or index >= self.__size:
raise IndexError
node = self.__head
for i in range(index):
node = node.next
node.data = item
3.2.7 访问元素
def get(self, index):
“”“访问元素”“”
if index < 0 or index >= self.__size:
raise IndexError
node = self.__head
for i in range(index):
node = node.next
return node.data
3.2.8 查找元素
def find(self, item):
“”“查找元素”“”
node = self.__head
while node:
if node.data == item:
return True
node = node.next
return False
3.2.9 遍历链表
def for_each(self, func):
“”“遍历链表”“”
node = self.__head
while node:
func(node)
node = node.next
3.2.10 完整代码
class Node:
def init(self, data, next=None):
self.data = data
self.next = next

class LinkedList:
def init(self):
“”“初始化链表”“”
self.__head = None
self.__size = 0

def __str__(self):"""打印链表"""result = []current = self.__headwhile current:result.append(str(current.data))current = current.nextreturn " -> ".join(result)@property
def size(self):"""获取链表元素个数"""return self.__sizedef is_empty(self):"""判断链表是否为空"""return self.__size == 0def insert(self, index, item):"""插入元素"""if index < 0 or index > self.__size:raise IndexErrorif index == 0:# 插入到头部,需要新建一个节点,然后让新节点的next指向原来的head,然后让head指向新节点self.__head = Node(item, self.__head)else:# 插入到中间,先找到index-1位置的节点node = self.__headfor i in range(index - 1):node = node.next# 新节点的next指向index位置的节点,然后让index-1位置的节点的next指向新节点node.next = Node(item, node.next)self.__size += 1def append(self, item):"""末尾插入元素"""self.insert(self.__size, item)def remove(self, index):"""删除元素"""if index < 0 or index >= self.__size:raise IndexErrorif index == 0:self.__head = self.__head.nextelse:# 找到index-1位置的节点,然后让index-1位置的节点的next指向index位置的节点的nextnode = self.__headfor i in range(index - 1):node = node.nextnode.next = node.next.nextself.__size -= 1def set(self, index, item):"""修改元素"""if index < 0 or index >= self.__size:raise IndexErrornode = self.__headfor i in range(index):node = node.nextnode.data = itemdef get(self, index):"""访问元素"""if index < 0 or index >= self.__size:raise IndexErrornode = self.__headfor i in range(index):node = node.nextreturn node.datadef find(self, item):"""查找元素"""node = self.__headwhile node:if node.data == item:return Truenode = node.nextreturn Falsedef for_each(self, func):"""遍历链表"""node = self.__headwhile node:func(node)node = node.next

相关文章:

AI大模型从0到1记录学习 day17

第 2 章 数据结构与算法基础 2.1 数据结构基础 2.1.1 什么是数据结构 数据结构是为了高效访问数据而设计出的一种数据的组织和存储方式。更具体的说&#xff0c;一个数据结构包含一个数据元素的集合、数据元素之间的关系以及访问和操作数据的方法。 像前面我们接触到的list、se…...

scanf函数功能与使用详解

【DeepSeek提问】 解释一下下面这段话&#xff1a; 函数scanf()是从标准输入流 stdin (标准输入设备&#xff0c; 一般指键盘)中读内容的通用子程序&#xff0c;可以按说明的格式读入多个字符&#xff0c;并保存在对应地址的变量中。 scanf函数返回成功读入的数据项数&#xf…...

使用Python从零开始构建端到端文本到图像 Transformer大模型

简介&#xff1a;通过特征向量从文本生成图像 回顾&#xff1a;多模态 Transformer 在使用Python从零实现一个端到端多模态 Transformer大模型中&#xff0c;我们调整了字符级 Transformer 以处理图像&#xff08;通过 ResNet 特征&#xff09;和文本提示&#xff0c;用于视觉…...

NDT和ICP构建点云地图 |【点云建图、Ubuntu、ROS】

### 本博客记录学习NDT&#xff0c;ICP构建点云地图的实验过程&#xff0c;参考的以下两篇博客&#xff1a; 无人驾驶汽车系统入门&#xff08;十三&#xff09;——正态分布变换&#xff08;NDT&#xff09;配准与无人车定位_settransformationepsilon-CSDN博客 PCL中点云配…...

第 1 篇✅ 用 AI 编程之前,你得先搞清楚你和 AI 是啥关系

程序员不是被替代的,是要学会主导 AI 的人 🧠 那些把 AI 当兄弟的程序员,后来都踩了坑 最近的一次线下开发者聚会,我们聊到“AI 编程”,现场笑声不断,也点醒了不少人。 有个朋友说: “我让 AI 写一个 Web 服务,它写得飞快,我一激动就上线了,结果上线后一堆坑,日志…...

Android Jetpack Compose 高级开发核心技术

Android Compose 高级技术总结 1. 性能优化 1.1 状态管理优化 状态提升原则&#xff1a;将状态提升到共享的最近共同父组件derivedStateOf&#xff1a;当需要基于多个状态计算派生状态时使用 val scrollState rememberScrollState() val showButton by remember {derivedS…...

Go小技巧易错点100例(二十五)

本期分享&#xff1a; 1. 使用atomic包实现无锁并发控制 2. Gin框架的中间件机制 3. 搞懂nil切片和空切片 使用atomic包实现无锁并发控制 sync/atomic包提供了原子操作&#xff0c;用于在多goroutine环境下安全地操作共享变量&#xff0c;避免使用锁带来的性能开销。 代码…...

如何用海伦公式快速判断点在直线的哪一侧

一、海伦公式的定义与推导 1. 海伦公式的定义 海伦公式&#xff08;Heron’s Formula&#xff09;是用于计算三角形面积的一种方法&#xff0c;适用于已知三角形三边长度的情况。公式如下&#xff1a; S s ( s − a ) ( s − b ) ( s − c ) S \sqrt{s(s - a)(s - b)(s - c…...

【异常处理】Clion IDE中cmake时头文件找不到 头文件飘红

如图所示是我的clion项目目录 我自定义的data_structure.h和func_declaration.h在unit_test.c中无法检索到 cmakelists.txt配置文件如下所示&#xff1a; cmake_minimum_required(VERSION 3.30) project(noc C) #设置头文件的目录 include_directories(${CMAKE_SOURCE_DIR}/…...

自动驾驶技术关键技术梳理

一、硬件 1、 传感器系统设计主要注意以下几个问题&#xff1a; 1.时间同步 一般包括多传感器之间时钟同源、帧同步触发的问题。首先要解决时钟同源问题&#xff0c;然后为了帧同步触发&#xff0c;可以让所有传感器整秒触发。常用GPS&#xff08;最多分2路&#xff09;给激光雷…...

MySQL索引介绍

索引的定义 扇区&#xff1a;磁盘存储的最小单位&#xff0c;扇区一般大小为512Byte。磁盘块&#xff1a;文件系统与磁盘交互的的最小单位&#xff08;计算机系统读写磁盘的最小单位&#xff09;&#xff0c;一个磁盘块由连续几个&#xff08;2^n&#xff09;扇区组成&#xf…...

2025认证杯一阶段各题需要使用的模型或算法(冲刺阶段)

A题&#xff08;小行星轨迹预测&#xff09; 问题一&#xff1a;三角测量法、最小二乘法、空间几何算法、最优化方法 问题二&#xff1a;Gauss/Laplace轨道确定方法、差分校正法、数值积分算法&#xff08;如Runge-Kutta法&#xff09;、卡尔曼滤波器 B题&#xff08;谣言在…...

每天学一个 Linux 命令(13):touch

Linux 文件管理命令:touch touch 是 Linux 中一个简单但高频使用的命令,主要用于创建空文件或修改文件的时间戳(访问时间、修改时间)。它是文件管理和脚本操作的实用工具。 1. 命令作用 创建空文件:快速生成一个或多个空白文件。更新时间戳:修改文件的访问时间(Access …...

Flutter常用组件实践

Flutter常用组件实践 1、MaterialApp 和 Center(组件居中)2、Scaffold3、Container(容器)4、BoxDecoration(装饰器)5、Column(纵向布局)及Icon(图标)6、Column/Row(横向/横向布局)+CloseButton/BackButton/IconButton(简单按钮)7、Expanded和Flexible8、Stack和Po…...

Python 实现最小插件框架

文章目录 Python 实现最小插件框架1. 基础实现项目结构plugin_base.py - 插件基类plugins/hello.py - 示例插件1plugins/goodbye.py - 示例插件2main.py - 主程序 2. 更高级的特性扩展2.1 插件配置支持2.2 插件依赖管理2.3 插件热加载 3. 使用 setuptools 的入口点发现插件3.1 …...

AUTOSAR_SWS_MemoryDriver图解

AUTOSAR 存储驱动程序&#xff08;Memory Driver&#xff09;详解 AUTOSAR存储驱动规范 - 技术解析与架构详解 目录 1. 概述2. Memory Driver架构设计 2.1 整体架构 3. Memory Driver核心组件4. 作业管理5. Memory Driver错误处理6. 时序流程7. 配置与设置8. 总结 1. 概述 A…...

AI结合VBA提升EXCEL办公效率尝试

文章目录 前言一、开始VBA编程二、主要代码三、添加到所有EXCEL四、运行效果五、AI扩展 前言 EXCEL右击菜单添加一个选项&#xff0c;点击执行自己逻辑的功能。 然后让DeepSeek帮我把我的想法生成VBA代码 一、开始VBA编程 我的excel主菜单没有’开发工具‘ 选项&#xff0c;…...

Python中NumPy的索引和切片

在数据科学和科学计算领域&#xff0c;NumPy是一个功能强大且广泛使用的Python库。它提供了高效的多维数组对象以及丰富的数组操作函数&#xff0c;其中索引和切片是NumPy的核心功能之一。通过灵活运用索引和切片操作&#xff0c;我们可以轻松访问和操作数组中的元素&#xff0…...

普通通话CSFB方式(2g/3g)

一、CSFB的触发条件 当模块&#xff08;或手机&#xff09;驻留在 4G LTE网络 时&#xff0c;若发生以下事件&#xff0c;会触发CSFB流程&#xff1a; 主叫场景&#xff1a;用户主动拨打电话。被叫场景&#xff1a;接收到来电&#xff08;MT Call&#xff09;。紧急呼叫&…...

daily routines 日常生活

总结 🛏 起床相关(Waking Up) 动作常用表达示例句子醒来wake upI usually wake up around 6:30.起床(离床)get up / get out of bedI got out of bed at 6:45.赖床stay in bed / lay thereI stayed in bed for another 10 minutes.关闭闹钟turn off the alarm / hit snoo…...

系分论文《论面向服务开发方法在设备租赁行业的应用》

系统分析师论文系列 【摘要】 2022年5月&#xff0c;我司承接某工程机械租赁企业"智能租赁运营管理平台"建设项目&#xff0c;我作为系统分析师主导系统架构设计。该项目需整合8大类2000余台设备资产&#xff0c;覆盖全国15个区域运营中心与300家代理商&#xff0c;实…...

深度解析python生成器和关键字yield

一、生成器概述 生成器&#xff08;Generator&#xff09;是Python中用于创建迭代器的工具&#xff0c;通过yield关键字实现。与普通函数不同&#xff0c;生成器函数返回的是迭代器对象&#xff0c;具有以下核心特性&#xff1a; 内存效率&#xff1a;只在需要时生成值&#x…...

蓝桥杯大模板

init.c void System_Init() {P0 0x00; //关闭蜂鸣器和继电器P2 P2 & 0x1f | 0xa0;P2 & 0x1f;P0 0x00; //关闭LEDP2 P2 & 0x1f | 0x80;P2 & 0x1f; } led.c #include <LED.H>idata unsigned char temp_1 0x00; idata unsigned char temp_old…...

Python装饰器的基本使用详解

各类资料学习下载合集 ​​https://pan.quark.cn/s/8c91ccb5a474​​ 装饰器是Python中的一个强大且灵活的特性&#xff0c;它允许我们在不修改函数代码的情况下为其添加额外功能。装饰器广泛应用于日志记录、性能测试、权限验证等场景。本文将详细介绍装饰器的基本使用&…...

5Why分析法

1. 基本概念 5Why分析法是一种通过连续追问"为什么"来探究问题根本原因的思考工具&#xff0c;由丰田生产方式创始人丰田喜一郎提出。其核心思想是&#xff1a;通过至少5次连续的"为什么"追问&#xff0c;穿透表面现象&#xff0c;直达问题本质。 2. 实施…...

AI Agent入门指南

图片来源网络 ‌一、开箱暴击&#xff1a;你以为的"智障音箱"&#xff0c;其实是赛博世界的007‌ ‌1.1 从人工智障到智能叛逃&#xff1a;Agent进化史堪比《甄嬛传》‌ ‌青铜时代&#xff08;2006-2015&#xff09;‌ “小娜同学&#xff0c;关灯” “抱歉&…...

华为机试—最大最小路

题目 对于给定的无向无根树&#xff0c;第 i 个节点上有一个权值 wi​ 。我们定义一条简单路径是好的&#xff0c;当且仅当&#xff1a;路径上的点的点权最小值小于等于 a &#xff0c;路径上的点的点权最大值大于等于 b 。 保证给定的 a<b&#xff0c;你需要计算有多少条简…...

java之多线程

目录 创建多线程的三种创建方式 常用的成员方法 守护线程 多线程的声明周期 ​编辑 同步代码块​编辑 同步方法 死锁 等待唤醒机制&#xff08;线程协调&#xff09; 线程池 创建多线程的三种创建方式 继承 Thread 类 通过继承 Thread 类并重写 run() 方法创建线程。 …...

php伪协议

PHP 伪协议&#xff08;PHP Stream Wrapper&#xff09; PHP 的伪协议&#xff08;Protocol Wrapper&#xff09;是一种机制&#xff0c;允许开发者通过统一的文件访问函数&#xff08;如 file_get_contents、fopen、include 等&#xff09;访问不同类型的数据源&#xff0c;包…...

六、测试分类

设计测试用例 万能公式&#xff1a;功能测试性能测试界面测试兼容性测试安全性测试易用性测试 弱网测试&#xff1a;fiddler上行速率和下行速率 安装卸载测试 在工作中&#xff1a; 1.基于需求文档来设计测试用例&#xff08;粗粒度&#xff09; 输入字段长度为6~15位 功…...

【AM2634】启动和调试

目录 【AM2634】启动和调试1. 上电流程1.1 BootFlow and Bootloader1.2 Rom Code1.2.1 功能介绍1.2.2 模式选择1.2.2.1 QSPI Boot1.2.2.2 UART Boot1.2.2.3 Dev Boot 1.3 SBL1.3.1 文件构成1.3.2 文件构建1.3.3 appimage解析和core启动流程 1.4 Appimage1.4.1 RPRC文件构成1.4.…...

鲁大师绿色版,纯净无广告

鲁大师是我们常用的硬件跑分软件,可以非常准确的识别电脑硬件,对电脑性能进行评估 但他的流氓行为:广告弹窗,捆绑下载其他软件,疯狂的吃硬件性能,无法卸载等因素&#xff0c;又使我们大家既享用又不敢用 我为大家整理了一款纯净的绿色版鲁大师 主要实现了以下功能: 01屏蔽了…...

Python数组(array)学习之旅:数据结构的奇妙冒险

Python数组学习之旅:数据结构的奇妙冒险 第一天:初识数组的惊喜 阳光透过窗帘缝隙洒进李明的房间,照亮了他桌上摊开的笔记本和笔记本电脑。作为一名刚刚转行的金融分析师,李明已经坚持学习Python编程一个月了。他的眼睛因为昨晚熬夜编程而微微发红,但脸上却挂着期待的微…...

spring cloud微服务API网关详解及各种解决方案详解

微服务API网关详解 1. 核心概念 定义&#xff1a;API网关作为微服务的统一入口&#xff0c;负责请求路由、认证、限流、监控等功能&#xff0c;简化客户端与后端服务的交互。核心功能&#xff1a; 路由与转发&#xff1a;将请求分发到对应服务。协议转换&#xff1a;HTTP/HTTP…...

工程师 - 场效应管分类

What Are the Different Types of FETs? Pulse Octopart Staff Jul 31, 2021 Field effect transistors (FETs) are today’s workhorses for digital logic, but they enjoy plenty of applications outside of digital integrated circuits, everything from motor driver…...

asm汇编源代码之按键处理相关函数

提供5个子程序: 1. 发送按键 sendkey 2. 检测是否有按键 testkey 3. 读取按键 getkey 4. 判断键盘缓冲区是否为空 bufempty 5. 判断键盘缓冲区是否已满 buffull 具体功能及参数描述如下 sendkey proc  far ; axcharcode testkey proc  far ; out: ;   zf1 buff empt…...

程序化广告行业(78/89):多因素交织下的行业剖析与展望

程序化广告行业&#xff08;78/89&#xff09;&#xff1a;多因素交织下的行业剖析与展望 在程序化广告这片充满活力又不断变化的领域&#xff0c;持续学习和知识共享是我们紧跟潮流、实现突破的关键。一直以来&#xff0c;我都渴望能与大家一同探索这个行业的奥秘&#xff0c…...

如何使用MaxScript+dotNet在UI中显示图像?

在MaxScript中,你可以使用dotNetControl来显示图像。以下是一个简单的示例脚本,它创建一个UI窗口并在其中显示logo.jpg图像: rollout logoRollout "Logo Display" width:300 height:300 (dotNetControl logoPicture "System.Windows.Forms.PictureBox"…...

BitMap和RoaringBitmap:极致高效的大数据结构

目录 1、引言 2、BitMap:基础 2.1、核心原理 2.2、BitMap的优势 2.3、BitMap的局限性 3、RoaringBitmap:进化 3.1、分段策略 3.2、三种容器类型 3.2.1. ArrayContainer(数组容器) 3.2.2. BitMapContainer(位图容器) 3.2.3. RunContainer(行程容器) 3.3、行…...

Java高性能并发利器-VarHandle

1. 什么是 VarHandle&#xff1f;​​ VarHandle 是 Java 9 引入的类&#xff0c;用于对变量&#xff08;对象字段、数组元素、静态变量等&#xff09;进行低级别、高性能的原子操作&#xff08;如 CAS、原子读写&#xff09;。它是 java.util.concurrent.atomic 和 sun.misc.…...

关于读完《毛泽东选集》的一些思考迭代

看完毛选前四卷&#xff0c;从革命初期一直讲到抗战胜利&#xff0c;共75.8W字&#xff0c;花费67个小时读完。从1925年发表的“中国社会各阶级的分析”&#xff0c;跨越100年&#xff0c;通过67个小时向主席学习到&#xff1a; 实事求是 从实践中来再到实践中去 用辩证与发展…...

机器学习 第一章

&#x1f9e0; 机器学习 第一章 一、什么是机器学习 (Machine Learning) 让计算机自己从数据中学习出规律&#xff0c;无需人手写规则 输入: 特征 x输出: 标签 y学习目标: 学习出 f(x) 等价于 y 二、三大类型任务 类型英文特点示例回归Regression输出是连续值房价预测分类Cla…...

LVS+Keepalived+DNS 高可用项目

项目架构 主机规划 主机IP角色软件lb-master172.25.250.105主备负载均衡器ipvsadm&#xff0c;keepalivedlb-backup172.25.250.106同时做web和dns调度ipvsadm&#xff0c;keepaliveddns-master172.25.250.107VIP&#xff1a;172.25.250.100binddns-slave172.25.250.108LVS DNS…...

app逆向专题三:adb工具的使用

app逆向专题三&#xff1a;adb工具的使用 一、adb工具的配置二、adb工具的下载与安装 一、adb工具的配置 adb它是一个通用命令行工具&#xff0c;它可以作为Android与PC端连接的一个桥梁&#xff0c;所以adb又成为Android调试桥&#xff0c;用户可以通过adb在电脑上对Android设…...

CAD导入arcgis中保持面积不变的方法

1、加载CAD数据&#xff0c;选择面数据&#xff0c;如下&#xff1a; 2、加载进来后&#xff0c;右键导出数据&#xff0c;导出成面shp数据&#xff0c;如下&#xff1a; 3、选择存储路径&#xff0c;导出面后计算面积&#xff0c;如下&#xff1a; 4、与CAD中的闭合线面积核对…...

提示词 (Prompt)

引言 在生成式 AI 应用中&#xff0c;Prompt&#xff08;提示&#xff09;是与大型语言模型&#xff08;LLM&#xff09;交互的核心输入格式。Prompt 的设计不仅决定了模型理解任务的准确度&#xff0c;还直接影响生成结果的风格、长度、结构与可控性。随着模型能力和应用场景…...

并查集(Java模板及优化点解析)

并查集 一、核心思想 并查集&#xff08;Union-Find&#xff09;是一种处理不相交集合合并与查询的高效数据结构&#xff0c;核心功能包括&#xff1a; 合并&#xff08;Union&#xff09;&#xff1a;将两个不相交集合合并为一个集合。查询&#xff08;Find&#xff09;&am…...

本地部署大模型(ollama模式)

分享记录一下本地部署大模型步骤。 大模型应用部署可以选择 ollama 或者 LM Studio。本文介绍ollama本地部署 ollama官网为&#xff1a;https://ollama.com/ 进入官网&#xff0c;下载ollama。 ollama是一个模型管理工具和平台&#xff0c;它提供了很多国内外常见的模型&…...

【JavaEE】TCP流套接字编程

目录 API 1.Socket类(客户端) 2.ServerSocket类(服务端) 创建回显服务器-客户端 服务器引入多线程 服务器引入线程池 解疑惑 长短连接 在Java中&#xff0c;TCP流套接字是基于TCP协议实现的网络通信方式&#xff0c;提供面向连接、可靠、有序的双向字节流传输。 API T…...

SQL问题分析与诊断(8)——分析方法1

8.4. 方法 8.4.1. 分析Cost方法 8.4.1.1. 方法说明 SQL Server中,通过阅读和分析SQL语句的评估查询计划,才是现实SQL优化工作中经常被采用的方法。然而,与Oracle等关系库类似,我们对SQL语句的查询计划进行阅读和分析时,首先要做的就是对SQL语句的整个查询计划进行快速的…...