【Python】全面掌握 Collections Deque:队列与栈的高效实现及动态内存管理指南

文章目录

    • 第一章:`deque` 的定义和特性
      • 1. 什么是双端队列(deque)
      • 2. `deque` 与普通列表(list)的性能差异
    • 第二章:构造函数
      • 1. 如何创建一个 `deque`
      • 2. 可选参数 `maxlen` 的作用和使用场景
    • 第三章:添加和删除元素
      • 1. 使用 `append` 方法在右端添加元素
      • 2. 使用 `appendleft` 方法在左端添加元素
      • 3. 使用 `pop` 方法从右端删除元素
      • 4. 使用 `popleft` 方法从左端删除元素
    • 第四章:访问和旋转元素
      • 1. 如何访问 `deque` 中的元素
      • 2. `deque` 的索引和切片操作
      • 3. `deque` 的 `rotate` 方法
    • 第五章:扩展 `deque`
      • 1. 使用 `extend` 方法在右端扩展多个元素
      • 2. 使用 `extendleft` 方法在左端扩展多个元素
    • 第六章:限制和性能考虑
      • 1. `maxlen` 属性的影响
      • 2. `deque` 的内存效率和操作效率
    • 第七章:实际应用场景
      • 1. 实现队列和栈
      • 2. 实现滑动窗口
        • 代码实现
        • 维护 `deque` 的递减性质
        • 例子解析
        • 检查和移除逻辑
      • 3. 广度优先搜索 (BFS)
    • 第八章:注意事项和局限性
      • 1. `deque` 的局限性
      • 2. 何时不应使用 `deque`

本文章主要探讨 Python collections 模块中的 deque 类,详尽介绍了其定义、特性、构造方法、操作技巧、实际应用场景以及其使用时的注意事项和局限性。

第一章:deque 的定义和特性

1. 什么是双端队列(deque)

deque,全名为双端队列(Double-Ended Queue),是一个由 Python 的 collections 模块提供的容器类型。它支持从两端进行元素的快速添加和删除操作。deque 是线程安全的,可以在不使用锁的情况下从两端操作,这使得它特别适合用于多线程编程中实现数据共享的队列。

deque 中,可以使用 append 来在队列的右端添加元素,使用 appendleft 在队列的左端添加元素。同样地,可以使用 pop 从右端删除元素,使用 popleft 从左端删除元素。这种灵活性使得 deque 不仅可以用作普通的队列,也可以作为栈使用,非常适合需要双向操作的场合。

在这里插入图片描述

2. deque 与普通列表(list)的性能差异

deque 和 Python 的内置列表(list)在使用和功能上有着明显的区别,特别是在性能方面:

  • 从两端添加或删除元素: 对于 deque,无论是从前端还是后端添加或删除元素,时间复杂度都是 O(1)。这得益于 deque 的数据结构设计,它允许两端都能高效地进行修改操作。相比之下,列表在尾部添加或删除元素(使用 appendpop)的效率也很高(O(1)),但在列表的开头插入或删除元素(如使用 insert(0, value)pop(0))时,性能会显著下降,因为这涉及到移动列表中的所有其他元素,时间复杂度为 O(n),其中 n 是列表的长度。
  • 内存效率: deque 在内存使用上通常比列表更加高效,因为它在两端的操作减少了内存重新分配的次数。列表在达到其容量极限时需要进行整体的内存重新分配,而 deque 则通过一个链表的形式分散存储,每次内存分配影响的范围较小。

由于这些特性,deque 是解决需要频繁修改两端元素的问题的理想选择,而列表则更适合那些主要进行尾部操作和顺序访问的任务。

第二章:构造函数

1. 如何创建一个 deque

要使用 deque,首先需要从 collections 模块中导入它。创建一个 deque 对象的基本方法非常简单,可以直接通过将一个可迭代对象传递给 deque 的构造函数来完成,这与创建列表类似。

from collections import deque

# 创建一个空的 deque
d = deque()

# 使用列表初始化 deque
d = deque([1, 2, 3, 4, 5])

# 使用字符串初始化,每个字符作为一个元素
d = deque("hello")

2. 可选参数 maxlen 的作用和使用场景

deque 的构造函数还接受一个名为 maxlen 的可选参数。这个参数用于设置 deque 可以容纳的最大元素数量。当设定了 maxlen 并且在 deque 中添加元素使其达到最大容量时,每当添加一个新元素,另一端的元素会被自动移除。

# 创建一个最大长度为 3 的 deque
d = deque([1, 2, 3], maxlen=3)

# 当尝试添加更多元素时,最旧的元素将被自动移除
d.append(4)  # deque([2, 3, 4])
d.appendleft(1)  # deque([1, 2, 3])

这个特性非常适合于需要限制容量的应用场景,如缓存机制或最近使用的项目(LRU)缓存。当只需要跟踪最新的几个项目时,使用 maxlen 可以自动维护 deque 的大小,避免手动删除老旧元素的复杂性。

第三章:添加和删除元素

deque 提供了多种方法来动态地添加和删除元素,使其非常适用于需要频繁修改的数据结构应用场景。以下是 deque 的基本操作方法的详细介绍。

1. 使用 append 方法在右端添加元素

append 方法是用于在 deque 的右端添加新元素的基本方法。这种操作非常快速,因为它不涉及元素之间的移动,只涉及到对尾部的访问和修改。

from collections import deque

d = deque([1, 2, 3])
d.append(4)  # 在右端添加元素
print(d)  # 输出: deque([1, 2, 3, 4])

这个方法通常用于实现栈(后进先出)或队列(先进先出)的操作。

2. 使用 appendleft 方法在左端添加元素

append 相对应,appendleft 方法允许用户在 deque 的左端添加新元素。这同样是一个时间复杂度为 O(1) 的操作,使得 deque 在需要从两端动态修改数据时表现出色。

d.appendleft(0)  # 在左端添加元素
print(d)  # 输出: deque([0, 1, 2, 3, 4])

appendleft 非常适合于需要从前端推入数据的场景,例如在某些特定的数据流或缓冲区操作中。

3. 使用 pop 方法从右端删除元素

pop 方法用于从 deque 的右端移除并返回最后一个元素,这是实现栈结构的标准操作。由于 deque 的设计,这种操作同样具有很高的效率(O(1))。

last_item = d.pop()  # 移除并返回右端元素
print(last_item)  # 输出: 4
print(d)  # 输出: deque([0, 1, 2, 3])

4. 使用 popleft 方法从左端删除元素

popleft 方法是 deque 中从左端移除并返回第一个元素的方法。这一操作对于实现队列结构至关重要,允许快速的从队列头部移除元素。

first_item = d.popleft()  # 移除并返回左端元素
print(first_item)  # 输出: 0
print(d)  # 输出: deque([1, 2, 3])

第四章:访问和旋转元素

尽管 deque 主要设计用于高效地从两端添加和删除元素,它也支持通过索引访问单个元素。然而,相比列表,deque 在中间元素的访问效率方面有一定的限制。

1. 如何访问 deque 中的元素

deque 支持通过索引访问元素,这类似于列表的索引方式。可以直接使用索引操作符访问任意位置的元素。

from collections import deque
d = deque([0, 1, 2, 3, 4])

# 访问第一个元素
print(d[0])  # 输出: 0

# 访问最后一个元素
print(d[-1])  # 输出: 4

尽管这种访问方式在语法上很直接,但需要注意的是,deque 中元素的随机访问不如列表高效,特别是在 deque 很大时。这是因为 deque 是用链表实现的,链表的随机访问性能相比于数组来说较差。

2. deque 的索引和切片操作

与列表不同,deque 并不直接支持切片操作,即不能直接使用切片语法如 d[0:3] 来获取 deque 的一部分。如果需要执行切片操作,可以先将 deque 转换为列表,再进行切片,或者使用 itertools.islice 实现更高效的切片。

# 将 deque 转换为列表进行切片
d_list = list(d)
print(d_list[0:3])  # 输出: [0, 1, 2]

# 使用 itertools.islice 进行切片
from itertools import islice
slice_result = islice(d, 0, 3)
print(list(slice_result))  # 输出: [0, 1, 2]

虽然操作有那么一些复杂,但它们提供了在需要时对 deque 进行灵活处理的方法。

deque 更多地被用于那些主要涉及到在两端添加或移除元素的情况,而不是频繁地随机访问中间元素。如果需要经常访问集合中间的元素,可能需要考虑是否有其他更适合的数据结构,如列表。当然,deque 提供了足够的功能来高效地处理数据,尤其是涉及队列和栈操作。

3. dequerotate 方法

deque 提供了一个非常有用的方法 rotate,可以旋转队列中的元素。这个方法可以向右或向左旋转 deque 中的元素,使得部分元素从一端移到另一端,非常适合于需要循环移位操作的场景。

rotate 方法接受一个参数 n。如果 n 是正数,deque 将会向右旋转;如果 n 是负数,则向左旋转。旋转操作的效果是将 deque 尾部的元素移动到前面,或者将前面的元素移动到尾部。

from collections import deque

d = deque([1, 2, 3, 4, 5])

# 向右旋转
d.rotate(1)
print(d)  # 输出: deque([5, 1, 2, 3, 4])

# 向左旋转
d.rotate(-1)
print(d)  # 输出: deque([1, 2, 3, 4, 5])

这种方法特别适合于需要周期性调整元素位置的应用,例如在某些算法中循环移位数组或处理缓冲流的数据。

第五章:扩展 deque

deque 提供了灵活的方法来扩展现有的双端队列,允许从两端迅速添加多个元素。这些功能特别适合于在执行批量操作时维护队列的效率和顺序。

1. 使用 extend 方法在右端扩展多个元素

extend 方法允许将一个可迭代对象中的元素添加到 deque 的右端。这个方法可以一次性添加多个元素,是扩展 deque 的一种高效方式。使用 extend 方法可以保持元素的添加顺序,与单独使用多次 append 方法相比,extend 在处理大量数据时更高效。

from collections import deque
d = deque([1, 2, 3])

# 使用 extend 在右端添加多个元素
d.extend([4, 5, 6])
print(d)  # 输出: deque([1, 2, 3, 4, 5, 6])

这种方法在需要将多个数据源或批量数据快速合并到现有队列中时非常有用,例如在数据流处理或批量文件处理中。

2. 使用 extendleft 方法在左端扩展多个元素

extend 类似,extendleft 方法允许将一个可迭代对象中的元素从左端添加到 deque 中。不同之处在于,extendleft 会逆序添加元素,因为它是从左端一次添加一个元素,所以首先添加的元素会被推到更远的位置。

# 使用 extendleft 在左端添加多个元素
d.extendleft([0, -1, -2])
print(d)  # 输出: deque([-2, -1, 0, 1, 2, 3, 4, 5, 6])

extendleft 方法的这种特性使得它在特定场景下非常有用,如需要反向保持元素添加的顺序时。然而,这也可能导致一些混淆,因为添加元素的顺序与 extend 是相反的。使用时需要特别注意这一点。

第六章:限制和性能考虑

当使用 deque 时,了解其性能限制和效率特点是至关重要的。这包括对 maxlen 属性的影响以及内存和操作效率的考量。

1. maxlen 属性的影响

maxlen 属性为 deque 设置了一个固定的长度限制。这意味着一旦 deque 达到了设定的最大长度,每当新元素被添加进来,最老的元素会自动被从另一端移除。这种机制有助于保持 deque 的大小不会无限增长,特别是在内存有限的环境中或者处理连续的数据流时。

from collections import deque

# 创建一个最大长度为 5 的 deque
d = deque(maxlen=5)
d.extend([1, 2, 3, 4, 5])
print(d)  # 输出: deque([1, 2, 3, 4, 5], maxlen=5)

# 添加新元素,自动移除最老元素
d.append(6)
print(d)  # 输出: deque([2, 3, 4, 5, 6], maxlen=5)

使用 maxlen 可以防止内存泄漏,确保 deque 不会因积累过多无关数据而影响性能。然而,这也意味着数据会丢失,因此在需要保留全部历史数据的应用中,使用 maxlen 需要谨慎。

2. deque 的内存效率和操作效率

内存效率deque 通过使用双向链表实现,可以实现两端的快速添加和删除操作,而不需要为整个容器重新分配内存。这与列表相比,在进行大量的插入和删除操作时可以显著减少内存的使用和提高性能。

操作效率

  • 两端操作deque 在其两端进行添加或删除操作都具有 O(1) 的时间复杂度,这使得它在实现如队列和栈等数据结构时非常高效。
  • 随机访问:尽管 deque 支持索引访问,但其效率低于列表,因为链表需要从头开始遍历到指定位置,时间复杂度为 O(n)。因此,如果依赖于频繁的随机访问,deque 可能不是最优选择。
  • 扩展操作extendextendleft 方法使得 deque 能够快速地从两端批量添加元素,这在处理大量数据时特别有用。

第七章:实际应用场景

deque 由于其独特的性能特性和灵活的操作方式,在许多编程问题中都有广泛的应用。下面列举了一些典型的使用场景,展示了 deque 在实际中的有效应用。

1. 实现队列和栈

由于 deque 支持从两端高效地添加和删除元素,它非常适合用于实现数据结构如队列(先进先出)和栈(后进先出)。

  • 队列deque 可以用作队列,其中元素从一端添加(通常是右端),从另一端(左端)移除。这模拟了队列的操作,适合于任务调度和消息处理等场景。

    from collections import deque
    queue = deque()
    queue.append('任务1')
    queue.append('任务2')
    queue.popleft()  # '任务1' 被处理
    
  • deque 也可以用作栈,其中元素从同一端添加和删除,模拟了栈的后进先出的特性。

    stack = deque()
    stack.append('页面1')
    stack.append('页面2')
    stack.pop()  # '页面2' 被访问
    

2. 实现滑动窗口

滑动窗口是一种常见的数据结构,用于处理连续数据流中的问题,如计算移动平均或滑动最大/最小值。deque 由于其两端操作的高效性,非常适合于实现滑动窗口的功能。

代码实现
from collections import deque

def maxSlidingWindow(nums, k):
    # 结果列表
    max_elements = []
    # 双端队列,用于存储可能是当前窗口最大值的元素索引
    d = deque()

    for i, num in enumerate(nums):
        # 移除所有小于当前元素的队尾元素的索引
        while d and nums[d[-1]] < num:
            d.pop()
        
        # 添加当前元素的索引到队列尾部
        d.append(i)

        # 检查队首元素是否超出窗口范围
        if d[0] == i - k:
            d.popleft()
        
        # 当索引大于等于窗口大小减1时,队首元素为当前窗口的最大值
        if i >= k - 1:
            max_elements.append(nums[d[0]])
    
    return max_elements

# 示例
nums = [1, 3, -1, -3, 5, 3, 6, 7]
k = 3
print(maxSlidingWindow(nums, k))  # 输出: [3, 3, 5, 5, 6, 7]

时间复杂度 O ( n ) O(n) O(n),其中 n 是数组长度。每个元素最多被添加和移除队列一次。

维护 deque 的递减性质

每当一个新元素(比如当前元素为 num)需要加入到 deque 时,会执行以下操作:

  1. 移除队尾小于当前元素的所有元素
    • 检查 deque 的队尾元素,如果队尾元素对应的数组值小于当前元素 num,则将这些元素从 deque 中移除。这是因为这些元素不可能再成为后续窗口的最大值了(当前元素更大,且更晚离开窗口)。
    • 这个过程会一直持续,直到 deque 为空或者队尾元素大于等于当前元素为止。
    • 这确保了当当前元素被加入 deque 后,deque 依然维持从左到右的递减顺序。
  2. 添加当前元素的索引到队尾
    • 紧接着将当前元素的索引添加到 deque 的队尾。
    • 因为之前已经移除了所有小于它的元素,所以保持了 deque 的递减性质。
例子解析

nums = [1, 3, -1, -3, 5, 3, 6, 7]k = 3 为例,考虑每一步的 deque 变化来理解:

  • 第一步i=0, num=1
    • deque = [0],只有一个元素,无需比较。
  • 第二步i=1, num=3
    • deque = [0] 中,索引0对应的值是1,小于3,所以移除。
    • deque = [1],现在 deque 只包含当前最大值3的索引。
  • 第三步i=2, num=-1
    • deque = [1] 中,索引1对应的值是3,大于-1,所以不移除。
    • deque = [1, 2],虽然-1不是最大值,但保留其索引以保持窗口大小。
  • 第四步i=3, num=-3
    • 类似地,deque = [1, 2],3和-1都大于-3,所以 deque 更新为 [1, 2, 3]
检查和移除逻辑
  • 检查条件if d[0] == i - k 这行代码检查 deque 的队首元素的索引是否等于 i - k。这里,i - k 是当前索引 i 减去窗口大小 k,得到的是当前窗口的前一个位置。如果 deque 的队首元素索引等于这个值,这意味着队首元素是窗口移动前的一个元素,现在已经不在当前窗口范围内了(已经超出了窗口的左边界)。
  • 移除操作:如果上述条件成立,使用 d.popleft()deque 的左端移除该过期的元素索引。这确保了 deque 始终只包含当前窗口范围内的元素索引,且队首是当前窗口的最大值的索引。

3. 广度优先搜索 (BFS)

在图或树的遍历中,广度优先搜索通常使用队列来维护当前层的节点。deque 由于其从两端高效地添加和删除操作,非常适合用作这类算法的数据结构基础。

from collections import deque

def bfs(graph, start):
    # 初始化一个集合来存储已访问过的节点,防止重复访问
    visited = set()
    # 初始化一个双端队列,开始时只包含起始节点
    queue = deque([start])

    # 循环执行,直到队列为空
    while queue:
        # 从队列的左端移除一个元素,这保证了按层次顺序访问
        vertex = queue.popleft()

        # 如果这个节点未被访问过,则进行处理
        if vertex not in visited:
            # 将节点标记为已访问
            visited.add(vertex)
            # 找出所有未访问的邻居节点并加入队列,保证这些节点将在未来被访问
            # graph[vertex] 访问当前节点的邻居
            # - visited 确保只添加还未访问的邻居
            queue.extend(graph[vertex] - visited)

    # 返回所有从起始节点可达的节点集合
    return visited

# 示例图的遍历
graph = {1: {2, 3}, 2: {4}, 3: {4}, 4: {5}, 5: {}}
print(bfs(graph, 1))  # 输出: {1, 2, 3, 4, 5}

第八章:注意事项和局限性

虽然 deque 在许多情况下表现出色,特别是在涉及到双端操作的场景中,但它并不总是最优的数据结构选择。了解 deque 的局限性和何时不应使用它是非常重要的。

1. deque 的局限性

  • 随机访问性能:尽管 deque 支持索引访问,但由于其底层是双向链表的实现,所以在随机访问时的性能不如数组或列表。每次访问都可能涉及从头节点或尾节点开始的遍历,尤其是访问中间元素时,性能会明显下降。
  • 不支持切片操作deque 不支持直接的切片操作,这在需要执行大量基于位置的操作时可能不太方便。虽然可以通过转换为列表来间接实现,但这种转换本身就会带来额外的性能开销。
  • 内存使用:与具有紧凑内存布局的数组相比,deque 的每个元素都可能需要更多的内存开销,因为除了存储数据外,还需要额外的空间来维护前驱和后继的链接。

2. 何时不应使用 deque

  • 需要频繁随机访问的场景:如果依赖于频繁的、快速的随机访问操作,使用列表或动态数组可能是更好的选择。例如,在需要经常访问或修改中间位置元素的大型数据集时,列表的性能通常会优于 deque
  • 大规模数据处理时的内存考量:虽然 deque 在添加和删除操作中非常高效,但如果要常大的数据集并且内存使用是一个关键考虑因素,更紧凑的数据结构(如数组)可能更合适。
  • 高度依赖切片操作的应用:在需要大量使用切片操作来处理数据的应用中,deque 的不支持直接切片可能成为一个限制。在这种情况下,列表或其他支持切片的数据结构可能更为适宜。

参考:

  • Fun with deques in Python
  • Sliding Window Maximum
  • Understanding Python deque (Double-Ended Queue)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vue3使用echarts做树图tree

vue3使用echarts做树图tree 1.安装echarts npm install echarts --save2.在main.js引入 import * as echarts from echarts // 全局方法 app.config.globalProperties.$echarts echarts3.使用 <div id"myChart" :style"{ width: 1000px, height: 1000px …

如何设置“mumu模拟器”使用fiddler抓取APP包?

1、打开fiddler-->tools-->optinons,设置如下信息https信息和connections 2、下载证书tools-->optinons-->https-->actions->Export Root Certificate to Desktop到桌面 3、mumu模拟器&#xff0c;安装证书 1)mumu进入桌面有个文件共享&#xff0c;打开后将桌…

python—字符串与正则表达式

1、编写程序&#xff0c;生成一个由15个不重复的大小写字母组成的列表。 &#xff08;1&#xff09;源代码&#xff1a; import random import string list1 [] while len(list1) < 15: x random.choice(string.ascii_letters) if x not in list1: list1.append(x) print…

pycharm-ieda-phpstorm超级好用插件,一键解释代码

功能&#xff1a;解释你看不懂的代码 当你在写python和Java代码的时候&#xff0c;总有你看不懂的代码&#xff0c;怎么办&#xff1f;csdn搜&#xff1f;那不麻烦&#xff0c;直接插件解决。 来安装&#xff1a;文件-设置 点击插件-Marketplace-搜索通义灵码 安装完成后&…

Qt Creator中变量与函数的注释 - 鼠标悬浮可显示

Qt Creator中变量与函数的注释 - 鼠标悬浮可显示 引言一、变量注释二、函数注释三、参考链接 引言 代码注释在软件开发中起着至关重要的作用。它们不仅有助于开发者理解和维护代码&#xff0c;还能促进团队协作&#xff0c;提高代码的可读性和可维护性。适当的注释应该是简洁明…

VoxAtnNet:三维点云卷积神经网络

VoxAtnNet:三维点云卷积神经网络 摘要IntroductionProposed VoxAtnNet 3D Face PAD3D face point cloud presentation attack Dataset (3D-PCPA) VoxAtnNet: A 3D Point Clouds Convolutional Neural Network for 摘要 面部生物识别是智能手机确保可靠和可信任认证的重要组件。…

16册 | 移动机器人(自动驾驶)系列

此文档整理推荐了16本移动机器人&#xff08;自动驾驶&#xff09;相关的书籍&#xff0c;内容包括&#xff1a;ROS、机器人基础开发、分布式机器人控制、集群机器人控制、嵌入式机器人、多传感器融合等等。 学习&#xff0c;切勿急于求成&#xff0c;读书自学&#xff0c;需多…

栈和队列总结

文章目录 前言一、栈和队列的实现1.栈的具体实现2.循环顺序队列的具体实现 二、栈和队列总结总结 前言 T_T此专栏用于记录数据结构及算法的&#xff08;痛苦&#xff09;学习历程&#xff0c;便于日后复习&#xff08;这种事情不要啊&#xff09;。所用教材为《数据结构 C语言版…

【启明智显技术分享】ESP32系列WiFi无线空中抓包指南

前言&#xff1a; 本文档旨在介绍 windows10 系统下网卡抓包工具(AC-1200)的驱动安装过程、Omnipeek 软件安装过程及Omnipeek软件与网卡抓包工具配合抓包的演示过程。 1、抓包工具(AC-1200)驱动安装 1.1 准备好抓包工具及厂家提供的抓包工具驱动文件 1.2 插上 USB 网卡&…

Linux——socket套接字与udp通信

目录 一、理解IP地址与端口 二、socket套接字 三、TCP与UDP的关系 四、网络字节序 五、socket编程 1.socket()创建套接字 2.填充sockaddr_in 结构体 3.bind() 绑定信息 4.recvfrom()接收消息 5.sendto()发送消息 六、UdpServer代码 一、理解IP地址与端口 IP地址是In…

Leetcode—1256. 加密数字【中等】Plus(bitset、find_first_not_of、erase)

2024每日刷题&#xff08;120&#xff09; Leetcode—1256. 加密数字 实现代码 class Solution { public:string encode(int num) {string ans;num 1;while(num ! 0) {ans to_string(num & 1);num num >> 1;}if(ans.empty()) {return "";} else {stri…

17 如何设计一锤子买卖的SDK

在前三个模块里&#xff0c;我将微服务根据目的性划分为三大类&#xff1a;读、写与扣减类&#xff0c;并针对每一大类涉及的各项技术问题讲解了应对方案。其实&#xff0c;每一类微服务除了本身业务特点涉及的技术问题外&#xff0c;在纯技术维度也有很多共性问题&#xff0c;…

房产中介小程序高效开发攻略:从模板到上线一站式服务

对于房产中介而言&#xff0c;拥有一个高效且用户友好的小程序是提升业务、增强客户黏性的关键。而采用直接复制模板的开发方式&#xff0c;无疑是实现这一目标的最佳途径&#xff0c;不仅简单快捷&#xff0c;而且性价比极高。 在众多小程序模板开发平台中&#xff0c;乔拓云网…

docker容器通俗理解

前言 如果大家没使用过Docker,就在电脑上下载一个VMware Workstation Pro&#xff0c;创建一个虚拟机安装一个windows操作一下感受一下,为什么我的电脑上还以再安装一台windows主机&#xff1f;其实你可以理解为Docker就是Linux系统的一个虚拟机软件。 我的Windows也可以安装…

WMS仓库库存管理软件如何优化工厂的仓库管理-亿发

如果一家工厂没有专业的WMS仓储软件支撑&#xff0c;管理原材料、辅料、半成品和产成品等环节可能会面临诸多问题。 在仓库管理方面&#xff0c;缺乏安全库存的管理会导致库存不足或过剩&#xff0c;而没有及时的缺货分析可能会导致生产中断。全凭人工核算剩余库存和订单质检的…

金价大跳水,美梦变噩梦!2024真正适合普通人的靠谱创业项目!2024适合30-40岁轻资产小生意

4月22日晚间&#xff0c;向上“狂飙”了一个多月的金价突然就“大跳水”。当日&#xff0c;每克金价均下调14块。在这次跳水中&#xff0c;有人欢喜有人愁&#xff1a;有投资者自报做空金价一夜狂赚14万&#xff0c;也有投资者哭诉&#xff0c;头晚进货到早上就净亏损2万&#…

Android 11 bindService 流程分析

我们可以使用bindService来跨进程通信&#xff0c;其使用方法如下 Intent intent new Intent("xxx"); intent.setPackage("xxx"); boolean result bindService(intent,new ServiceConn(),BIND_AUTO_CREATE);private class ServiceConn implements Servi…

STM32入门_江协科技_1~2_OB记录的自学笔记_STM32简介

1.综述 1.1. 课程简介 手打代码是加入了实操&#xff0c;增加学习效果&#xff1b; STM最小系统板面包板的硬件平台&#xff1b; 配套0.96寸的显示屏&#xff0c;便于调试&#xff1b; 因为使用面板板&#xff0c;所以如果程序现象不出来也有可能是硬件连接的问题&#xff1b; …

Allegro画PCB时如何只删除走线的一部分

如何只删除走线的一部分 1、第一步&#xff1a; 2、第二步&#xff1a; 3、第三步&#xff0c;点击相应的走线段就能删除了。 说明&#xff1a;上面的Cline和Line只的是电线和线,您按下删除后,就可以删除这两种东西,但删除的是一整条折线.把这两个取消掉,换成Cline Segs和Ot…

【代码随想录刷题记录】LeetCode283移动零

题目地址 1. 思路 1.1 基本思路及假设 拿到这个题&#xff0c;首先想到&#xff0c;这是类似删除元素的方法&#xff0c;因为删除元素也是移动元素&#xff0c;但是移动的方向和删除元素的方法刚好相反&#xff0c;我们都知道&#xff0c;如果在数组中删除某个元素&#xff…