11大排序的原理讲解和Python源码剖析

排序算法

【谁教你这么剪的 | 11大排序的原理讲解和Python源码剖析】 https://www.bilibili.com/video/BV1Zs4y1X7mN/?share_source=copy_web&vd_source=ed4a51d52f6e5c9a2cb7def6fa64ad6a

稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面。

不稳定:如果a原本在b的前面,而a=b,排序之后 a 可能会出现在 b 的后面。

时间复杂度:对排序数据的总的操作次数。反映当n变化时,操作次数呈现什么规律。

**空间复杂度:**是指算法在计算机内,执行时所需存储空间,它也是数据规模n的函数。

在这里插入图片描述
在这里插入图片描述

平均时,空复杂度【o(n^2),o(1)】

冒泡 Bubble Sort-o(n^2),o(1)

冒泡排序(Bubble Sort)是一种简单的排序算法。**它通过重复比较相邻元素,并将其中最大(或最小)的元素逐渐调换到正确的位置。**简单来说,就是把小的元素往前调或者把大的元素往后调。

为什么冒泡排序是一种稳定的排序算法?

  • 在冒泡排序中,当相邻的两个元素相等时,它们的位置不会交换,保持了它们在原始数组中的相对顺序。因此,冒泡排序是一种稳定的排序算法。

如果两个相等的元素相邻,冒泡排序只会比较元素大小不会交换。如果两个相等的元素没有相邻,即使通过前面的交换使它们相邻,由于它们相等,不会再发生交换,所以它们的顺序保持不变。因此,冒泡排序是一种稳定的排序算法。

#每次比较的元素数量会减少一对,直到没有需要交换的元素,排序完成。
def bubble_sort(lst):
    n = len(lst)
    for i in range(n-1,-1,-1):#1)从最后一个元素开始,依次比较相邻的两个元素。
        for j in range(0, i):
            #2)如果顺序错误(比如前一个元素 大于 后一个元素),则交换它们的位置。
            if lst[j] > lst[j+1]:
                lst[j], lst[j+1] = lst[j+1], lst[j]   
    return lst    

选择 Selection Sort-o(n^2),o(1)

![动画展示](https://i-blog.csdnimg.cn/direct/cb4c07259e324252ae8a4ad220d34c00.png

原理:**每一轮从待排序序列中选出最小的元素,将其放置在已排序序列的末尾。然后,再从剩余的未排序元素中寻找最小元素,放置在已排序序列的末尾。**重复这个过程,直到全部待排序的数据元素个数为零,即完成排序。

特点:

1)每一轮只进行一次交换,因此交换次数相对较少,但是比较次数较多

2)选择排序是一种不稳定的排序算法:例如,考虑以下序列:[5, 3, 5, 2]。在第一次选择最小元素时,会选择到索引为3的元素2,并将其与索引为0的元素5进行交换,得到序列[2, 3, 5, 5]。由于原序列中的两个5的相对顺序被改变,所以选择排序是不稳定的。

def selection_sort(lst):
    for i in range(len(lst) - 1): #遍历列表,i从第一个元素到倒数第二个元素
        min_index = i  #1)假设当前索引为i的元素为最小值
        for j in range(i + 1, len(lst)):  #2)遍历未排序部分的元素
            if lst[j] < lst[min_index]:  #3)如果找到比当前最小值更小的元素
                min_index = j  #4)更新最小值的索引
        lst[i], lst[min_index]=lst[min_index],lst[i]#4)最后,将当前最小值与未排序部分的第一个元素交换位置
    return lst  

插入 Insertion Sort -o(n^2),o(1)

动画展示:https://gitee.com/cjq1311485460/brush-question-notes/raw/master/4d409d3d864794158b9d00ed87970110.gif

它的原理是将待排序的数据 逐个插入到 已排序的数据序列中的适当位置,直到全部插入完毕。插入排序如同打扑克牌一样,每次将后面的牌插到前面已经排好序的牌中。

具体步骤如下:

  1. 假设第一个元素已经是有序的序列,将其视为已排序序列。
  2. 从第二个元素开始,将其与已排序序列中的元素逐个比较,找到合适的位置插入。
  3. 将待插入元素插入到已排序序列中的适当位置,使得插入后的序列仍然有序。
  4. 重复步骤2和步骤3,直到所有元素都插入到已排序序列中。

特点:

稳定排序,适用于小规模数据或基本有序的数据。

def insertion_sort(lst):
    n=len(lst)
    for i in range(1,n):  
        cur_num, pre_index = lst[i], i-1 #获取当前待插入的元素 和 其前一个元素的索引
        while pre_index>=0 and cur_num<=lst[pre_index]: #当 当前待插入的元素 不大于 前一个元素时,就进行插入操作
            lst[pre_index + 1] = lst[pre_index]  #1)将前一个元素 后移一位
            pre_index -= 1  #2)还原前一个元素的索引
        lst[pre_index + 1] = cur_num  #3)将 当前待插入的元素 插入到正确的位置
    return lst  

o(nlogn)

希尔排序 Shell Sort o(nlogn),o(1)

动画展示:https://gitee.com/cjq1311485460/brush-question-notes/raw/master/4f3d6ca502bddeb2b466cd2c2054be55.gif

希尔排序(Shell Sort)是插入排序的一种改进算法,通过使用不同的间隔序列来提高排序的效率。

希尔排序的关键在于选择合适的间隔序列,不同的间隔序列可能会影响排序的效率。常用的间隔序列有**希尔增量序列(gap = gap // 2)**和Hibbard增量序列(gap = 2^k - 1),可以根据具体情况选择合适的间隔序列。

具体步骤如下:

  1. 首先,确定初始的间隔(gap)值,可以将数据序列的长度除以2取整作为初始间隔值。
  2. 然后,使用间隔值 对 数据序列进行分组,每个分组包含 相隔间隔值个元素。
  3. 将每个分组内的元素 按照插入排序的方式进行排序。(粗略排序)
  4. 缩小间隔值,将当前间隔值除以2取整,得到新间隔值。(逐渐精排)
  5. 重复步骤2到步骤4,直到最后一个间隔值为1
  6. 最后,使用间隔值为1进行一次插入排序,完成最终的排序。

特点:

不稳定的排序

def shell_sort(lst):
    n = len(lst)  
    gap = n // 2  # 初始间隔值为列表长度的一半
    while gap > 0:  #当间隔值大于0时,进行排序
        for i in range(gap, n):  #遍历列表,从间隔值开始 到 最后一个元素
            cur_num=lst[i]
            #以间隔值为步长进行插入排序,如果当前元素小于前一个间隔的元素,则交换元素
            j=i
            while j>=gap and cur_num<lst[j - gap]:  
                    lst[j], lst[j - gap] = lst[j - gap], lst[j]  
        gap //= 2  # 缩小间隔值
    return lst  

【重要】归并 Merge Sort-o(nlogn),o(n)

动画展示:“https://gitee.com/cjq1311485460/brush-question-notes/raw/master/20181120110141.gif” alt=“img” style="

该算法使用分治法的思想,将一个未排序的序列 分割成 多个已排序的子序列,然后递归地将这些子序列合并成一个有序的序列。

具体步骤如下:

  1. 首先,将待排序的序列进行拆分,将序列分割成多个子序列,直到每个子序列只包含一个元素。
  2. 然后,递归地将这些子序列进行合并。在合并的过程中,不断比较两个子序列的元素,不断将较小的元素放入新的序列中,并将相应子序列的指针向后移动一位,重复这个过程直到其中一个子序列为空。然后将另一个非空的子序列中的剩余元素直接放入新的序列中。
  3. 重复步骤2和步骤3,直到所有的子序列都合并成一个有序的序列。

特点:

稳定的排序

# 定义合并函数:先两个两个排序归并,再四个四个排序归并,,,
def merge(nums, left, mid, right):
    tmp = []  # 合并后的结果序列
    i = left  # 左子序列的指针
    j = mid + 1  # 右子序列的指针
    while i <= mid and j <= right:
        if nums[i] <= nums[j]:  # 1.1)如果左子序列的元素小于等于右子序列的元素
            tmp.append(nums[i])  # 1.2)将左子序列的元素添加到结果序列中
            i += 1  # 1.3)左子序列指针向后移动一位
        else:
            tmp.append(nums[j])  # 1.4)否则,将右子序列的元素添加到结果序列中
            j += 1  # 1.5)右子序列指针向后移动一位

    # 2)将剩余的元素直接添加到结果序列中
    tmp.extend(nums[i:mid+1])
    tmp.extend(nums[j:right+1])
    
    #原地操作
    for i in range(left,right+1):
        nums[i]=tmp[i-left]
    return tmp


def merge_sort(nums, left, right):
    if left == right: return

    mid = left + (right - left) // 2
    merge_sort(nums, left, mid)  # 对左子序列进行递归排序
    merge_sort(nums, mid + 1, right)  # 对右子序列进行递归排序
    return merge(nums, left, mid, right)  # 合并左右子序列并返回结果序列


# nums=[1, 2, 2, 3, 5]
nums=[10,10, 9, 9, 8, 7,5,6,4,3,4,2]
print(merge_sort(nums,0,len(nums)-1))
print(nums[len(nums)-3])

【重要】快速 quick sort-o(nlogn),o(logn)

动画展示:<img src"https://gitee.com/cjq1311485460/brush-question-notes/raw/master/9a08519db9e53d08dc353299cfbe2147.gif" alt=“快速排序” style=“zoom:50%;” />

  • 为什么快速排序的最坏情况时间复杂度为O(n^2)?

    • 在最坏的情况下,选取的基准值是数组中的最大或最小元素,导致分区过程每次只能分出一个元素,这使得递归调用次数达到最大,时间复杂度为O(n^2)。
  • 为什么快速排序的平均时间复杂度为O(nlogn)?

    • 在平均情况下,基准值能够将数组均匀分割成两部分,使得递归调用的深度为O(logn),每层的分区操作需要O(n)时间,因此整体的时间复杂度为O(nlogn)。

第一种、快排递归流程:

(1) 从数列中挑出一个基准值

(2) 每次,将所有比基准值小的摆放在基准前面,所有比基准值大的摆在基准的后面(相同的数可以放到任一边)。【在这个分区退出之后,该基准就处于数列的中间位置】

(3) 最后,递归地 把"基准值前面的子数列" 和 “基准值后面的子数列” 进行排序。

第二种、快排非递归流程:

通过使用栈来模拟递归调用过程,可以将快速排序算法转化为循环实现,避免了递归调用的额外开销。这种方法可以提高快速排序的效率

步骤如下:

  1. 首先,将数组的起始位置 和 终止位置入栈。

  2. 然后,以栈是否为空为条件,开始进行循环。每次循环时,从栈中取出两个元素作为当前的区间,进行一次快速排序调用。

  3. 快速排序函数会返回一个分界点。根据这个分界点,将左侧的起点 和 终点、右侧的起点 和终点 进行判断。

  4. 如果左侧的起点小于终点,将左侧的起点 和 终点入栈,以便后续对该区间进行排序。

  5. 如果右侧的起点小于终点,将右侧的起点 和 终点入栈,以便后续对该区间进行排序。

  6. 继续循环,直到栈为空为止。

#[1]递归实现快速排序
# 划分函数,将列表划分为左右两个子序列,并返回划分点的位置
import random
def partition(nums, left, right):
    #优化点:将pivot的位置随机化
    # randpivot=random.randint(left,right)
    # nums[left],nums[randpivot]=nums[randpivot],nums[left]
    pivot=left # 再选择最左边的元素作为划分点的值

    #将区间内比nums[pivot]小的元素 都排在前面:
    #通过交换nums[i],nums[j]实现
    j = left+1
    for i in range(left+1,right+1):
        if nums[i]<=nums[pivot]:
            nums[i],nums[j]=nums[j],nums[i]
            j+=1
    nums[pivot],nums[j-1]=nums[j-1],nums[pivot] #将间隔nums[pivot]放中间位置,从而实现左小右大
    pivot=j-1
    return pivot

# 【1】递归实现快速排序
def QuickSort(nums: list, left: int, right: int) -> list:
    if left >= right: return
    p = partition(nums, left, right)  # 获取划分点的位置
    QuickSort(nums, left, p - 1)  # 对左子序列进行递归排序
    QuickSort(nums, p + 1, right)  # 对右子序列进行递归排序
    return nums

# nums=[1, 2, 2, 3, 5]
nums=[10,10, 9, 9, 8, 7,5,6,4,3,4,2]
print(QuickSort(nums,0,len(nums)-1))
print(nums[len(nums)-3])

    
# 【2】非递归实现快速排序(使用栈)
def QuickSort_No_Stack(nums: list, left: int, right: int) -> list:
    temp = [left, right]  # 使用栈来保存 待处理的子序列的左右边界
    
    while temp:
        j = temp.pop()  # 取出栈顶的右边界
        i = temp.pop()  # 取出栈顶的左边界
        index = partition(nums, i, j)  # 获取分界点的位置
        
        if i < index - 1:  # 如果左子序列存在元素,压入栈中
            temp.append(i)
            temp.append(index - 1)
        
        if j > index + 1:  # 如果右子序列存在元素,压入栈中
            temp.append(index + 1)
            temp.append(j)
    return nums

(一)快速排序的最好情况,时间复杂度O(nlogn),空间复杂度O(logn)

在理想的情况下,选取的分界点刚好就是这个区间的中位数。此时,就和归并排序基本一致了。

过程:

递归的第一层,n个数被划分为2个子区间,每个子区间的数字个数为n/2;

递归的第二层,n个数被划分为4个子区间,每个子区间的数字个数为n/4;

递归的第三层,n个数被划分为8个子区间,每个子区间的数字个数为n/8;

递归的第logn层,n个数被划分为n个子区间,每个子区间的数字个数为1;

与归并排序的区别

归并排序是从最后一层开始,进行merge操作,自底向上;而快速排序则从第一层开始,交换区间中 数字的位置,是自顶向下的。

与归并排序的相似点:

merge操作和快速排序的时间复杂度是一样的。对于每一个区间,交换处理的时候,都需要遍历区间中的每一个元素,每一层的时间复杂度都是O(n)。在理想的情况下,有logn层,所以快速排序最好的时间复杂度为O(nlogn)

快速排序的最坏情况,时间复杂度O(n^2),空间复杂度O(n)

在最坏的情况下,选取的分界点刚好就是这个区间的最大值或者最小值

过程:比如,需要对n个数排序,每一次进行交换处理的时候,选取的分界点刚好都是区间的最小值。这样的话,每次操作,都只能将最小值放到第一个位置,而剩下的元素,则没有任何变化

**结果:**这种方式,对于n个数来说,就需要操作n次,而每一次操作都需要遍历剩下的所有元素,完成交换,所以总时间复杂度为O(n^2)。

堆排序 Heap sort-o(nlogn),o(1)

【堆排序(heapsort)】 https://www.bilibili.com/video/BV1Eb41147dK/?share_source=copy_web&vd_source=ed4a51d52f6e5c9a2cb7def6fa64ad6a

堆排序的核心思想是通过建立一个初始堆来表示无序区,然后不断地将堆顶元素(即最值)输出,并将其与无序区的最后一个元素交换。这样,每次交换后,有序区的长度增加1,无序区的长度减少1,直到无序区为空,排序完成。

为什么堆排序的时间复杂度为O(NlogN)?

  • 堆排序首先构建一个堆,这个过程的时间复杂度为O(N)。然后,通过不断调整堆结构来排序,调整每个元素的时间复杂度为O(logN),因此总体时间复杂度为O(NlogN)。
#【写法1】调整堆,使得以i为根节点的子树满足堆的性质
def adjust_heap(lst, i, size):  # size:总节点数
    if i >= size: return

    left_index = 2 * i + 1  # 左子节点的索引
    right_index = 2 * i + 2  # 右子节点的索引

    largest_index = i  # 假设最大值的索引为根节点索引
    # 1)如果左子节点大于根节点,更新最大值的索引 为 左子节点的索引
    if left_index < size and lst[left_index] > lst[largest_index]:
        largest_index = left_index
        # 2)如果右子节点大于最大值,更新最大值的索引 为 右子节点的索引
    if right_index < size and lst[right_index] > lst[largest_index]:
        largest_index = right_index
        # 3)如果最大值的索引 不等于 根节点的索引,交换根节点和最大值
    # 4),并递归调整交换后的子树
    if largest_index != i:
        lst[largest_index], lst[i] = lst[i], lst[largest_index]
        adjust_heap(lst, largest_index, size)
        
# 【推荐:写法2】调整堆,使得以i为根节点的子树满足堆的性质
def adjust_heap(lst, i, size):  # size:总节点数
    dad = i
    son = dad * 2 + 1
    while son < size:  # 若子节点指标在范围内才做比较
        if son + 1 < size and lst[son] < lst[son + 1]:  # 先比较两个子节点大小,选择最大的
            son+=1  # 含递归过程中son的改变
        if lst[dad] > lst[son]:  # 如果父节点大于子节点代表调整完毕,直接跳出函数
            return
        else:  # 否则交换父子内容再继续子节点和孙节点比较
            lst[dad], lst[son] = lst[son], lst[dad]
            dad = son
            son = dad * 2 + 1

def HeapSort(lst):
    n = len(lst)
    # 1)初始化大顶堆:完全二叉树-上到下,左到右构建;父节点 一定大于 根节点
    # 实现: 建立初始堆,从最后一个 非叶子节点开始,依次向上调整 每个子树 使其满足堆的性质
    for i in range(n // 2, -1, -1):  # n//2:以一半的子树 作为堆化的根节点,再通过递归,就可构建出整个大顶堆
        adjust_heap(lst, i, n)
    # 2)在已构建大顶堆的基础上,做排序
    for i in range(n - 1, -1, -1):  # 从最后一个元素开始,依次将最大值 放到 末尾
        lst[0], lst[i] = lst[i], lst[0]  # 将根节点(即最大值)与 最后一个元素交换
        adjust_heap(lst, 0, i)  # 2)调整交换后的堆【即依次“除去”最后一个最大元素的堆】,从而堆顶依次为最大值
    return lst

# nums=[1, 2, 2, 3, 5]
nums=[10,10, 9, 9, 8, 7,5,6,4,3,4,2]
print(HeapSort(nums))
print(nums[len(nums)-3])

nums=[10,10, 9, 9, 8, 7,5,6,4,3,4,2]
print(HeapSort(nums))

【o(n+k)】

桶排序 bucket sort-o(k*o(选择的排序算法)),o(k),k为桶

桶排序的思想是将待排序列表划分为多个桶,然后对每个桶中的元素进行选择排序【不固定】,最后将排序后的元素按照桶的顺序依次放回原列表。桶排序适用于待排序列表中元素的分布比较均匀的情况。桶排序的时间复杂度取决于桶的数量和每个桶中元素的排序算法。在这段代码中,使用了冒泡排序对每个桶中的元素进行排序。

为什么桶排序对数据分布均匀的数据效果更好?

  • 桶排序将数据分到多个桶中,然后对每个桶内的数据进行选择排序。如果数据分布均匀,每个桶内的数据量相对均衡,排序效率较高。但如果数据分布不均匀,有些桶内可能会有大量数据,导致排序效率下降。

具体的算法步骤如下:

  1. 划分桶:确定桶的数量和范围。

  2. 数据入桶:将待排序的数据按照规则放入对应的桶中。

  3. 桶内排序:对每个桶中的数据进行排序,可以使用其他排序算法,如选择排序、插入排序、快速排序等。

  4. 数据合并:将每个桶中的数据按照顺序依次合并,得到最终的有序序列。

def selection_sort(lst):
    for i in range(len(lst) - 1): #遍历列表,i从第一个元素到倒数第二个元素
        min_index = i  #1)假设当前索引为i的元素为最小值
        for j in range(i + 1, len(lst)):  #2)遍历未排序部分的元素
            if lst[j] < lst[min_index]:  #3)如果找到比当前最小值更小的元素
                min_index = j  #4)更新最小值的索引
        lst[i], lst[min_index]=lst[min_index],lst[i]#4)最后,将当前最小值与未排序部分的第一个元素交换位置
    return lst  

def bucket_sort(lst):
    maxVal, minVal = max(lst), min(lst)
    bucketSize = 3 #自定义的值
    
    # 1)计算桶的数量=(待排序列表中的最大值和最小值 的差)// 桶的个数
    bucketCount = (maxVal - minVal) // bucketSize + 1
    # 2)创建桶
    buckets = [[] for i in range(bucketCount)] #[[]*bucketCount]:这些空列表是同一个对象的多个引用。修改其中一个空列表会影响到所有引用了这个空列表的地方
    # 3)将元素放入对应的桶中
    for num in lst:
        buckets[(num - minVal) // bucketSize].append(num)
    
    # 4)对每个桶中的元素进行排序(这里使用了选择排序)
    for bucket in buckets:
        selection_sort(bucket)
        
    # 5)将排序后的元素放回原列表
    lst.clear()# 清空原列表
    for bucket in buckets:
        lst.extend(bucket)
    return lst

计数排序 Counting Sort -o(n+k),o(k),k 是列表中最大值

计数排序的思想是通过统计每个元素出现的次数,然后根据元素的大小顺序将其放回原列表。它适用于待排序列表中元素的范围较小且已知的情况。计数排序的时间复杂度为O(n+k),其中n为待排序列表的长度,k为元素的范围。计数排序是一种稳定的排序算法,因为相同元素的相对顺序不会改变。

为什么计数排序适用于范围较小且已知的数据?

  • 计数排序需要创建一个计数数组,其大小等于待排序数据的范围。如果数据范围太大,计数数组会占用大量空间,因此计数排序适用于范围较小且已知的数据。

算法的步骤如下:

Counting Sort 算法步骤总结:

1.创建计数数组:

2.计算最大元素值 max(lst) 并创建一个长度为 max(lst) + 1 的计数数组 cnt,所有初始值为 0。

3.填充计数数组:

4.遍历待排序列表 lst,将每个元素的计数增加,即 cnt[val] += 1,记录每个元素出现的频率。

5.按顺序填充原数组:

6.遍历计数数组 cnt,根据每个值的计数,将元素按顺序放回原数组 lst,直到计数为 0。

结果:排序后的列表 lst 将按非递减顺序排列。

def counting_sort(lst):
    n = len(lst)
    cntlen = max(lst) + 1  # 1)根据最大元素值创建 计数数组
    cnt = [0] * cntlen

    # 2)遍历待排序列表,将每个元素放入对应的计数位置中
    for val in lst:
        cnt[val] += 1

    # 3)从计数数组中依次取出元素,按照顺序放回结果数组(即原数组)
    i = 0
    for val in range(cntlen):
        while cnt[val] > 0:
            lst[i] = val
            cnt[val] -= 1
            i += 1
    return lst

基数排序 radix sort-o(nd),o(k),d为最大元素的最大位数,k为桶大小

动画展示:<img src"https://gitee.com/cjq1311485460/brush-question-notes/raw/master/9a3483c2b6dec0045db27fcccb7db4dd.gif" alt=“在这里插入图片描述” style=“zoom:50%;” />

基数排序是一种非比较排序算法,它根据数字的每个位上的值进行排序。

为什么基数排序适合对数字进行排序?

  • 基数排序通过逐位排序(从最低位到最高位或从最高位到最低位)来处理每个数字的每一位,这使得基数排序特别适合对数字进行排序,尤其是位数较多但每位数的范围较小的情况。

基数排序的过程:

1.确定最大值:找出列表中的最大值以确定排序的位数。
2.按位排序:

3.从个位开始,逐位向左处理每个数字。
4.使用桶对当前位的数字进行分组。
5.按桶的顺序将元素重新组合回原列表。

6.重复:对每一位重复上述过程,直到处理完所有位数。

def radix_sort(lst):
    base = 1  # 初始化基数为1,表示当前处理个位数字
    maxv = max(lst)  # 获取列表中的最大值

    while base <= maxv:  # 处理所有位数,直到最大值的位数
        buckets = [[] for idx in range(10)]  # 创建10个桶,用于存储每一位上的数字(0到9)

        for num in lst:  # 遍历列表中的每个数字
            idx = (num // base) % 10  # 计算当前数字的位数上的值
            buckets[idx].append(num)  # 将数字放入相应的桶中

        l = 0  # 重新填充列表的索引
        for idx in range(10):  # 遍历所有桶
            for val in buckets[idx]:  # 遍历每个桶中的元素
                lst[l] = val  # 将桶中的元素放回列表
                l += 1  # 移动到列表中的下一个位置
        base *= 10  # 将基数乘以10,处理下一个位数
        
    return lst  # 返回排序后的列表

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

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

相关文章

金士顿NV2 2TB假固态硬盘抢救记,RL6577/RTS5765DL量产工具,RTS5765DL+B47R扩容开卡修复

之前因为很长时间不买固态硬盘&#xff0c;没注意到NVME的固态盘也有了假货和扩容盘&#xff0c;花200多块买了个2TB的金士顿NV2固态硬盘&#xff0c;我原本以为NV1的假货最多是用黑片冒充正片&#xff0c;结果没想到NV2居然有扩容的。后来发现是扩容盘的时候&#xff0c;已经过…

亿发进销存一体化解决方案:数据互联互通,优化企业全局管理-下

亿发软件凭借对产品、市场、业务的深入理解&#xff0c;在进销存基础上进行了延伸&#xff0c;推出多终端、一体化的“进销存管理系统”多元产品矩阵。在技术上实现电脑端、手机端、PDA端、零售端、商家版以及小程序商城的多终端无缝对接&#xff0c;保障企业业务的连贯性和效率…

Win10安装.net FrameWork3.5失败解决方法

win10安装.net FrameWork3.5失败解决方法 已经好久没有来投稿了,实在最近业务缠身,忙的焦头烂额(呵~多么伟大的牛马) 但最近开发使用windows11实在是拉胯的不行,升级完就后悔,所以就一怒之下,重装了win10 可是,好家伙,我重装完遇到一个问题,就是在使用.Net Framework3.5,按照Mi…

Zynq7020 SDK 初学篇(4)- PL 端 GPIO

1.开发背景 基于 PS 端 GPIO 的基础上&#xff0c;如何调用 PL 端 GPIO 的输入输出 2.开发需求 PL 端按键控制 PL 端 LED 3.开发环境 Zynq7020 Vivado2017.4 4.实现步骤 4.1 设计配置 这里设置 PIO 数量 3 个 由于 PL 端不像 PS 端一样绑定 GPIO&#xff0c;所以需要对上面…

C++:拷贝构造函数、赋值运算符重载

目录 一、拷贝构造函数 拷贝构造的特点 二、赋值运算符重载 2.1 运算符重载 2.2 赋值运算符重载 赋值运算符重载的特点 一、拷贝构造函数 如果一个构造函数的第一个参数是自身类类型的引用&#xff0c;且任何额外的参数都有默认值&#xff0c;则此构造函数也叫做拷贝构造…

【Python篇】matplotlib超详细教程-由入门到精通(上篇)

文章目录 第一部分&#xff1a;基础概念与简单绘图1.1 matplotlib 简介1.2 创建第一个折线图1.3 图表的基本组成元素 第二部分&#xff1a;图表样式与修饰2.1 修改图表样式2.2 添加图例2.3 调整坐标轴与刻度 第三部分&#xff1a;绘制不同类型的图表3.1 散点图 (Scatter Plot)3…

JVM 调优篇2 jvm的内存结构以及堆栈参数设置与查看

一 jvm的内存模型 2.1 jvm内存模型概览 二 实操案例 2.1 设置和查看栈大小 1.代码 /*** 演示栈中的异常:StackOverflowError** author shkstart* create 2020 下午 9:08** 设置栈的大小&#xff1a; -Xss (-XX:ThreadStackSize)** -XX:PrintFlagsFinal*/ public class S…

关于ansible自动化运维工具

成长路上不孤单&#x1f60a;【14后&#xff0c;C爱好者&#xff0c;持续分享所学&#xff0c;如有需要欢迎收藏转发&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#xff01;&#xff01;&#xff01;&#xff01;&#xff…

Android SystemUI组件(05)状态栏-系统状态图标显示管理

该系列文章总纲链接&#xff1a;专题分纲目录 Android SystemUI组件 本章关键点总结 & 说明&#xff1a; 说明&#xff1a;本章节持续迭代之前章节的思维导图&#xff0c;主要关注下方 SystemBars分析中状态栏中的部分-系统状态图标显示&管理 即可。 1 系统状态图标显…

Error when attempting to add data source to Azure OpenAI api

题意&#xff1a;尝试向 Azure OpenAI API 添加数据源时出现错误 问题背景&#xff1a; My code is working for a call to Azure OpenAI when I dont have a datasource added. However, when I do add my datasource with the following parameters I get an error: 当我没…

Dubbo精要

1、为什么需要 Dubbo&#xff1f; 分布式系统中的服务调用和协调问题&#xff1a;在分布式系统中&#xff0c;服务之间的相互依赖会导致复杂的通信和协调问题。Dubbo提供了高效的服务调用和自动注册、发现等功能&#xff0c;使得构建分布式应用程序更加容易。服务治理和服务调…

LeetCode 热题 100 回顾5

干货分享&#xff0c;感谢您的阅读&#xff01;原文见&#xff1a;LeetCode 热题 100 回顾_力code热题100-CSDN博客 一、哈希部分 1.两数之和 &#xff08;简单&#xff09; 题目描述 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标…

CentOS Stream 8中安装和使用 Docker

docker安装包-CSDN博客 〇、常用的docker命令 docker的作用&#xff1a; 快速进行软件的安装&#xff0c;便于软件环境的维护 docker的镜像: 压缩了指定软件的安装包的文件。使用镜像文件创建容器 docker的容器: 容器可以理解为就是一台小电脑。安装的linux系统&am…

C++入门基础篇

引言 说到编程语言常常听到的就是C语言C Java 。C语言是面向过程的&#xff0c;C是和Java是面向对象的&#xff0c;那么什么是面向对象呢&#xff1f;什么又是面向过程呢&#xff1f;C是什么&#xff1f;封装、继承、多态是什么&#xff1f;且听我絮絮叨叨。 C入门基础 1.命名…

SpringBoot OAuth2自定义登陆/授权页

背景 5 月份的时候&#xff0c;我实践并整理了一篇博客&#xff1a;SpringBoot搭建OAuth2&#xff0c;该博客完成之后&#xff0c;很长一段时间里我都有种意犹未尽的感觉。诚然&#xff0c;我把OAuth2搭起来了&#xff0c;各种场景的用例也跑通了&#xff0c;甚至源码也看了&am…

《花100块做个摸鱼小网站! 》第六篇—将小网站部署到云服务器上

⭐️基础链接导航⭐️ 服务器 → ☁️ 阿里云活动地址 看样例 → &#x1f41f; 摸鱼小网站地址 学代码 → &#x1f4bb; 源码库地址 一、前言 到这一篇我们终于把环境搭好&#xff0c;也做好了几个热搜小组件&#xff0c;为了让我们方便展示成果或者方便自己摸鱼&#xff0c…

2024最新!Facebook手机版和网页版改名教程!

Facebook作为全球最大的社交平台之一&#xff0c;允许用户自定义名字和昵称。在Facebook更新姓名可以帮助您更好的展现账号形象。本文将为您提供详细的步骤指导&#xff0c;帮助您在手机APP和网页版上轻松完成Facebook改名操作。 Facebook手机版改名 打开Facebook APP并登录账号…

DataGridView用法合集【精品】

目录 1.当前的单元格属性取得、变更 2.DataGridView编辑属性 3.DataGridView最下面一列新追加行非表示 4.判断当前选中行是否为新追加的行 5. DataGridView删除行可否设定 6. DataGridView行列不表示和删除 7. DataGridView行列宽度高度设置为不能编辑 8. DataGridView行…

SQL进阶技巧:如何利用SQL解决趣味赛马问题?| 非等值关联匹配问题

目录 0 问题描述 1 数据准备 2 问题分析 方法一:先分后合思想 方法2:非等值关联匹配 3 小结 0 问题描述 有一张赛马记录表,如下所示: create table RacingResults ( trace_id char(3) not null,race_date date not null, race_nbr int not null,win_name char(30) n…

【北京迅为】《STM32MP157开发板使用手册》-第十四章 QtE5.12应用开发

iTOP-STM32MP157开发板采用ST推出的双核cortex-A7单核cortex-M4异构处理器&#xff0c;既可用Linux、又可以用于STM32单片机开发。开发板采用核心板底板结构&#xff0c;主频650M、1G内存、8G存储&#xff0c;核心板采用工业级板对板连接器&#xff0c;高可靠&#xff0c;牢固耐…