【Python 算法零基础 4.排序 ⑨ 堆排序】

news2025/6/7 18:38:09

目录

一、问题描述

二、算法对比

1.朴素算法

① 数组模拟容器

②  有序数组模拟容器

2.二叉堆

① 二叉堆特点

② 数组表示二叉树

③ 堆

④ 大顶堆

⑤ 小顶堆

⑥ 元素插入

⑦ 获取堆顶

⑧ 堆顶元素删除

三、代码分析

1.工具函数

2.调整大顶堆函数

Ⅰ、计算子节点索引

Ⅱ、找出最大值索引

Ⅲ、交换并递归调整

3.堆排序流程

Ⅰ、构建最大堆

Ⅱ、交换元素并调整堆

四、实战练习

912. 排序数组

思路与算法


关卡一一都击破

                        —— 25.5.30

选择排序回顾

① 遍历数组从索引 0 到 n-1n 为数组长度)。

② 每轮确定最小值假设当前索引 i 为最小值索引 min_index。从 i+1 到 n-1 遍历,若找到更小元素,则更新 min_index

③ 交换元素若 min_index ≠ i,则交换 arr[i] 与 arr[min_index]

'''
① 遍历数组:从索引 0 到 n-1(n 为数组长度)。

② 每轮确定最小值:假设当前索引 i 为最小值索引 min_index。从 i+1 到 n-1 遍历,若找到更小元素,则更新 min_index。

③ 交换元素:若 min_index ≠ i,则交换 arr[i] 与 arr[min_index]。
'''

def selectionSort(arr: List[int]):
    n = len(arr)
    for i in range(n):
        min_index = i
        for j in range(i+1, n):
            if arr[j] < arr[min_index]:
                min_index = j
        if min_index != i:
            arr[i], arr[min_index] = arr[min_index], arr[i]
    return arr

冒泡排序回顾

① 初始化设数组长度为 n

② 外层循环遍历 i 从 0 到 n-1(共 n 轮)。

③ 内层循环对于每轮 i,遍历 j 从 0 到 n-i-2

④ 比较与交换若 arr[j] > arr[j+1],则交换两者。

⑤ 结束条件重复步骤 2-4,直到所有轮次完成。

'''
① 初始化:设数组长度为 n。

② 外层循环:遍历 i 从 0 到 n-1(共 n 轮)。

③ 内层循环:对于每轮 i,遍历 j 从 0 到 n-i-1。

④ 比较与交换:若 arr[j] > arr[j+1],则交换两者。

⑤ 结束条件:重复步骤 2-4,直到所有轮次完成。
'''
def bubbleSort(arr: List[int]):
    n = len(arr)
    for i in range(n):
        for j in range(n-i-1):
            if arr[j] > arr[j+1]:
                arr[j], arr[j+1] = arr[j+1], arr[j]
    return arr

插入排序回顾

① 遍历未排序元素从索引 1 到 n-1

② 保存当前元素将 arr[i] 存入 current

③ 元素后移从已排序部分的末尾(索引 j = i-1)向前扫描,将比 current 大的元素后移。直到找到第一个不大于 current 的位置或扫描完所有元素。

④ 插入元素将 current 放入 j+1 位置。

'''
① 遍历未排序元素:从索引 1 到 n-1。

② 保存当前元素:将 arr[i] 存入 current。

③ 元素后移:从已排序部分的末尾(索引 j = i-1)向前扫描,将比 current 大的元素后移。直到找到第一个不大于 current 的位置或扫描完所有元素。

④ 插入元素:将 current 放入 j+1 位置。
'''
def insertSort(arr: List[int]):
    n = len(arr)
    for i in range(n):
        current = arr[i]
        j = i - 1
        while current < arr[j] and j >0:
            arr[j+1] = arr[j]
            j -= 1
        arr[j + 1] = current
    return arr

计数排序回顾

① 初始化设数组长度为 n,元素最大值为 r。创建长度为 r+1 的计数数组 count,初始值全为 0。

② 统计元素频率遍历原数组 arr,对每个元素 x,将 count[x] 加 1。

③ 重构有序数组初始化索引 index = 0。遍历计数数组 count,索引 v 从 0 到 r,若 count[v] > 0,则将 v 填入原数组 arr[index],并将 index 加 1。count[v] - 1,重复此步骤直到 count[v] 为 0。

④ 结束条件当计数数组遍历完成时,排序结束。

'''
输入全为非负整数,且所有元素 ≤ r

① 初始化:设数组长度为 n,元素最大值为 r。创建长度为 r+1 的计数数组 count,初始值全为 0。

② 统计元素频率:遍历原数组 arr,对每个元素 x,将 count[x] 加 1。

③ 重构有序数组:初始化索引 index = 0。遍历计数数组 count,索引 v 从 0 到 r,
若 count[v] > 0,则将 v 填入原数组 arr[index],并将 index 加 1。
count[v] - 1,重复此步骤直到 count[v] 为 0。

④ 结束条件:当计数数组遍历完成时,排序结束。
'''

def countingSort(arr: List[int], r: int):
    # count = [0] * len(r + 1)
    count = [0 for i in range(r + 1)]
    for x in arr:
        count[x] += 1
    index = 0
    for v in range(r + 1):
        while count[v] > 0:
            arr[index] = v
            index += 1
            count[v] -= 1
    return arr

归并排序回顾

Ⅰ、递归分解列表

① 终止条件:若链表为空或只有一个节点(head is None 或 head.next is None),直接返回头节点。

② 快慢指针找中点:初始化 slow 和 fast 指针,slow 指向头节点,fast 指向头节点的下一个节点。fast 每次移动两步,slow 每次移动一步。当 fast 到达末尾时,slow 恰好指向链表的中间节点。

③ 分割链表:将链表从中点断开,head2 指向 slow.next(后半部分的头节点)。将 slow.next 置为 None,切断前半部分与后半部分的连接。

④ 递归排序子链表:对前半部分(head)和后半部分(head2)分别递归调用 mergesort 函数。

Ⅱ、合并两个有序列表

① 创建虚拟头节点创建一个值为 -1 的虚拟节点 zero,用于简化边界处理。使用 current 指针指向 zero,用于构建合并后的链表。

② 比较并合并节点:遍历两个子链表 head1 和 head2,比较当前节点的值:若 head1.val <= head2.val,将 head1 接入合并链表,并移动 head1 指针。否则,将 head2 接入合并链表,并移动 head2 指针。每次接入节点后,移动 current 指针到新接入的节点。

③ 处理剩余节点:当其中一个子链表遍历完后,将另一个子链表的剩余部分直接接入合并链表的末尾。

④ 返回合并后的链表:虚拟节点 zero 的下一个节点即为合并后的有序链表的头节点。

'''
Ⅰ、递归分解列表

① 终止条件:若链表为空或只有一个节点(head is None 或 head.next is None),直接返回头节点。

② 快慢指针找中点:初始化 slow 和 fast 指针,slow 指向头节点,fast 指向头节点的下一个节点。fast 每次移动两步,slow 每次移动一步。当 fast 到达末尾时,slow 恰好指向链表的中间节点。

③ 分割链表:将链表从中点断开,head2 指向 slow.next(后半部分的头节点)。将 slow.next 置为 None,切断前半部分与后半部分的连接。

④ 递归排序子链表:对前半部分(head)和后半部分(head2)分别递归调用 mergesort 函数。

Ⅱ、合并两个有序列表

① 创建虚拟头节点:创建一个值为 -1 的虚拟节点 zero,用于简化边界处理。使用 current 指针指向 zero,用于构建合并后的链表。

② 比较并合并节点:遍历两个子链表 head1 和 head2,比较当前节点的值:若 head1.val <= head2.val,将 head1 接入合并链表,并移动 head1 指针。否则,将 head2 接入合并链表,并移动 head2 指针。每次接入节点后,移动 current 指针到新接入的节点。

③ 处理剩余节点:当其中一个子链表遍历完后,将另一个子链表的剩余部分直接接入合并链表的末尾。

④ 返回合并后的链表:虚拟节点 zero 的下一个节点即为合并后的有序链表的头节点。
'''
def mergesort(self, head: ListNode):
    if head is None or head.next is None:
        return head
    slow, fast = head, head.next
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next
    head2 = slow.next
    slow.next = None
    return self.merge(self.mergesort(head), self.mergesort(head2))

def merge(self, head1: ListNode, head2: ListNode):
    zero = ListNode(-1)
    current = zero
    while head1 and head2:
        if head1.val <= head2.val:
            current.next = head1
            head1 = head1.next
        else:
            current.next = head2
            head2 = head2.next
        current = current.next
    current.next = head1 if head1 else head2
    return zero.next

快速排序回顾

Ⅰ、分区函数 Partition

① 随机选择基准元素:根据左右边界下标随机选择基准元素(选择的是元素并非下标),将基准元素赋值变量进行后续比较

② 交换基准元素:将基准元素移动到最左边,将基准元素存储在变量中,

③ 分区操作:对于基准元素右边的元素,找到第一个小于基准元素的值,移动到最左边;对于基准元素左边的元素,找到第一个大于基准元素的值,移动到最右边

④ 返回基准元素的最终位置:循环执行完毕后,基准元素左边的值都小于它,基准元素右边的值都大于它

Ⅱ、递归快速排序函数

① 定义递归终止条件:当左索引小于右索引时,结束递归

② 分区操作: 执行第一次分区操作,找到基准元素

③ 递归调用分区函数:将基准元素的左边、右边部分分别传入递归函数进行排序

'''
Ⅰ、分区函数 Partition

① 随机选择基准元素:根据左右边界下标随机选择基准元素(选择的是元素并非下标),将基准元素赋值变量进行后续比较

② 交换基准元素:将基准元素移动到最左边,将基准元素存储在变量中,

③ 分区操作:对于基准元素右边的元素,找到第一个小于基准元素的值,移动到最左边;对于基准元素左边的元素,找到第一个大于基准元素的值,移动到最右边

④ 返回基准元素的最终位置:循环执行完毕后,基准元素左边的值都小于它,基准元素右边的值都大于它

Ⅱ、递归排序函数

① 定义递归终止条件:当左索引小于右索引时,结束递归

② 分区操作: 执行第一次分区操作,找到基准元素

③ 递归调用分区函数:将基准元素的左边、右边部分分别传入递归函数进行排序
'''

def Partition(arr, left, right):
    idx = random.randint(left, right)
    arr[left], arr[idx] = arr[idx], arr[left]
    l = left
    r = right
    x = arr[l]
    while l < r:
        while l < r and x < arr[r]:
            r -= 1
        if l < r:
            arr[l], arr[r] = arr[r], arr[l]
            l += 1

        while l < r and x > arr[l]:
            l += 1
        if l < r:
            arr[l], arr[r] = arr[r], arr[l]
            r -= 1
    return l

def quickSort(arr, l, r):
    if l >= r:
        return
    node = self.quickSort(l, r)
    self.quickSort(arr, l, node-1)
    self.quickSort(arr, node+1, r)
    return arr

桶排序回顾

① 初始化桶和频率数组: 创建字符长度+1的桶bucket,索引 i 表示频率为 i 的字符列表;长度为max的频率数组count,用于记录每个字符的出现次数

② 统计字符频率:通过 ord(char) 获取字符的ASCII码,作为频率数组的索引

③ 将字符按照频率放入桶中:遍历频率数组,将每个字符以频率作为索引放入数组中

④ 返回桶数组:返回桶数组,其中每个桶包含对应频率的字符列表

def bucketSort(arr, max_val):  # 移除 max_val 表示字符编码最大值(如 256)
    n = len(arr)
    # 初始化桶:索引范围 [0, max_val-1]
    bucket = [[] for _ in range(max_val)]
    
    # 分布:按字符编码放入桶
    for char in arr:
        bucket[ord(char)].append(char)  # 索引 = 字符编码值
    
    # 合并桶(索引升序即字符升序)
    sorted_arr = []
    for b in bucket:
        sorted_arr.extend(b)  # 每个桶内元素已按插入顺序排列
    
    return sorted_arr  # 返回排序后的一维数组

基数排序

① 初始化参数和辅助数组设置最大元素数MAX_N为 50000,最大位数MAX_T为 8,进制BASE为 10;计算并存储基数的各次幂(如 10⁰, 10¹, ..., 10⁷)到数组PowOfBase

② 预处理数组元素为每个元素加上BASE^(MAX_T-1)(即 10⁷),确保所有元素变为正数;这一步是为了处理可能的负数输入,将其转换为正数进行排序

③ 按位进行多轮排序从最低有效位(个位)开始,逐位进行处理(共进行MAX_T轮)

        分配阶段将元素分配到对应的桶(0-9)中对每个元素,计算当前位上的数字(通过整除和取模运算)

        收集阶段按桶的顺序(0 到 9)依次收集元素;将收集的元素依次放回原数组,覆盖原有的顺序

④ 恢复原始数值排序完成后,从每个元素中减去BASE^(MAX_T-1)(即 10⁷);恢复元素的原始值,完成排序过程

'''
基数排序

① 初始化参数和辅助数组:设置最大元素数MAX_N为 50000,最大位数MAX_T为 8,进制BASE为 10;计算并存储基数的各次幂(如 10⁰, 10¹, ..., 10⁷)到数组PowOfBase中

② 预处理数组元素:为每个元素加上BASE^(MAX_T-1)(即 10⁷),确保所有元素变为正数;这一步是为了处理可能的负数输入,将其转换为正数进行排序

③ 按位进行多轮排序:从最低有效位(个位)开始,逐位进行处理(共进行MAX_T轮)

        分配阶段:将元素分配到对应的桶(0-9)中对每个元素,计算当前位上的数字(通过整除和取模运算)

        收集阶段:按桶的顺序(0 到 9)依次收集元素;将收集的元素依次放回原数组,覆盖原有的顺序

④ 恢复原始数值:排序完成后,从每个元素中减去BASE^(MAX_T-1)(即 10⁷);恢复元素的原始值,完成排序过程
'''
    MAX_N = 50000    # 最多的元素数
    MAX_T = 8        # 元素的最大位数
    BASE = 10        # 定义数字的进制

    def RedixSort(self, arr):
        n = len(arr)
        PowOfBase = [1 for i in range(self.MAX_T)]    # 代表BASE的多少次方
        for i in range(1, self.MAX_T):
            PowOfBase[i] = PowOfBase[i - 1] * self.BASE

        for i in range(n):
            arr[i] += PowOfBase[self.MAX_T - 1]

        pos = 0 
        while pos < self.MAX_T:
            RedixBucket = [ [] for i in range(self.BASE)]

            for i in range(n):
                rdx = arr[i] // PowOfBase[pos] % self.BASE
                RedixBucket[rdx].append( arr[i] )
            
            top = 0
            for i in range(self.BASE):
                for rb in RedixBucket[i]:
                    arr[top] = rb
                    top += 1
            
            pos += 1

        for i in range(n):
            arr[i] -= PowOfBase[self.MAX_T - 1]
        return arr

一、问题描述

二叉堆的数据结构其实是基于一种叫做完全二叉树的数据结构

        对于一个容器,有三种操作:

                ① I a:插入一个值为 a 的元素

                ② Q:查询最大的元素

                ③ D:删除最大的元素


二、算法对比

1.朴素算法

① 数组模拟容器

插入 I a—— O(1)

删除 D —— O(n)

查找 Q —— O(n)

②  有序数组模拟容器

插入 I a —— O(n)

删除 D —— O(1)

查找 Q —— O(1)


2.二叉堆

① 二叉堆特点

Ⅰ、O(1)时间获取最大值

Ⅱ、O(logn)时间进行元素的增删

Ⅲ、利用数组随机访问的特性模拟二叉树

Ⅳ、需要有数据结构中二叉树的概念基础

② 数组表示二叉树

parent(id) = (id - 1) / 2、        left(id) = id * 2 + 1、        right(id) = id * 2 + 2

子节点一定是个数,子节点一定是个

③ 堆

堆满足任意一个节点都比其子节点 大 / 小

④ 大顶堆

任意一个节点的值都比其子节点

⑤ 小顶堆

任意一个节点的值都比其子节点

⑥ 元素插入

往数组尾部插入一个元素;对插入的元素,比较它(在树型结构中)和它的父节点的大小关系,来决定是否和父节点进行交换

插入的情况,新插入节点只会上浮,不会下沉

 

⑦ 获取堆顶

返回数组中的第0个元素

⑧ 堆顶元素删除

获取数组中的最后一个元素,然后让堆顶元素与最后一个元素进行交换

将交换后的堆顶的元素不断做“下沉”操作,选择的进行交换,直到“交换后的堆顶的元素自己”成为最大的

删除数组的最后一个元素


三、代码分析

1.工具函数

给定一个元素下标,获取左子树下标

def lson(idx)
    return 2 * idx + 1

 给定一个元素下标,获取右子树下标

def rson(idx):
    return 2 * idx + 2

给定一个元素下标,获取父节点的下标 

def parrent(idx):
    return (idx - 1) / 2

判断函数,任意传入两个元素,返回两节点中更优的值,如果是小顶堆,则返回 a < b

# <: 小顶堆    >:大顶堆
def batter(a, b):
    return a > b
    # return a < b

2.调整大顶堆函数

Ⅰ、计算子节点索引

leftSon(curr) 和 rightSon(curr) 分别计算当前节点的左右子节点索引。

optId 初始化为当前节点索引,用于记录最大值的位置。

Ⅱ、找出最大值索引

比较当前节点与左右子节点的值:如果左子节点存在且值更大,则更新 optId 为左子节点索引。同理,对右子节点进行相同比较。better 函数默认实现为 a > b,确保构建最大堆。

Ⅲ、交换并递归调整

如果最大值不在当前节点(curr != optId),则交换当前节点与最大值节点。

递归调用 Heapify 处理被交换的子节点,确保其所有子树仍满足堆性质。

def Heapify(self, heap, size, curr):
    leftSonId = leftSon(curr)
    rightSonId = rightSon(curr)
    optId = curr
    if leftSonId < size and better(heap[leftSonId], heap[optId]):
        optId = leftSonId
    if rightSonId < size and better(heap[rightSonId], heap[optId]):
        optId = rightSonId

    if curr != optId:
        heap[curr], heap[optId] = heap[optId], heap[curr]
        self.Heapify(heap, size, optId)

3.堆排序流程

Ⅰ、构建最大堆

从最后一个非叶子节点(n//2 -1)开始,向上逐个调用Heapify,确保整个数组成为最大堆。

Ⅱ、交换元素并调整堆

循环过程将堆顶元素(最大值)与当前未排序部分的最后一个元素交换;减少堆的大小(size = i),将最大值排除在后续调整范围外;调用 Heapify(0) 重新调整剩余元素为最大堆。

效果每次循环将当前最大值移至数组末尾,最终形成升序排列。

    def sortArray(self, nums: List[int]) -> List[int]:
        n = len(nums)
        for i in range(n // 2, -1, -1):
            self.Heapify(nums, n, i)

        for i in range(n-1, -1, -1):
            nums[0], nums[i] = nums[i], nums[0]
            self.Heapify(nums, i, 0)

        return nums

四、实战练习

912. 排序数组

给你一个整数数组 nums,请你将该数组升序排列。

你必须在 不使用任何内置函数 的情况下解决问题,时间复杂度为 O(nlog(n)),并且空间复杂度尽可能小。

    示例 1:

    输入:nums = [5,2,3,1]
    输出:[1,2,3,5]
    

    示例 2:

    输入:nums = [5,1,1,2,0,0]
    输出:[0,0,1,1,2,5]
    

    提示:

    • 1 <= nums.length <= 5 * 104
    • -5 * 104 <= nums[i] <= 5 * 104

    思路与算法

    辅助函数(节点关系):

    leftSon(idx)返回节点idx的左子节点索引(2*idx + 1)。

    rightSon(idx)返回节点idx的右子节点索引(2*idx + 2)。

    parent(idx)返回节点idx的父节点索引((idx-1)//2)。

    better(a, b)比较函数,默认返回a > b,用于定义最大堆的比较规则。

    Heapify 函数:

    Ⅰ、计算子节点索引

    leftSon(curr) 和 rightSon(curr) 分别计算当前节点的左右子节点索引。

    optId 初始化为当前节点索引,用于记录最大值的位置。

    Ⅱ、找出最大值索引

    比较当前节点与左右子节点的值:如果左子节点存在且值更大,则更新 optId 为左子节点索引。同理,对右子节点进行相同比较。better 函数默认实现为 a > b,确保构建最大堆。

    Ⅲ、交换并递归调整

    如果最大值不在当前节点(curr != optId),则交换当前节点与最大值节点。

    递归调用 Heapify 处理被交换的子节点,确保其所有子树仍满足堆性质。

    sortArray 函数

    构建最大堆:从最后一个非叶子节点(n//2 -1)开始,向上逐个调用Heapify,确保整个数组成为最大堆。

    循环过程将堆顶元素(最大值)与当前未排序部分的最后一个元素交换;减少堆的大小(size = i),将最大值排除在后续调整范围外;调用 Heapify(0) 重新调整剩余元素为最大堆。

    效果每次循环将当前最大值移至数组末尾,最终形成升序排列。

    def leftSon(idx):
        return 2 * idx + 1
    
    def rightSon(idx):
        return 2 * idx + 2
    
    def parent(idx):
        return (idx - 1) // 2
    
    def better(a, b):
        return a > b 
    
    class Solution:
        def Heapify(self, heap, size, curr):
            leftSonId = leftSon(curr)
            rightSonId = rightSon(curr)
            optId = curr
            if leftSonId < size and better(heap[leftSonId], heap[optId]):
                optId = leftSonId
            if rightSonId < size and better(heap[rightSonId], heap[optId]):
                optId = rightSonId
    
            if curr != optId:
                heap[curr], heap[optId] = heap[optId], heap[curr]
                self.Heapify(heap, size, optId)
    
        def sortArray(self, nums: List[int]) -> List[int]:
            n = len(nums)
            for i in range(n // 2, -1, -1):
                self.Heapify(nums, n, i)
    
            for i in range(n-1, -1, -1):
                nums[0], nums[i] = nums[i], nums[0]
                self.Heapify(nums, i, 0)
    
            return nums

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

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

    相关文章

    Deepseek/cherry studio中的Latex公式复制到word中

    需要将Deepseek/cherry studio中公式复制到word中&#xff0c;但是deepseek输出Latex公式&#xff0c;比如以下Latex代码段&#xff0c;需要通过Mathtype翻译才能在word中编辑。 $$\begin{aligned}H_1(k1) & H_1(k) \frac{1}{A_1} \left( Q_1 u_1(k) Q_{i1} - Q_2 u_2(k…

    32单片机——窗口看门狗

    1、WWDG的简介 WWDG&#xff1a;Window watchdog&#xff0c;即窗口看门狗 窗口看门狗本质上是能产生系统复位信号和提前唤醒中断的递减计数器 WWDG产生复位信号的条件&#xff1a; &#xff08;1&#xff09;当递减计数器值从0x40减到0x3F时复位&#xff08;即T6位跳变到0&a…

    IDEA 中 Undo Commit,Revert Commit,Drop Commit区别

    一、Undo Commit 适用情况&#xff1a;代码修改完了&#xff0c;已经Commit了&#xff0c;但是还未push&#xff0c;然后发现还有地方需要修改&#xff0c;但是又不想增加一个新的Commit记录。这时可以进行Undo Commit&#xff0c;修改后再重新Commit。如果已经进行了Push&…

    DAY43打卡

    浙大疏锦行 kaggle找到一个图像数据集&#xff0c;用cnn网络进行训练并且用grad-cam做可视化 进阶&#xff1a;并拆分成多个文件 fruit_cnn_project/ ├─ data/ # 存放数据集&#xff08;需手动创建&#xff0c;后续放入图片&#xff09; │ ├─ train/ …

    Leetcode 1892. 页面推荐Ⅱ

    1.题目基本信息 1.1.题目描述 表&#xff1a; Friendship ---------------------- | Column Name | Type | ---------------------- | user1_id | int | | user2_id | int | ---------------------- (user1_id,user2_id) 是 Friendship 表的主键(具有唯一值的列的组合…

    进程——环境变量及程序地址空间

    目录 环境变量 概念 补充&#xff1a;命令行参数 引入 其它环境变量 理解 程序地址空间 引入 理解 虚拟地址存在意义 环境变量 概念 环境变量一般是指在操作系统中用来指定操作系统运行环境的一些参数。打个比方&#xff0c;就像你布置房间&#xff0c;这些参数就类…

    VR视频制作有哪些流程?

    VR视频制作流程知识 VR视频制作&#xff0c;作为融合了创意与技术的复杂制作过程&#xff0c;涵盖从初步策划到最终呈现的多个环节。在这个过程中&#xff0c;我们可以结合众趣科技的产品&#xff0c;解析每一环节的实现与优化&#xff0c;揭示背后的奥秘。 VR视频制作有哪些…

    Ubuntu 系统部署 MySQL 入门篇

    一、安装 MySQL 1.1 更新软件包 在终端中执行以下命令&#xff0c;更新系统软件包列表&#xff0c;确保安装的是最新版本的软件&#xff1a; sudo apt update 1.2 安装 MySQL 执行以下命令安装 MySQL 服务端&#xff1a; sudo apt install mysql-server 在安装过程中&…

    【MATLAB代码】制导——平行接近法,三维,目标是运动的,订阅专栏后可直接查看MATLAB源代码

    文章目录 运行结果简介代码功能概述运行结果核心模块解析代码特性与优势MATLAB例程代码调整说明相关公式视线角速率约束相对运动学方程导引律加速度指令运动学更新方程拦截条件判定运行结果 运行演示视频: 三维平行接近法导引运行演示 简介 代码功能概述 本代码实现了三维空…

    黑马Java面试笔记之 微服务篇(SpringCloud)

    一. SpringCloud 5大组件 SpringCloud 5大组件有哪些&#xff1f; 总结 五大件分别有&#xff1a; Eureka&#xff1a;注册中心Ribbon&#xff1a;负载均衡Feign&#xff1a;远程调用Hystrix&#xff1a;服务熔断Zuul/Gateway&#xff1a;网关 如果项目用到了阿里巴巴&#xff…

    CLIP多模态大模型的优势及其在边缘计算中的应用

    CLIP多模态大模型的优势及其在边缘计算中的应用 CLIP&#xff08;Contrastive Language-Image Pre-training&#xff09;模型&#xff0c;是OpenAI开发的一种多模态大模型。该模型通过对比学习的方式&#xff0c;在大规模图像-文本对上进行预训练&#xff0c;成功实现了图像和文…

    基于STM32语音识别柔光台灯

    基于STM32语音识别柔光台灯 &#xff08;程序&#xff0b;原理图&#xff0b;PCB&#xff0b;设计报告&#xff09; 功能介绍 具体功能&#xff1a; 基于语音识别的智能LED柔光台灯设计&#xff0c;主要包括语音识别模块应用&#xff0c;PWM波控制LED柔光灯的亮度&#xff0c…

    基于PSO粒子群优化的VMD-GRU时间序列预测算法matlab仿真

    目录 1.前言 2.算法运行效果图预览 3.算法运行软件版本 4.部分核心程序 5.算法仿真参数 6.算法理论概述 6.1变分模态分解&#xff08;VMD&#xff09; 6.2 门控循环单元&#xff08;GRU&#xff09; 6.3 粒子群优化&#xff08;PSO&#xff09; 7.参考文献 8.算法完…

    探索未知惊喜,盲盒抽卡机小程序系统开发新启航

    在消费市场不断追求新鲜感与惊喜体验的当下&#xff0c;盲盒抽卡机以其独特的魅力&#xff0c;迅速成为众多消费者热衷的娱乐与消费方式。我们紧跟这一潮流趋势&#xff0c;专注于盲盒抽卡机小程序系统的开发&#xff0c;致力于为商家和用户打造一个充满趣味与惊喜的数字化平台…

    基于开源AI大模型与AI智能名片的S2B2C商城小程序源码优化:企业成本管理与获客留存的新范式

    摘要&#xff1a;本文以企业成本管理的两大核心——外部成本与内部成本为切入点&#xff0c;结合开源AI大模型、AI智能名片及S2B2C商城小程序源码技术&#xff0c;构建了企业数字化转型的“技术-成本-运营”三维模型。研究结果表明&#xff0c;通过AI智能名片实现获客留存效率提…

    Python----目标检测(YOLO简介)

    一、 YOLO简介 [YOLO](You Only Look Once&#xff09;是一种流行的物体检测和图像分割模型&#xff0c; 由华盛顿大学的约瑟夫-雷德蒙&#xff08;Joseph Redmon&#xff09;和阿里-法哈迪&#xff08;Ali Farhadi&#xff09;开发&#xff0c;YOLO 于 2015 年推出&#xff0c…

    Profinet 协议 IO-Link 主站网关(三格电子)

    一、产品概述 1.1 产品用途 SG-PN-IOL-8A-001 网关是 Profinet 从转 IO-Link 主的网关设备 &#xff0c;可以将 IO-Link 从站设备接入 Profinet 系统&#xff0c;通过该网关可实现传感器及驱动器与控制 器之间的信息交互。网关有两个百兆网口和 8 个 IO-Link 端口&#xff0c;两…

    Ubuntu22.04 安装 Miniconda3

    Conda 是一个开源的包管理系统和环境管理系统&#xff0c;可用于 Python 环境管理。 Miniconda 是一个轻量级的 Conda 发行版。Miniconda 包含了 Conda、Python和一些基本包&#xff0c;是 Anaconda 的精简版本。 1.下载安装脚本 在 conda官网 找到需要的安装版本&#xff0…

    Hubstudio浏览器如何使用Loongproxy?

    1. 使用软件 1.1 Loongproxy 1. 顶级ISP资源&#xff1a;Loongproxy是神龙云旗下品牌&#xff0c;依托与全球领先ISP运营商的深度合作&#xff0c;Loongproxy 精选全球优质静态住宅IP资源。 2. IP池庞大&#xff1a;覆盖 100 国家/地区&#xff0c;构建庞大的 70 万 静态IP池…

    硬件工程师笔记——555定时器应用Multisim电路仿真实验汇总

    目录 一 555定时器基础知识 二、引脚功能 三、工作模式 1. 单稳态模式: 2. 双稳态模式(需要外部电路辅助): 3. 无稳态模式(多谐振荡器): 4. 可控脉冲宽度调制(PWM)模式: 四、典型应用 五、优点 二 555无稳态触发器 三 555单稳态触发器 四 555双稳态触发器…