排序算法(2)之选择排序----直接选择排序和堆排序

 个人主页:C++忠实粉丝
欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C++忠实粉丝 原创

排序算法(2)之交换排序----冒泡排序和堆排序

收录于专栏【数据结构初阶
本专栏旨在分享学习数据结构学习的一点学习笔记,欢迎大家在评论区交流讨论💌

目录

1.前置说明 

2.选择排序

2.1选择排序的基本思想

2.2直接选择排序

2.2.1直接选择排序的概念

2.2.2直接选择排序的示例

2.2.3动图演示

2.2.4代码展示 

2.2.4.1未经优化的选择排序

2.2.4.2优化后的选择排序

2.2.5测试代码 

2.2.5.1未经优化

2.2.5.2经过优化

2.2.6时间复杂度分析

2.3堆排序

2.3.1堆排序的概念

2.3.2 堆排序示例

2.3.3堆排序图形演示

2.3.4代码展示

2.3.4.1向下调整建堆

2.3.4.2向上调整建堆

2.3.5测试代码

2.3.6时间复杂度分析

2. 排序过程的时间复杂度

3.直接选择排序与堆排序的比较

总结比较

4.总结


1.前置说明 

关于排序的概念及其运用大家可以参考下面的文章,这里就不重复讲述:

今天讲的是选择排序中的直接选择排序和堆排序

排序算法(1)之插入排序----直接插入排序和希尔排序-CSDN博客

 

2.选择排序

2.1选择排序的基本思想

每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的 数据元素排完 。

2.2直接选择排序

2.2.1直接选择排序的概念

直接选择排序(Selection Sort)是一种简单直观的排序算法,其基本思想是每次从待排序的数据元素中选择最小(或最大)的一个元素,依次放到已排序序列的末尾,直到所有元素均排序完成为止。

具体步骤如下:

  • 首先,在未排序序列中找到最小(或最大)的元素,存放到排序序列的起始位置。
  • 然后,从剩余未排序元素中继续寻找最小(或最大)的元素,放到已排序序列的末尾。
  • 依次类推,直到所有元素均排序完毕。 

2.2.2直接选择排序的示例

假设我们有一个数组 [64, 25, 12, 22, 11] 需要按照从小到大的顺序进行排序。

第一步: 初始状态,整个数组为 [64, 25, 12, 22, 11]

  1. 第一次迭代

    • 找到当前未排序部分的最小值,即数组中的 11
    • 将 11 与第一个元素 64 交换位置,得到数组 [11, 25, 12, 22, 64]
    • 此时,第一个位置 [11] 可以看作已排序部分,而剩余的未排序部分为 [25, 12, 22, 64]
  2. 第二次迭代

    • 在剩余的数组 [25, 12, 22, 64] 中找到最小值 12
    • 将 12 与第二个位置的 25 交换位置,得到数组 [11, 12, 25, 22, 64]
    • 现在,前两个位置 [11, 12] 已排序,剩余的未排序部分为 [25, 22, 64]
  3. 第三次迭代

    • 在剩余的数组 [25, 22, 64] 中找到最小值 22
    • 将 22 与第三个位置的 25 交换位置,得到数组 [11, 12, 22, 25, 64]
    • 现在,前三个位置 [11, 12, 22] 已排序,剩余的未排序部分为 [25, 64]
  4. 第四次迭代

    • 在剩余的数组 [25, 64] 中找到最小值 25
    • 将 25 与第四个位置的 25(其实是自身,无需交换)位置,得到数组 [11, 12, 22, 25, 64]
    • 现在,整个数组都已排序完成。

排序过程总结为:

  • 第一次迭代找到 11,交换得到 [11, 25, 12, 22, 64]
  • 第二次迭代找到 12,交换得到 [11, 12, 25, 22, 64]
  • 第三次迭代找到 22,交换得到 [11, 12, 22, 25, 64]
  • 第四次迭代找到 25,无需交换,数组最终有序。

这样,通过反复选择未排序部分的最小元素,并与未排序部分的第一个元素交换位置,直到整个数组排序完成,即完成了直接选择排序的过程。

2.2.3动图演示

2.2.4代码展示 

2.2.4.1未经优化的选择排序
void Swap(int* p1, int* p2)
{int a = *p1;*p1 = *p2;*p2 = a;
}
void SelectSort1(int* a, int n)
{for (int i = 0; i < n; i++){int mini = i;for (int j = i; j < n; j++){if (a[mini] > a[j])mini = j;}Swap(&a[i], &a[mini]);}
}
2.2.4.2优化后的选择排序
void Swap(int* p1, int* p2)
{int a = *p1;*p1 = *p2;*p2 = a;
}
void SelectSort2(int* a, int n)
{int begin = 0, end = n - 1;while (begin < end){int mini = begin, maxi = begin;for (int i = begin + 1; i <= end; ++i){if (a[i] > a[maxi]){maxi = i;}if (a[i] < a[mini]){mini = i;}}Swap(&a[begin], &a[mini]);if (begin == maxi)maxi = mini;Swap(&a[end], &a[maxi]);++begin;--end;}
}

分析: 

  1. 函数定义

    void SelectSort2(int* a, int n)
    • 函数名为 SelectSort2,返回类型为 void,表示不返回任何值。
    • 函数接受两个参数:a 是指向整型数组的指针,n 是数组中元素的个数。
  2. 选择排序的变种实现

    • 首先定义了两个变量 begin 和 end,分别初始化为数组的起始索引 0 和末尾索引 n-1
    • 进入 while 循环,条件是 begin < end,即未排序部分至少有两个元素。
  3. 内部循环

    • 在每次循环开始时,初始化 mini 和 maxi 分别为 begin,意味着假定当前未排序部分的第一个元素为最小和最大。
    • 通过 for 循环遍历 begin+1 到 end 之间的元素:
      • 如果发现比当前 maxi 索引指向的元素大的元素,则更新 maxi
      • 如果发现比当前 mini 索引指向的元素小的元素,则更新 mini
  4. 交换操作

    • 在每一轮循环结束后,通过 Swap 函数交换 begin 索引和 mini 索引所指向的元素,确保当前未排序部分的最小元素被放置在已排序部分的末尾。
    • 如果 begin 等于 maxi,则在交换后需要更新 maxi 为 mini 的值。
    • 接着,再次通过 Swap 函数交换 end 索引和 maxi 索引所指向的元素,确保当前未排序部分的最大元素被放置在已排序部分的开头。
  5. 循环控制

    • 每完成一轮循环,即一个元素被正确地放置在已排序的位置上,递增 begin 并递减 end,缩小未排序部分的范围,直至 begin 不再小于 end,排序完成。
  6. 功能分析

    • 这种选择排序的变种在每一轮循环中同时找到未排序部分的最小值和最大值,并将它们分别放置在已排序部分的开头和末尾。
    • 效果上比传统的选择排序稍微快一些,因为减少了每轮循环中的交换次数,但其时间复杂度仍为 O(n^2),并未改变选择排序的基本特性。

注意: 

        Swap(&a[begin], &a[mini]);
        if (begin == maxi)
            maxi = mini;

这段代码是为了防止在第一次交换后,maxi和mini已经进行过交换,将它们回复原位

2.2.5测试代码 

--测试oj链接--912. 排序数组 - 力扣(LeetCode)

2.2.5.1未经优化

代码展示:

void Swap(int* p1, int* p2)
{int a = *p1;*p1 = *p2;*p2 = a;
}void SelectSort1(int* a, int n)
{for (int i = 0; i < n; i++){int mini = i;for (int j = i; j < n; j++){if (a[mini] > a[j])mini = j;}Swap(&a[i], &a[mini]);}
}
int* sortArray(int* nums, int numsSize, int* returnSize) {(*returnSize) = numsSize;int* array = (int*)malloc(sizeof(int)*(*returnSize));for(int i = 0; i < numsSize; i++){array[i] = nums[i];}SelectSort1(array, numsSize);return array;
}

结果分析: 

很遗憾,只过了10个例子就超时,比插入排序还要烂......

2.2.5.2经过优化

代码展示:

void Swap(int* p1, int* p2)
{int a = *p1;*p1 = *p2;*p2 = a;
}void SelectSort2(int* a, int n)
{int begin = 0, end = n-1;while(begin < end){int mini = begin, maxi = begin;for(int i = begin + 1; i <= end; i++){if(a[i] < a[mini])mini = i;if(a[i] > a[maxi])maxi = i; }Swap(&a[begin], &a[mini]);if(begin == maxi)maxi = mini;Swap(&a[end], &a[maxi]);++begin;--end;}
}
int* sortArray(int* nums, int numsSize, int* returnSize) {(*returnSize) = numsSize;int* array = (int*)malloc(sizeof(int)*(*returnSize));for(int i = 0; i < numsSize; i++){array[i] = nums[i];}SelectSort2(array, numsSize);return array;
}

结果分析:

优化后还是只能通过10个例子,效率还是很低....

2.2.6时间复杂度分析

  • 时间复杂度为 (O(n^2)),其中 (n) 是待排序元素的数量。
  • 空间复杂度为 (O(1)),因为直接选择排序是原地排序算法,不需要额外的存储空间。
  • 稳定性:直接选择排序是不稳定的,因为交换操作可能改变相同元素的相对顺序。

2.3堆排序

因为这里是具体讲排序的章节,所以不会具体分析堆的实现,大家可以去下面的链接自行查看

--数据结构之二叉树的超详细讲解(2)--(堆的概念和结构的实现,堆排序和堆排序的应用)-CSDN博客

2.3.1堆排序的概念

堆排序(Heap Sort)是一种基于堆数据结构的排序算法,其特点是在排序过程中使用了最大堆或最小堆这种特殊的完全二叉树结构。堆是一种满足堆属性的二叉树:对于最大堆,父节点的值始终大于或等于其子节点的值;对于最小堆,则父节点的值始终小于或等于其子节点的值。

堆排序的步骤:

  1. 构建堆

    • 将待排序的序列构建成一个堆。根据排序的要求,可以构建最大堆(升序排序使用)或最小堆(降序排序使用)。
    • 构建堆的过程可以通过自下而上的方式,从最后一个非叶子节点开始,依次向上调整每个子树,使其满足堆的性质。调整过程称为堆化(Heapify)。
  2. 堆排序

    • 利用堆的特性,每次从堆顶(根节点)取出最大或最小的元素,与堆的最后一个元素交换。
    • 交换后,堆的规模减小一,然后再通过堆调整(Heapify)重新将剩余的元素重新调整为堆。
    • 重复以上步骤,直到堆中只剩下一个元素,此时所有元素都已经有序排列。 

2.3.2 堆排序示例

当我们使用堆排序时,可以通过一个简单的例子来说明其工作原理。假设我们有一个待排序的数组 [4, 10, 3, 5, 1],我们希望按升序排序这个数组。

步骤一:构建最大堆

  1. 初始数组[4, 10, 3, 5, 1]

  2. 从最后一个非叶子节点开始进行堆化

    • 最后一个非叶子节点索引是 (n // 2) - 1 = (5 // 2) - 1 = 1,对应元素为 10
    • 开始堆化过程,使得整个数组满足最大堆的性质。

    堆化后的数组:[10, 5, 3, 4, 1]

  3. 继续堆化

    • 对于根节点 10,将其与子节点 3 和 4 进行比较和交换,确保最大堆性质。
    • 堆化后的数组:[10, 5, 3, 4, 1]

步骤二:堆排序

  1. 交换堆顶元素与末尾元素

    • 将堆顶元素 10 与末尾元素 1 交换,此时数组末尾是已排序部分。
    • 数组变为:[1, 5, 3, 4, 10]
  2. 重新堆化

    • 对剩余的元素 [1, 5, 3, 4] 进行堆化,重新构建最大堆。

    堆化后的数组:[5, 4, 3, 1]

  3. 继续排序

    • 将堆顶元素 5 与末尾元素 1 交换,数组末尾再添加一个已排序元素。
    • 数组变为:[1, 4, 3, 5]
  4. 最后一步

    • 将堆顶元素 4 与末尾元素 3 交换。
    • 数组变为:[1, 3, 4, 5]

完成排序

最终排序后的数组为 [1, 3, 4, 5, 10],这就是堆排序按升序排列给定的数组的过程。

2.3.3堆排序图形演示

向上调整建堆

向下调整建堆

2.3.4代码展示

2.3.4.1向下调整建堆
void Swap(int* p1, int* p2)
{int a = *p1;*p1 = *p2;*p2 = a;
}void AdjustDown(int* a, int n, int parent)
{// 先假设左孩子小int child = parent * 2 + 1;while (child < n)  // child >= n说明孩子不存在,调整到叶子了{// 找出小的那个孩子if (child + 1 < n && a[child + 1] > a[child]){++child;}if (a[child] > a[parent]){Swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}void HeapSort(int* a, int n)
{// 向下调整建堆 O(N)for (int i = (n - 1 - 1) / 2; i >= 0; i--){AdjustDown(a, n, i);}// O(N*logN)int end = n - 1;while (end > 0){Swap(&a[0], &a[end]);AdjustDown(a, end, 0);--end;}
}

分析:

  1. Swap 函数:

    • 实现了两个整数指针指向的值的交换。
  2. AdjustDown 函数:

    • 用于向下调整堆结构,保持堆的性质(大顶堆),其中 a 是待调整的数组,n 是数组长度,parent 是需要调整的父节点索引。
    • 该函数首先假设左孩子较小,然后找出实际较大的孩子,将较大的孩子与父节点比较并交换,然后递归调整被交换的孩子节点。
  3. HeapSort 函数:

    • 先通过向下调整(AdjustDown 函数)建立初始的大顶堆。从最后一个非叶子节点开始,依次向上调整堆,确保每个节点都满足堆的性质。
    • 排序阶段,从堆顶(最大值)开始,将堆顶元素与当前未排序部分的末尾元素交换,然后重新调整堆顶,继续这个过程直到所有元素都被排序。

 

2.3.4.2向上调整建堆

代码展示:

void Swap(int* p1, int* p2)
{int a = *p1;*p1 = *p2;*p2 = a;
}void AdjustUp(int* a, int n, int child)
{// 初始条件// 中间过程// 结束条件int parent = (child - 1) / 2;//while (parent >= 0)while (child > 0){if (a[child] > a[parent]){Swap(&a[child], &a[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}
}void AdjustDown(int* a, int n, int parent)
{// 先假设左孩子小int child = parent * 2 + 1;while (child < n)  // child >= n说明孩子不存在,调整到叶子了{// 找出小的那个孩子if (child + 1 < n && a[child + 1] > a[child]){++child;}if (a[child] > a[parent]){Swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}void HeapSort2(int* a, int n)
{// 向下上调整建堆 O(N*logN)for (int i = 0; i < n; i++){AdjustUp(a, n, i);}printf("\n");// O(N*logN)int end = n - 1;while (end > 0){Swap(&a[0], &a[end]);AdjustDown(a, end, 0);--end;}}

分析:

  1. Swap 函数

    • 这个函数用于交换两个整数指针所指向的值,用于数组元素的位置交换。
  2. AdjustUp 函数

    • 这个函数用于向上调整堆结构,确保在数组的某个位置(child)插入新元素后,仍然保持堆的性质(大顶堆)。
    • 从给定的孩子节点开始,不断与其父节点比较并交换,直到满足堆的条件或者已经到达根节点。
  3. AdjustDown 函数

    • 这个函数用于向下调整堆结构,确保在删除堆顶元素后,剩余的数组依然是一个大顶堆。
    • 从指定的父节点开始,找出其两个孩子中较大的一个,然后与父节点比较并交换,重复这个过程直到满足堆的性质或者到达叶子节点。
  4. HeapSort2 函数

    • 这是堆排序的主函数。首先通过调用 AdjustUp 函数,将整个数组构建成一个大顶堆。
    • 然后,通过交换堆顶元素和当前堆的末尾元素,并调用 AdjustDown 函数来恢复堆的性质。重复这个过程直到整个数组排序完成。

2.3.5测试代码

oj链接:912. 排序数组 - 力扣(LeetCode)

代码展示:

void Swap(int* p1, int* p2)
{int a = *p1;*p1 = *p2;*p2 = a;
}void AdjustUp(int* a, int n, int child)
{// 初始条件// 中间过程// 结束条件int parent = (child - 1) / 2;//while (parent >= 0)while (child > 0){if (a[child] > a[parent]){Swap(&a[child], &a[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}
}void AdjustDown(int* a, int n, int parent)
{// 先假设左孩子小int child = parent * 2 + 1;while (child < n)  // child >= n说明孩子不存在,调整到叶子了{// 找出小的那个孩子if (child + 1 < n && a[child + 1] > a[child]){++child;}if (a[child] > a[parent]){Swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}void HeapSort1(int* a, int n)
{// 向下调整建堆 O(N)for (int i = (n - 1 - 1) / 2; i >= 0; i--){AdjustDown(a, n, i);}// O(N*logN)int end = n - 1;while (end > 0){Swap(&a[0], &a[end]);AdjustDown(a, end, 0);--end;}
}void HeapSort2(int* a, int n)
{// 向下上调整建堆 O(N*logN)for (int i = 0; i < n; i++){AdjustUp(a, n, i);}// O(N*logN)int end = n - 1;while (end > 0){Swap(&a[0], &a[end]);AdjustDown(a, end, 0);--end;}}
int* sortArray(int* nums, int numsSize, int* returnSize) {(*returnSize) = numsSize;int* array = (int*)malloc(sizeof(int)*(*returnSize));for(int i = 0; i < numsSize; i++){array[i] = nums[i];}HeapSort2(array, numsSize);return array;
}

结果分析: 

 

 可以看出无论是向上建堆还是向下建堆,堆排序都能够轻松通过

注意:
这里建议大家还是使用向下建堆实现堆排序,因为实现的时候只需要实现一个向下调整的算法,而且调整算法的时间复杂度为O(n),可谓是又方便,又高效.

2.3.6时间复杂度分析

堆排序的时间复杂度分析主要分为两个部分:建堆过程的时间复杂度和排序过程的时间复杂度。

1. 建堆过程的时间复杂度
--具体可以看这篇博客
数据结构之二叉树的超详细讲解(2)--(堆的概念和结构的实现,堆排序和堆排序的应用)-CSDN博客

建堆的过程是将一个无序的数组构建成一个堆,通常是最大堆或最小堆。建堆的时间复杂度为 O(n)

  • 建堆的详细步骤
    • 从最后一个非叶子节点开始,依次向前进行堆化操作,保证每个子树都满足堆的性质。
    • 最后一个非叶子节点的索引为 (n // 2) - 1,其中 n 是数组的长度。
    • 每次堆化的时间复杂度是 O(log n),因为堆的高度是 O(log n)

2. 排序过程的时间复杂度

排序过程主要包括将堆顶元素与末尾元素交换并重新调整堆的过程。排序过程的时间复杂度为 O(n log n)

  • 排序的详细步骤
    • 将堆顶元素与当前堆的最后一个元素交换,然后从根节点开始重新调整堆,使其重新满足堆的性质。
    • 每次重新调整堆的时间复杂度是 O(log n)
    • 总共需要进行 n-1 次交换和堆调整操作。

总结堆排序的时间复杂度:

  • 建堆时间复杂度:O(n)
  • 排序时间复杂度:O(n log n)

综合起来,堆排序的总时间复杂度是 O(n log n)。这使得堆排序在时间复杂度上表现出色,适合于大规模数据的排序操作。

3.直接选择排序与堆排序的比较

直接选择排序(Selection Sort)和堆排序(Heap Sort)都属于比较排序的算法,但它们在实现和性能上有显著的差异。

直接选择排序(Selection Sort)

  1. 基本原理

    • 直接选择排序通过每次从未排序的部分选出最小(或最大)的元素,然后放到已排序部分的末尾。
    • 每次选择过程都需要线性扫描未排序部分,找出最小元素,然后与当前位置交换。
  2. 时间复杂度

    • 最好情况、平均情况和最坏情况下的时间复杂度都是 O(n^2)
    • 每次选择都需要线性时间,总共进行了 n 次选择,每次选择需要线性时间。
  3. 空间复杂度

    • 额外空间复杂度是 O(1),因为只需要常数级别的额外空间用于交换元素。
  4. 稳定性

    • 直接选择排序是一种不稳定的排序算法,因为在选择的过程中可能破坏相同元素的相对顺序。

堆排序(Heap Sort)

  1. 基本原理

    • 堆排序利用堆的数据结构来实现排序。
    • 先构建一个最大堆(或最小堆),然后将堆顶元素(最大值或最小值)与堆的最后一个元素交换,并调整堆,使其满足堆的性质,重复这个过程直到整个数组排序完成。
  2. 时间复杂度:(向下调整建堆)

    • 建堆的时间复杂度是 O(n)
    • 每次调整堆的时间复杂度是 O(log n)
    • 总的时间复杂度是 O(n log n),堆排序是一种稳定的时间复杂度为 O(n log n) 的排序算法。
  3. 空间复杂度

    • 堆排序的空间复杂度是 O(1),因为所有操作都在原数组上进行,没有额外使用的空间。
  4. 稳定性

    • 堆排序在交换堆顶元素时可能破坏相同元素的相对顺序,因此是一种不稳定的排序算法。

总结比较

  • 性能:堆排序在大多数情况下比直接选择排序要快,特别是在处理大规模数据时,由于堆排序的时间复杂度为 O(n log n),比直接选择排序的 O(n^2) 要好。
  • 稳定性:直接选择排序可能比堆排序更容易实现为稳定排序,但通常它们都是不稳定的排序算法。
  • 实现复杂度:堆排序需要实现堆的构建和堆的调整过程,相对而言实现起来比直接选择排序稍微复杂一些,但在实际应用中通常都是可以接受的复杂度。

4.总结

直接选择排序的性能非常差,因为他每次遍历都需要完整遍历完整个数组,现实生活中基本不用,但堆排序时间复杂度能达到n*logn,特别是在top-k问题中,堆排序更是能到达O(n)的级别.

如果这篇文章对大家有帮助的话,麻烦点赞关注支持一下

我将会马上更新排序算法(3)之交换排序----冒泡排序和快速排序,记得点赞关注不迷路哦!

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

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

相关文章

51Sim核心参编!《中国智能网联汽车自动驾驶仿真测试白皮书》发布(附资源)

近日&#xff0c;《中国智能网联汽车自动驾驶仿真测试白皮书&#xff08;2023版&#xff09;》&#xff08;以下简称白皮书&#xff09;正式发布。 该白皮书由国汽&#xff08;北京&#xff09;智能网联汽车研究院有限公司、吉林大学、51Sim、中国第一汽车集团有限公司研发总院…

初阶 《操作符详解》11. 下标引用、函数调用和结构成员

11. 下标引用、函数调用和结构成员 1. [ ] 下标引用操作符 操作数&#xff1a;一个数组名 一个索引值 int arr[10];//创建数组 arr[9] 10;//实用下标引用操作符&#xff0c;[ ]的两个操作数是arr和9arr[7]-->*(arr7)-->*(7arr)-->7[arr] 7[arr] 9; //编译器不会…

postman忘记密码发邮件,久久收不到怎么办?

根本原因是需要FQ&#xff01;&#xff01;&#xff01; 重置密码的链接&#xff1a; https://identity.getpostman.com/trouble-signing-in 找个平台或者软件&#xff0c;访问这个链接即可完成修改密码后续操作&#xff0c;不用再傻傻等着验证码了。 有需要协助的朋友也可私信…

【Nginx】静态资源访问配置

nginx 静态资源访问配置 Nginx 静态资源访问配置 通过该片文章&#xff0c;你能了解图中的内容&#xff1a; 实际问题 Nginx 应该怎么写&#xff0c;才能匹配这个图片资源路径&#xff1f; http://47.120.10.110:7001/public/images/picture.jpg解决方案 你需要配置一个 N…

植物大战僵尸杂交版v2.1最新整合版,附PC端+安卓端+iOS端安装包+修改器+安装教程!

嘿&#xff0c;大家好&#xff0c;我是阿星&#xff0c;今天要跟大家聊聊一款游戏&#xff0c;它不是那种让人眼花缭乱的大制作&#xff0c;也不是那种能让人回味无穷的艺术作品&#xff0c;但它在阿星心里&#xff0c;绝对是神作中的佼佼者。没错&#xff0c;它就是《植物大战…

经验分享,免费商标查询网站

有时候想快速查询商标状况&#xff0c;官方网站比较慢&#xff0c;这里分享一个免费快速的网站。 网址&#xff1a;https://www.sscha.com/ 截图&#xff1a;

深度之眼(二十六)——神经网络基础知识(一)

文章目录 一、前言二、神经网络与多层感知机2.1 人工神经元2.2 人工神经网络2.3 多层感知机2.4 激活函数 一、前言 看了下课程安排&#xff0c;自己还是没安排好&#xff0c;刚刚捋清了一下思路。 基础&#xff1a;python、数理 认识&#xff1a;神经网络基础、opencv基础、py…

sys.stdout.write()方法——标准输出打印

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 语法参考 Sys.Stdout是sys模块中的标准输出对象&#xff0c;可以实现将数据向屏幕、文件等进行输出。Sys.Stdout通过write 方法实现数据的标准输出。…

RK3588 Android13 TvSetting 中性能浮窗RAM显示bug

前言 电视产品,客户发现在设备偏好设置->高级设置->性能浮窗菜单里显示的 RAM 大小是错误的, 要求改成正确的,并且屏幕密度修改后,这个浮窗显示不全,也需要一起处理。 效果图 TvSetting 部分修改文件清单 bug 原因在于 Formatter.formatFileSize 这个 API,我们…

华为---VRRP基本配置(一)

10、VRRP 10.1 VRRP基本配置 10.1.1 原理概述 随着Internet的发展&#xff0c;人们对网络可靠性的要求越来越高。对于用户来说&#xff0c;能够时刻与外部网络保持通信非常重要&#xff0c;但内部网络中的所有主机通常只能设置一个网关IP地址&#xff0c;通过该出口网关实现…

CVE-2020-26048(文件上传+SQL注入)

简介 CuppaCMS是一套内容管理系统&#xff08;CMS&#xff09;。 CuppaCMS 2019-11-12之前版本存在安全漏洞&#xff0c;攻击者可利用该漏洞在图像扩展内上传恶意文件&#xff0c;通过使用文件管理器提供的重命名函数的自定义请求&#xff0c;可以将图像扩展修改为PHP&#xf…

Qt:2.环境搭建

目录 1.搭建需要的三个组件&#xff1a; 2.下载Qt安装包&#xff1a; 3.安装qt&#xff1a; 4.配置环境变量&#xff1a; 1.搭建需要的三个组件&#xff1a; C编译器&#xff08;gcc&#xff0c;cl.exe等&#xff09;Qt的SDK&#xff1a;软件开发工具包&#xff0c;Windows…

玩转AI之四个免费热门的AI工具

2023年&#xff0c;可以说称之为人工智能元年&#xff0c;随着 AI 人工智能、机器学习技术的不断发展&#xff0c;各种 AI 算法的应用也越来越广泛&#xff0c;在AI这一领域中&#xff0c;软件、工具和网站如雨后春笋般涌现。下半年&#xff0c;预计会有更多王炸级别的产品问世…

打破数据分析壁垒:SPSS复习必备(十)

Means过程 统计学上的定义和计算公式 定义&#xff1a;Means过程是SPSS计算各种基本描述统计量的过程&#xff0c;其实就是按照用户指定条件&#xff0c;对样本进行分组计算均数和标准差&#xff0c;如按性别计算各组的均数和标准差。 用户可以指定一个或多个变量作为分组变…

java基于ssm+jsp 社区生活超市管理系统

1前台首页功能模块 社区生活超市管理系统 &#xff0c;在社区生活超市管理系统可以查看首页、商品信息、我的、跳转到后台等内容&#xff0c;如图1所示。 图1系统首页界面图 用户登录、用户注册&#xff0c;通过注册填写用户账号、密码、用户姓名、性别、用户手机、送货地址等…

观测云 VS 开源自建

观测云是一款面向全技术栈的监控观测一体化产品方案&#xff0c;具备强大而丰富的功能&#xff0c;目标是帮助最终用户提升监控观测的能力&#xff0c;化繁为简&#xff0c;轻松的构建起完整的监控观测体系。同时能够帮助整个企业的开发技术团队从统一的观测能力上获得完整的收…

ACL 2023事件相关(事件抽取、事件关系抽取、事件预测等)论文汇总

ACL 2023事件抽取相关(事件抽取、事件关系抽取、事件预测等)论文汇总&#xff0c;后续会更新全部的论文讲解。 Event Extraction Code4Struct: Code Generation for Few-Shot Event Structure Prediction 数据集&#xff1a;ACE 2005 动机&#xff1a;与自然语言相比&#xf…

文件上传漏洞---Pyload

文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 本文重点从靶场案例分析文件上传漏洞常见的Pylod&#xff0c;本文演示靶场upload-labs 一.文件类型---Pyload 不同的文件对应不同的文件类型&#xff0c;后端代码通过限制特定的文件类型…

fastadmin框架修改前端时间戳格式的时区

一、上传文件 将 moment-timezone-with-data.js 和 moment-timezone-with-data.min.js 文件上传到项目的 \public\assets\libs\moment\ 文件夹中。 二、配置中引入文件 在 \public\assets\js\require-backend.js 文件中增加所引入文件的配置: moment-timezone-with-data: …

JS(JavaScript)入门指南(DOM、事件处理、BOM、数据校验)

天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。 玉阶生白露,夜久侵罗袜。 却下水晶帘,玲珑望秋月。 ——《玉阶怨》 文章目录 一、DOM操作1. D…