【排序算法】选择排序、堆排序

文章目录

  • 选择排序
    • 选择排序的概念
    • 选择排序的基本步骤:
    • 选择排序的特点
    • 选择排序的代码实现(C语言)
  • 选择排序-优化
    • 双向选择排序的步骤
    • 堆的基本概念
    • 堆排序详细步骤
    • 堆排序代码讲解

选择排序

选择排序的概念

选择排序是一种简单直观的排序算法。它的工作原理是每次从未排序的部分中选择一个最小(或最大)的元素,并将其与未排序部分的第一个元素进行交换。这个过程重复 n-1 次,直到数组排序完毕。

选择排序的基本步骤:

  1. 未排序的部分中找到最小的元素。
  2. 将这个元素与未排序部分的第一个元素交换
  3. 每次遍历数组,未排序部分就会减少,已排序部分逐渐扩大。
  4. 当所有元素都经过选择排序后,数组就变为有序的。

选择排序的特点

  • 时间复杂度: O(n²),因为对于每个元素,都需要扫描剩下的未排序元素来找到最小值。
  • 空间复杂度: O(1),因为它是原地排序算法,不需要额外的存储空间。
  • 稳定性: 选择排序是不稳定的排序算法。因为元素交换时,可能会改变相同值元素的相对顺序。
  • 虽然很好理解,效率不好,实际中很少使用。

选择排序的代码实现(C语言)

#include <stdio.h>// 选择排序函数
void SelectionSort(int arr[], int n) {// 外层循环,逐渐缩小未排序部分for (int i = 0; i < n - 1; i++) {// 初始化最小值的索引为当前未排序部分的第一个元素int minIndex = i;
//注意i<n-1,因为i之后会比较j=i+1的值
//但j是<n,可以走到最后一个// 内层循环,从 i+1 开始查找未排序部分的最小元素for (int j = i + 1; j < n; j++) {// 如果找到比当前最小值更小的元素,更新最小值索引if (arr[j] < arr[minIndex]) {minIndex = j;}}// 如果最小值的索引不是 i,则交换元素if (minIndex != i) {int temp = arr[i];arr[i] = arr[minIndex];arr[minIndex] = temp;}}
}// 打印数组函数
void PrintArray(int arr[], int n) {for (int i = 0; i < n; i++) {printf("%d ", arr[i]);}printf("\n");
}int main() {// 示例数组int arr[] = {64, 25, 12, 22, 11};int n = sizeof(arr) / sizeof(arr[0]);printf("排序前的数组: ");PrintArray(arr, n);// 执行选择排序SelectionSort(arr, n);printf("排序后的数组: ");PrintArray(arr, n);return 0;
}

输出示例

排序前的数组: 64 25 12 22 11 
排序后的数组: 11 12 22 25 64 

详细讲解

  1. 外层循环 for (int i = 0; i < n - 1; i++):
    • 控制循环次数,每次选择一个最小元素并将其放到正确位置。
    • 循环结束后,前 i 个元素已经排好序。
  2. 初始化最小值索引int minIndex = i;:
    • 在每一轮选择中,将当前未排序部分的第一个元素假设为最小元素。
  3. 内层循环 for (int j = i + 1; j < n; j++):
    • 通过从 i+1 开始的未排序部分中寻找最小值。
    • 如果发现比当前最小值更小的元素,更新 minIndex,标记该元素的索引。
  4. 元素交换 if (minIndex != i):
    • 如果最小值不是当前元素,就交换最小值和未排序部分第一个元素。
    • 交换之后,已排序部分扩大一个元素。
  5. PrintArray()** 函数**:
    • 一个简单的辅助函数,用于打印数组的当前状态。

选择排序的运行步骤举例

假设排序数组 arr[] = {64, 25, 12, 22, 11}:

  • 第1轮:
    • i = 0,未排序部分为 {64, 25, 12, 22, 11}
    • 找到最小值 11,将其与 64 交换,数组变为 {11, 25, 12, 22, 64}
  • 第2轮:
    • i = 1,未排序部分为 {25, 12, 22, 64}
    • 找到最小值 12,将其与 25 交换,数组变为 {11, 12, 25, 22, 64}
  • 第3轮:
    • i = 2,未排序部分为 {25, 22, 64}
    • 找到最小值 22,将其与 25 交换,数组变为 {11, 12, 22, 25, 64}
  • 第4轮:
    • i = 3,未排序部分为 {25, 64}
    • 最小值是 25,不需要交换,数组保持 {11, 12, 22, 25, 64}

最后得到有序数组 {11, 12, 22, 25, 64}

总结

选择排序的核心思想就是每次从未排序的部分中选择最小的元素,并把它放到正确的位置。虽然算法实现简单,但它的时间复杂度为 O(n²),效率较低,适用于小规模数组的排序问题。

选择排序-优化

双向选择排序双端选择排序,这种方法通过同时从两个方向进行选择,以减少排序的时间复杂度。具体来说,它在每一轮中既选择最小值也选择最大值,并将它们放到数组的两端。

双向选择排序的步骤

  1. 初始化:设置两个指针,一个指向数组的开始位置(left),一个指向数组的结束位置(right)。
  2. 选择最小值和最大值
    • 遍历当前的未排序部分,找到最小值和最大值。
    • 将最小值放到left指针指向的位置,将最大值放到right指针指向的位置。
  3. 更新指针
    • left指针向右移动一位(因为最小值已经放到正确的位置)。
    • right指针向左移动一位(因为最大值已经放到正确的位置)。
  4. 重复步骤2和3,直到left指针与right指针交叉或重叠。

双向选择排序的C语言实现

#include <stdio.h>// 函数用于交换两个整数的值
void swap(int *x, int *y) {int temp = *x;*x = *y;*y = temp;
}// 双向选择排序函数
void biDirectionalSelectionSort(int arr[], int n) {int left = 0;          // 指向未排序部分的起始位置int right = n - 1;     // 指向未排序部分的结束位置while (left < right) {int minIndex = left;   // 初始化最小值的索引int maxIndex = right;  // 初始化最大值的索引// 遍历未排序部分,找到最小值和最大值for (int i = left; i <= right; i++) {if (arr[i] < arr[minIndex]) {minIndex = i;}if (arr[i] > arr[maxIndex]) {maxIndex = i;}}// 交换最小值到当前左边界swap(&arr[left], &arr[minIndex]);// 如果最大值在左边界位置,交换最大值到右边界位置if (maxIndex == left) {maxIndex = minIndex; // 更新最大值的索引}// 交换最大值到当前右边界swap(&arr[right], &arr[maxIndex]);// 更新边界left++;right--;}
}// 辅助函数:打印数组元素
void printArray(int arr[], int size) {for (int i = 0; i < size; i++) {printf("%d ", arr[i]);}printf("\n");
}// 测试双向选择排序的主函数
int main() {int arr[] = {64, 25, 12, 22, 11, 90};int n = sizeof(arr) / sizeof(arr[0]);printf("原始数组:\n");printArray(arr, n);biDirectionalSelectionSort(arr, n);printf("排序后的数组:\n");printArray(arr, n);return 0;
}
  1. swap函数
    • 用于交换两个整数的值,以便在数组中重新排列元素。
  2. biDirectionalSelectionSort函数
    • 初始化left指针从数组的开始位置开始,right指针从数组的结束位置开始。
    • 找到最小值和最大值
      • 遍历当前未排序的部分,记录最小值和最大值的索引。
    • 交换最小值和最大值
      • 将最小值交换到left位置。
      • 如果最大值在left位置(也就是最小值交换后,最大值可能在左边),需要更新最大值的索引,然后将最大值交换到right位置。
    • 更新边界
      • left指针向右移动一位,将right指针向左移动一位,准备处理下一轮。
  3. printArray函数
    • 用于打印数组中的元素,帮助观察排序的结果。
  4. main函数
    • 初始化一个数组,打印原始数组,调用biDirectionalSelectionSort函数进行排序,然后打印排序后的数组。

性能分析

  • 时间复杂度:最坏情况下是O(n^2),因为每一轮的遍历操作都需要O(n)的时间,总共会执行n/2轮。
  • 空间复杂度O(1),因为排序过程在原地完成,没有使用额外的存储空间。

双向选择排序通过同时选择最小值和最大值来减少了需要排序的次数,从而比传统的选择排序略微优化了性能。

堆的基本概念

堆是一种特殊的完全二叉树,满足以下条件:

  • 最大堆(Max-Heap):在最大堆中,每个父节点的值都大于或等于其子节点的值。因此,堆顶(根节点)是最大值。
  • 最小堆(Min-Heap):在最小堆中,每个父节点的值都小于或等于其子节点的值,因此堆顶是最小值。

堆是一个完全二叉树,因此它可以用数组来高效地表示。对于任意节点i

  • 左子节点的索引是2 * i + 1
  • 右子节点的索引是2 * i + 2
  • 父节点的索引是(i - 1) / 2

堆排序详细步骤

1. 构建最大堆

构建最大堆的过程是从最后一个非叶子节点开始,依次对每一个节点执行“堆化”操作。堆化(Heapify)是一个过程,它将以某个节点为根的子树调整为最大堆。

构建最大堆的过程

  • 从数组的最后一个非叶子节点开始(索引为n/2 - 1),向前逐步调整每个节点,保证每个子树都是最大堆。

2. 排序过程

  • 将堆顶(最大值)与堆的最后一个元素交换,堆的大小减1。
  • 重新调整堆(heapify),以确保剩下的部分仍然是最大堆。
  • 重复上述步骤,直到堆的大小减小到1。

代码实现

#include <stdio.h>// 函数用于交换两个整数的值
void swap(int *x, int *y) {int temp = *x;*x = *y;*y = temp;
}// 函数用于维护最大堆的性质
void heapify(int arr[], int n, int i) {int largest = i;       // 初始化最大值为当前节点int left = 2 * i + 1;  // 左子节点的索引int right = 2 * i + 2; // 右子节点的索引// 如果左子节点比根节点大,更新最大值的索引if (left < n && arr[left] > arr[largest]) {largest = left;}// 如果右子节点比当前最大值的节点还大,更新最大值的索引if (right < n && arr[right] > arr[largest]) {largest = right;}// 如果最大值不是根节点,交换节点并递归调整if (largest != i) {swap(&arr[i], &arr[largest]);heapify(arr, n, largest); // 递归调整}
}// 主函数实现堆排序
void heapSort(int arr[], int n) {// 构建最大堆for (int i = n / 2 - 1; i >= 0; i--) {heapify(arr, n, i);}// 一个一个取出元素进行排序for (int i = n - 1; i >= 0; i--) {// 当前最大值(根节点)与堆的最后一个元素交换swap(&arr[0], &arr[i]);// 重新调整堆,排除已排序的部分heapify(arr, i, 0);}
}// 辅助函数:打印数组元素
void printArray(int arr[], int size) {for (int i = 0; i < size; i++) {printf("%d ", arr[i]);}printf("\n");
}// 测试堆排序的主函数
int main() {int arr[] = {12, 11, 13, 5, 6, 7};int n = sizeof(arr) / sizeof(arr[0]);printf("原始数组:\n");printArray(arr, n);heapSort(arr, n);printf("排序后的数组:\n");printArray(arr, n);return 0;
}

代码逐步讲解

  1. swap函数
    • 交换两个整数的值,用于调整堆中元素的位置。
  2. heapify函数
    • heapify用于维护最大堆的性质。它从节点i开始,调整以i为根的子树,确保子树符合最大堆的特性。
    • largest变量用来追踪当前子树中的最大值索引。
    • 如果largest不是i,说明子树不符合最大堆的特性,需要交换并递归调用heapify
  3. heapSort函数
    • 首先构建最大堆。for循环从最后一个非叶子节点开始,通过heapify将整个数组调整为最大堆。
    • 然后逐个取出堆顶元素(最大值)并将其与数组的最后一个元素交换,接着调整剩余部分,保持最大堆的性质。
  4. printArray函数
    • 打印数组中的元素,帮助观察排序的结果。
  5. main函数
    • 初始化一个数组,打印原始数组,调用heapSort函数进行排序,然后打印排序后的数组。

希望这些详细解释和代码示例能帮助你更好地理解堆排序。如果还有其他问题或需要更深入的解释,请告诉我!

堆排序代码讲解

堆排序简介

堆排序是一种基于堆(Heap)数据结构的排序算法。堆是一棵完全二叉树,可以通过数组表示:

  • 最大堆:每个节点的值都大于或等于其子节点的值。根节点是最大值。
  • 最小堆:每个节点的值都小于或等于其子节点的值。根节点是最小值。

堆排序的核心思想是:

  1. 首先将无序数组构建为一个最大堆
  2. 然后,将堆顶(即最大值)与数组的最后一个元素交换,缩小堆的范围,对剩下的元素继续调整成最大堆,直到排序完成。

1. `AdjustDown` 函数分析(向下调整)

该函数用于维护最大堆的性质。它从父节点开始,将其与子节点比较,并向下调整,使得父节点的值始终大于等于它的子节点。

void AdjustDown(int* a, int n, int parent)
{int child = parent * 2 + 1; // 左孩子的索引while (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; // 如果父节点已经大于等于孩子,则无需再调整}}
}
解释:
  • child = parent * 2 + 1:左孩子节点的索引。因为堆是一棵完全二叉树,所以对于索引为 parent 的节点,左孩子的索引为 2 * parent + 1,右孩子的索引为 2 * parent + 2
  • 核心逻辑:找到较大的孩子(如果右孩子存在并且比左孩子大,则选择右孩子),并与父节点进行比较,如果父节点比孩子小,则交换它们的值,并继续向下调整。
  • while 循环确保只要存在孩子节点,继续调整,直到父节点大于等于孩子节点或到达树的底部。

2. `HeapSort` 函数分析(堆排序的实现)

void HeapSort(int* a, int n)
{// 建堆过程,从最后一个非叶子节点开始调整,逐步向上调整for (int i = (n - 1 - 1) / 2; i >= 0; i--){AdjustDown(a, n, i);}// 逐步将堆顶元素(最大值)与最后一个未排序元素交换int end = n - 1;while (end > 0){Swap(&a[0], &a[end]); // 将堆顶元素与当前未排序部分的最后一个元素交换AdjustDown(a, end, 0); // 重新调整堆,使剩余部分维持最大堆的性质--end; // 排除最后一个已排序的元素}
}
详细讲解:
  1. 建堆过程
    • for (int i = (n - 1 - 1) / 2; i >= 0; i--)
      • (n - 1 - 1) / 2 计算的是最后一个非叶子节点的索引。叶子节点不需要调整,所以从最后一个非叶子节点开始向上遍历,逐一调整每个节点,以确保整个数组满足最大堆的性质。
      • 调用 AdjustDown(a, n, i) 对从 i 开始的子树进行调整,确保以 i 为根节点的子树是一个最大堆。
  2. 排序过程
    • Swap(&a[0], &a[end]):将当前堆的堆顶元素(最大值)与最后一个未排序的元素交换。
    • AdjustDown(a, end, 0):交换后,堆顶元素可能破坏了堆的性质,需要再次从堆顶(即索引 0)开始进行向下调整,恢复最大堆性质。
    • --end:每次处理完一个最大元素后,end 减少1,表示缩小待排序区域,直到所有元素都排序完成。

示例:堆排序的执行过程

假设我们有一个数组 [4, 10, 3, 5, 1],我们将详细分析堆排序的执行过程。

  1. 建堆
    • 原数组为 [4, 10, 3, 5, 1]
    • 从最后一个非叶子节点开始(i = 1,即 10)。
      • 比较 10 与其孩子(51),10 已经大于它的孩子,不需要调整。
    • 继续处理 i = 04)。
      • 比较 4 与其孩子(103),10 更大,交换 410
      • 现在数组变为 [10, 4, 3, 5, 1]
      • 继续向下调整,4 与它的孩子 5 比较,交换 45,得到 [10, 5, 3, 4, 1]
    • 完成建堆后,最大堆为 [10, 5, 3, 4, 1]
  2. 排序
    • 交换堆顶 10 和最后一个元素 1,得到 [1, 5, 3, 4, 10]
    • 调整堆 [1, 5, 3, 4],结果是 [5, 4, 3, 1, 10]
    • 继续交换堆顶 51,得到 [1, 4, 3, 5, 10]
    • 调整堆 [1, 4, 3],结果是 [4, 1, 3, 5, 10]
    • 交换堆顶 43,得到 [3, 1, 4, 5, 10],调整堆 [3, 1],结果是 [3, 1, 4, 5, 10]
    • 最后交换 31,得到 [1, 3, 4, 5, 10]

时间复杂度

  • 建堆的时间复杂度O(n),因为每个节点调整的次数与其深度成正比,而总的深度是 log(n)
  • 排序的时间复杂度O(n*log(n)),因为需要执行 n 次堆调整,而每次堆调整的时间是 O(log(n))

堆排序的特点

  • 空间复杂度O(1),因为堆排序是在原地排序,不需要额外的数组存储空间。
  • 不稳定性:堆排序是不稳定的,因为元素在交换时可能破坏它们的相对顺序。

通过这段代码,整个堆排序的逻辑就清晰地展示了出来:先建堆,再逐步通过调整最大堆进行排序。

  1. 📜 [ 声明 ] 由于作者水平有限,本文有错误和不准确之处在所难免,
  2. 本人也很想知道这些错误,恳望读者批评指正!
  3. 我是:勇敢滴勇~感谢大家的支持!

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

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

相关文章

SpringBoot项目编译运行成功,但有些包名类名仍然下划线标红的解决方法 | Idea

目录 问题解决方案&#xff1a;方法一&#xff1a;方法二【我用这个成功的】 问题 如图&#xff0c;成功运行但有些包名类名仍然下划线标红&#xff0c;强迫症抓狂 成功运行&#xff1a; 有些包导入标红&#xff1a; 解决方案&#xff1a; 方法一&#xff1a; 点击fil…

分布式框架 - ZooKeeper

一、什么是微服务架构 1、单体架构 顾名思义一个软件系统只部署在一台服务器上。 ​ 在高并发场景中&#xff0c;比如电商项目&#xff0c;单台服务器往往难以支撑短时间内的大量请求&#xff0c;聪明的架构师想出了一个办法提高并发量&#xff1a;一台服务器不够就加一台&am…

整合SpringSecurity框架经典报错

报错描述Description: Field userDetailsService in com.atguigu.security.config.WebSecurityConfig required a bean of type org.springframe 这是整合SpringSecurity权限认证中经常出现的一个问题&#xff0c;由于SpringSecurity中这个UserDetailsService未找到 解决方案…

【线程】线程的同步---生产消费者模型

本文重点&#xff1a;理解条件变量和生产者消费者模型 同步是在保证数据安全的情况下&#xff0c;让我们的线程访问资源具有一定的顺序性 条件变量cond 当一个线程互斥地访问某个变量时&#xff0c;它可能发现在其它线程改变状态之前&#xff0c;它什么也做不了&#xff0c;…

Java 微服务框架 HP-SOA v1.1.4

HP-SOA 功能完备&#xff0c;简单易用&#xff0c;高度可扩展的Java微服务框架。 项目主页 : https://www.oschina.net/p/hp-soa下载地址 : https://github.com/ldcsaa/hp-soa开发文档 : https://gitee.com/ldcsaa/hp-soa/blob/master/README.mdQQ Group: 44636872, 66390394…

ctf.show---->re2

做题笔记。 下载 查壳 32 ida打开。 WSL先运行一下&#xff1a; &#xff1f; 创建呗。 函数如下&#xff1a; 逻辑很清晰&#xff0c;写脚本咯 &#xff1a; #include <stdio.h> #include <string.h> #include <stdlib.h>int main() {char encode[] &qu…

TCP网络编程概述、相关函数、及实现超详解

文章目录 TCP网络编程概述1. TCP协议的特点2. TCP与UDP的差异3. TCP编程流程 TCP网络编程相关函数详解1. socket()&#xff1a;创建套接字参数说明&#xff1a;返回值&#xff1a;示例&#xff1a; 2. connect()&#xff1a;客户端连接服务器参数说明&#xff1a;返回值&#x…

IDEA去除掉虚线,波浪线,和下划线实线的方法

初次安装使用IDEA&#xff0c;总是能看到导入代码后&#xff0c;出现很多的波浪线&#xff0c;下划线和虚线&#xff0c;这是IDEA给我们的一些提示和警告&#xff0c;但是有时候我们并不需要&#xff0c;反而会让人看着很不爽&#xff0c;这里简单记录一下自己的调整方法&#…

Ubunt系统设置NVIDIA显卡性能模式

文章目录 前言一、了解自己的显卡1、输入nvidia-smi指令搞清楚表中的含义 二、通过英伟达官方设置进行修改1、此时的状态3、改完后变为P0 总结 前言 工欲善其事&#xff0c;那性能直接拉满&#xff0c;宁可累坏显卡&#xff0c;也不能影响自己&#xff0c;首先了解自己的显卡以…

OpenAPI鉴权(二)jwt鉴权

一、思路 前端调用后端可以使用jwt鉴权&#xff1b;调用三方接口也可以使用jwt鉴权。对接多个三方则与每个third parth都约定一套token规则&#xff0c;因为如果使用同一套token&#xff0c;token串用可能造成权限越界问题&#xff0c;且payload交叉业务不够清晰。下面的demo包…

uni-app页面调用接口和路由(四)

文章目录 一、路由二、页面调用接口二、路由跳转1.uni.navigateTo(OBJECT)2.uni.redirectTo(OBJECT)3.uni.reLaunch(OBJECT)4.uni.switchTab(OBJECT)5.uni.navigateBack(OBJECT) 总结 一、路由 路由配置 uni-app页面路由为框架统一管理&#xff0c;开发者需要在pages.json里配…

iOS六大设计原则设计模式

六大设计原则&#xff1a; 一、单一职责原则 一个类或者模块只负责完成一个职责或者功能。 类似于&#xff1a;UIView 和 CALayer 二、开放封闭原则 对扩展开放&#xff0c;对修改封闭。 我们要尽量通过扩展软件实体来解决需求变化&#xff0c;而不是通过修改已有的代码来…

ESP32-WROOM-32 [创建AP站点-客户端-TCP透传]

简介 基于ESP32-WROOM-32 开篇(刚买)&#xff0c; 本篇讲的是基于固件 ESP32-WROOM-32-AT-V3.4.0.0&#xff08;内含用户指南, 有AT指令说明&#xff09;的TCP透传设置与使用 设备连接 TTL转USB线, 接ESP32 板 的 GND&#xff0c;RX2&#xff0c; TX2 指令介绍 注意,下面指…

Facebook Marketplace无法使用的原因及解决方案

Facebook Marketplace是一项广受欢迎的买卖平台&#xff0c;然而&#xff0c;有时候用户可能会遇到无法访问或使用该功能的问题。通常&#xff0c;这些问题可以归结为以下几类原因&#xff1a; 地理位置限制&#xff1a; Facebook Marketplace并非在全球每个地区都可用。在某些…

【C++】C++中如何处理多返回值

十四、C中如何处理多返回值 本部分也是碎碎念&#xff0c;因为这些点都是很小的点&#xff0c;构不成一篇文章&#xff0c;所以本篇就是想到哪个点就写哪个点。 1、C中如何处理多个返回值 写过python的同学都知道&#xff0c;当你写一个函数的返回时&#xff0c;那是你想返回…

MySQL(日志)

日志 日志分为三种&#xff1a; undo log &#xff08;回滚日志&#xff09;&#xff1a;用于事务回滚和MVCC redo log &#xff08;重做日志&#xff09;&#xff1a;用于故障恢复 binlog &#xff08;归档日志&#xff09;&#xff1a;用于数据备份和主从复制 undo log undo…

一个简单的个人博客管理平台适合新手学习(最底下有github链接)

一个简单的个人博客管理平台 欢迎大家一起学习 前端技术栈 vue3jshtmlcsselement-plus 后端技术栈 springbootredismysqlmybatis 首页展示 页面介绍 左边为文章界面点击文字名字就能进行阅读 右边为热门博客功能能够实时统计前五名博客热度并且将前三名展示在卡片中(卡片…

【人工智能学习之常用损失函数浅谈】

【人工智能学习之常用损失函数浅谈】 Focal Loss基本概念Focal Loss的定义作用应用场景 Arc Loss基本概念ArcFace Loss的定义作用应用场景 CenterLoss基本概念Center Loss 的定义作用应用场景实现细节 Cross Entropy Loss (CELoss)基本概念二分类任务多分类任务作用优点缺点应用…

oracle avg、count、max、min、sum、having、any、all、nvl的用法

组函数 having的使用 any的使用 all的使用 nvl 从执行结果来看&#xff0c;nvl(列名&#xff0c;默认值)&#xff0c;nvl的作用就是如果列名所在的这一行出现空则用默认值替换

D. Determine Winning Islands in Race (cf div2,dp、图论最短路)

D. Determine Winning Islands in Race 思路: bfs找到E到达每个点的最短时间t[i]。 如果E要超过B&#xff0c;那么一定要借助辅助桥&#xff0c;从而获胜。 假设有u->v的辅助桥&#xff0c;E能通过这个桥超过B的条件是: s>u 且 t[v] < v-s 即 s的取值要为[u1,v-t[v]-…