常用排序算法(下)

目录

2.5 冒泡排序

2.6 快速排序

2.6 1 快速排序思路

详细步骤

2.6 2 快速排序递归实现 

2.6 3快速排序非递归:

快排非递归的优势

 非递归思路

1. 初始化栈

2. 将整个数组的起始和结束索引入栈

3. 循环处理栈中的子数组边界

4. 单趟排序

5. 处理分区后的子数组

6. 重复步骤3和步骤5

注意事项

2.7 归并排序

基本思想:

一、算法步骤

二、具体实现

归并排序递归实现:

归并排序非递归实现: 

三、性能分析

2.8 计数排序

计数排序概念:

一、计数排序的原理与步骤

二、计数排序的示例

 计数排序代码实现:

三、注意事项

四、计数排序的特点


2.5 冒泡排序

   基本思路

    冒泡排序的基本思路是通过重复遍历待排序的数列,比较每对相邻元素的值,若发现顺序错误则交换它们的位置。这个过程重复进行,直到没有需要交换的元素为止,此时数列就完成了排序。冒泡排序的名字是因为较小的元素会逐渐“冒泡”到数列的顶端,即前面,而较大的元素则会沉到数列的底部,即后面。
冒泡排序的基本步骤如下:
(1)比较相邻的元素。如果第一个比第二个大,就交换它们两个。
(2)对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
(3)针对所有的元素重复以上的步骤,除了最后一个。
(4)持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
冒泡排序的时间复杂度在最坏情况下是O(n^2),其中n是数列的长度。尽管冒泡排序不是最高效的排序算法,但它的实现简单,对于小数据量的排序问题还是相当实用的。

  动图展示:

代码实现:

void BubbleSort(int* a, int n)
{for (int i = 1; i < n-1; i++){int flag = 0;for (int j = 0; j < n - i ; j++){if (a[j] > a[j + 1]){Swap(&a[j], &a[j + 1]);flag = 1;}}if (flag == 0){break;}}
}

 问:程序中的flag的作用是什么?

答:冒泡排序时间复杂度是O(N^2),但是这个时间复杂度是由这个算法的最坏情况决定的,也就是当我们要排升序时,我们给了一个降序的数组,这时这个程序的时间复杂度就是O(N^2),而在这个组相对有序的情况下 ,我们可以使用一些手段来提高这个算法的效率,而这个flag就是我们优化这个算法的关键。

   我们知道,如果一个相对有序甚至有序组因该是比无序的数组排序的速度更快的,但是,我们需要判断何时有序,像这个程序中我们使用了两个for循环,如果不判断何时有序然后结束程序的话,它就会完完整整地将这两个循环走完,也就是说,无论是有序还是无序的一组数来排序它的时间复杂度都是O(N^2)。这时我们就可以定义一个flag变量,将它初始化为0,如果里面有数排序了,说明这个数组是无序的,将flag置为1,下一次循环又将flag置为0,我们在下面判断,如果flag为0的话,就说明这个数组没有元素交换过,也就是说这个数组是有序的,既然它是有序的,我们就马上结束这个程序,这样优化我们的冒泡排序就不会每次进入它的时间复杂度都是O(N^2)了,如果这个数组是有序的,那么只会遍历一遍数组就结束程序,此时它的速度是0(N)。

2.6 快速排序

    快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止

2.6 1 快速排序思路

快速排序(Quick Sort)是一种高效的排序算法,它使用分治策略来对一个数组进行排序。以下是快速排序的基本思路:

  1. 选择基准
    从数组中选择一个元素作为基准(key)。这个基准可以是数组中的第一个元素、最后一个元素、中间元素,或者通过某种方式随机选择的元素。

  2. 分区
    重新排列数组,使得所有小于基准的元素都位于基准的左侧,所有大于基准的元素都位于基准的右侧。这个操作称为分区(partition)。

  3. 递归排序
    对基准左侧和右侧的子数组分别进行快速排序。这是一个递归的过程,直到子数组的大小为零或一(此时子数组已经是有序的)。

  4. 合并
    由于快速排序是原地排序,且通过递归已经保证了每个子数组的有序性,所以最终整个数组也会是有序的,不需要额外的合并步骤。

详细步骤

  1. 初始化

    • 设定数组的起始位置 left和结束位置 right
  2. 选择基准

    • 选择数组中的一个元素作为基准,通常选择 array[right](也可以选择其他元素)。
  3. 分区

    • 初始化一个指针 i,使其指向数组的起始位置 low
    • 遍历数组,从 left 到 right-1
      • 如果 array[i] <= key,则继续向右移动 i
      • 如果 array[i] > key,则交换 array[i] 和 array[righth-1](或者任何一个大于key 的未处理元素的位置),并将 right-1 向左移动一位(因为该位置已经处理过)。
    • 最后,将基准元素key 放到正确的位置上,即 array[i] 和 array[right] 之间(通常是通过交换 array[i] 和 array[right] 来完成)。
  4. 递归排序

    • 对基准左侧的子数组(left到 i-1)进行快速排序。
    • 对基准右侧的子数组(i+1 到 right)进行快速排序。
  5. 结束条件

    • 当子数组的大小为零或一时,递归结束,数组已经有序。

2.6 2 快速排序递归实现 

  到现在为止,我们已经了解了快速排序的大致思路,先来看递归实现的快速排序:

void Swap(int* p1, int* p2)
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}
int GetMiddle(int* a, int left, int right)
{int mid = left + right + 1;if (a[left] < a[mid]){if (a[right] > a[mid]){return mid;}else if (a[right] > a[left]){return right;}else{return left;}}else //a[left]>a[mid]{if (a[right] > a[left]){return left;}else if (a[right] > a[mid]){return right;}else{return mid;}}
}void QuickSort(int* a, int left, int right)
{if (left >= right){return;}
//当left大于或等于right时,说明数组已经有序if ((left + right + 1) < 10){InsertSort(a + left, left + right + 1);
//假设快排递归将被排序数组分散成了
//一棵二叉树,我们知道二叉树的最后一层
//占了这棵树的大半结点,当左右加起来
//的数据少于10时,我们可以使用
//插入排序提高它的效率}else{//三数取中int mid = GetMiddle(a, left, right);Swap(&a[left], &a[mid]);int keyi = left;int begin = left, end = right;while (begin < end){while (begin < end && a[end] >= a[keyi]){end--;}while (begin < end && a[begin] <= a[keyi]){begin++;}Swap(&a[begin], &a[end]);}Swap(&a[keyi], &a[begin]);keyi = begin;QuickSort(a, left, keyi - 1);QuickSort(a, keyi + 1, right);}
}

使用一组无序的数来测试一下:

int a[] = { 3,5,8,6,9,7,4,1,2,0,10 };

注意:此程序中的插入排序和三数取中算法都是为了优化快速排序,使它拥有更好的效率,快速排序的核心逻辑代码为:

void Swap(int* p1, int* p2)
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}
void QuickSort(int* a, int left, int right)
{if (left >= right){return;}//当left大于或等于right时,说明数组已经有序int keyi = left;int begin = left, end = right;while (begin < end){while (begin < end && a[end] >= a[keyi]){end--;}while (begin < end && a[begin] <= a[keyi]){begin++;}Swap(&a[begin], &a[end]);}Swap(&a[keyi], &a[begin]);keyi = begin;QuickSort(a, left, keyi - 1);QuickSort(a, keyi + 1, right);
}

2.6 3快速排序非递归:

  看到这里,小伙伴们不禁疑惑:我们既然可以使用递归实现快速排序,为什么还要使用非递归实现呢?

快排非递归的优势

快速排序非递归实现的重要性主要体现在以下几个方面:

  1. 避免递归调用开销:递归实现虽然直观易懂,但在一些编程语言中,递归调用会引入额外的函数调用栈的使用和维护开销。非递归实现通过显式地使用栈来管理状态,可以有效避免这些开销,从而提高性能。

  2. 防止栈溢出:在极端情况下,递归实现可能导致栈溢出,尤其是在处理大规模数据时。非递归实现使用显式的数据结构(如栈)来管理状态,不依赖于系统的调用栈,从而避免了栈溢出的风险。

  3. 降低空间复杂度:递归实现可能需要更多的内存空间,因为每个递归调用都需要在内存中保留一些信息。非递归实现通常使用更少的内存,只需维护一些必要的状态信息,有助于减少内存使用。

  4. 提升性能:在某些编程语言和环境中,递归调用的性能可能不如循环,因为每个递归调用都需要函数调用的开销。非递归实现可以更好地与一些编译器和优化器协同工作,从而提高性能。

  5. 便于优化:非递归实现更容易进行一些优化,例如通过使用迭代而不是递归的方式来访问数组,以更好地利用CPU缓存。这种优化可以进一步提升算法的执行效率。

  6. 适应特定场景:在一些对递归深度有限制的环境(如嵌入式系统)中,非递归实现是必须的,以确保算法能够正常运行。

 非递归思路

快速排序的非递归思路主要是通过手动管理一个栈来模拟递归过程中的函数调用栈,从而实现对数组的排序。以下是快速排序非递归思路的详细步骤:

1. 初始化栈

  • 创建一个空栈,用于保存接下来需要排序的子数组的边界。这个栈可以是任意类型的栈结构,但通常使用整型栈来保存子数组的起始索引(left)和结束索引(right)。

2. 将整个数组的起始和结束索引入栈

  • 这一步相当于递归排序中的初始调用。将数组的起始索引(left)和结束索引(right)作为一对入栈,表示接下来需要处理整个数组。

3. 循环处理栈中的子数组边界

  • 不断从栈中弹出子数组的边界索引(一对),然后对这个子数组进行快速排序的单趟排序。

4. 单趟排序

  • 在单趟排序中,首先选择一个元素作为基准(pivot)。基准的选择可以是子数组的第一个元素,也可以通过其他策略(如三数取中法)来选择。
  • 进行分区操作,将子数组划分为比基准小的左侧部分和比基准大的右侧部分,并确定基准元素的最终位置。

5. 处理分区后的子数组

  • 分区操作完成后,基准元素左侧的子数组(如果存在)和右侧的子数组(如果存在)可能还需要继续排序。
  • 如果左侧子数组有多个元素,则将其起始和结束索引作为一对入栈。
  • 如果右侧子数组有多个元素,也将其起始和结束索引作为一对入栈。

6. 重复步骤3和步骤5

  • 继续迭代该过程,直到栈为空。此时,所有的子数组都已经被正确排序,整个数组也就完成了排序。

注意事项

  • 在单趟排序中,分区操作是关键步骤,它决定了基准元素的最终位置,并将数组划分为两个子数组。
  • 栈的使用是非递归快速排序的核心,它模拟了递归调用栈的功能,允许我们手动管理子数组的排序顺序。
  • 非递归快速排序的性能与递归快速排序相近,但在某些情况下(如递归深度过大导致栈溢出)可能更加稳定可靠。

总结:通过以上步骤,我们可以实现快速排序的非递归版本,从而在处理大规模数据时避免递归调用栈的限制。

由于c语言没有STL,我们使用c++来实现:

int GetMiddle(int* a, int left, int right)
{int mid = left + right + 1;if (a[left] < a[mid]){if (a[right] > a[mid]){return mid;}else if (a[right] > a[left]){return right;}else{return left;}}else //a[left]>a[mid]{if (a[right] > a[left]){return left;}else if (a[right] > a[mid]){return right;}else{return mid;}}
}
int PartSort1(int* a, int left, int right)
{// 三数取中int midi = GetMiddle(a, left, right);Swap(&a[left], &a[midi]);int keyi = left;int begin = left, end = right;while (begin < end){// 右边找小while (begin < end && a[end] >= a[keyi]){--end;}// 左边找大while (begin < end && a[begin] <= a[keyi]){++begin;}Swap(&a[begin], &a[end]);}Swap(&a[keyi], &a[begin]);return begin;
}//非递归
void QuickSortNonR(int* a, int left, int right)
{stack<int> st;st.push(right);st.push(left);while (!st.empty()){int begin = st.top();st.pop();int end = st.top();st.pop();int keyi = PartSort1(a, begin, end);if (keyi+1 < end){st.push(end);st.push(keyi+1);}if (begin < keyi - 1){st.push(keyi - 1);st.push(begin);}}
}

我们来测试一下:

可以看到我们的快排非递归也是成功地实现了。

快速排序的特性总结

1. 快速排序整体的综合性能和使用场景都是比较好的,所以才敢叫快速排序
2. 时间复杂度:O(N*logN)

3. 空间复杂度:O(logN)
4. 稳定性:不稳定 

总结:快速排序是一种非常高效的排序算法,尤其适用于大部分元素已经有序的情况。通过合理选择基准和优化递归过程,可以进一步提高其性能

2.7 归并排序

基本思想:

   归并排序(Merge Sort)是一种分治策略的排序算法,其基本思想是将一个序列分为两个较小的子序列,直到子序列的大小为1,然后将已排序的子序列合并成一个大的有序序列。以下是归并排序的完整思路:

一、算法步骤

  1. 分割

    • 将待排序的数组分成两半,如果数组长度为奇数,则其中一部分会比另一部分多一个元素。
    • 对这两部分数组继续递归地进行分割,直到子数组的长度为1,此时可以认为每个子数组都是有序的(因为只有一个元素)。
  2. 治理(解决)

    • 这一步在归并排序中实际上是通过分割步骤隐含完成的。当子数组的长度为1时,它们自然就是有序的,无需进一步处理。
  3. 合并

    • 将相邻的有序子数组合并成一个有序数组,直到合并为1个完整的数组。
    • 合并过程中,通过比较两个子数组的元素,按大小顺序依次放入新的数组中,从而实现排序。

二、具体实现

  1. 申请空间

    • 创建一个临时数组,用于存放合并后的子数组。
  2. 设定指针

    • 在两个待合并的子数组上分别设置指针,初始时都指向子数组的起始位置。
  3. 比较合并

    • 比较两个指针所指向的元素,将较小的元素放入临时数组,并移动该指针。
    • 重复此过程,直到某个子数组的所有元素都被复制到临时数组中。
    • 将另一个子数组中剩余的元素(如果有的话)直接复制到临时数组的末尾。
  4. 复制回原数组

    • 将临时数组中的元素复制回原数组,以替换原来的子数组。

归并排序递归实现:

void _MergeSort(int* a, int* tmp,int begin,int end)
{if (begin >= end){return;}int mid = (begin + end) / 2;_MergeSort(a, tmp, begin, mid);_MergeSort(a, tmp, mid+1, end);int begin1 = begin, end1 = mid;int begin2 = mid+1, end2 = end;int i = begin;while (begin1 <= end1 && begin2 <= end2){if(a[begin1] < a[begin2]){tmp[i++] = a[begin1++];}else{tmp[i++] = a[begin2++];}}while (begin1 <= end1){tmp[i++] = a[begin1++];}while (begin2 <= end2){tmp[i++] = a[begin2++];}memcpy(a + begin, tmp + begin, (end - begin + 1) * sizeof(int));}
void MergeSort(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){perror("malloc fail");}_MergeSort(a, tmp, 0, n - 1);free(tmp);tmp = NULL;}

此程序涉及在堆上申请资源,所以我们分两个接口实现。

归并排序非递归实现: 

//归并排序非递归
void MergeSortNonR(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * (n+1));if (tmp == NULL){perror("malloc fail");return;}int gap = 1;while (gap <= n){for (int j = 0; j <= n;j+=gap*2){int begin1 = j, end1 = j + gap - 1;int begin2 = j + gap, end2 = j + gap * 2 - 1;if (begin2 > n ){break;}if (end2 > n){end2 = n;}int i = j;while (begin1 <= end1 && begin2 <= end2){if (a[begin1] < a[begin2]){tmp[i++] = a[begin1++];}else{tmp[i++] = a[begin2++];}}while (begin1 <= end1){tmp[i++] = a[begin1++];}while (begin2 <= end2){tmp[i++] = a[begin2++];}memcpy(a + j, tmp + j, sizeof(int) * (end2 - j+1));}gap *= 2;}free(tmp);tmp == NULL;}

给一组无序数,我们来测试一下:

int a[] = { 3,5,7,1,2,0,9,10,4,8,11 };

 

可以看到没有什么问题。

 

三、性能分析

  • 时间复杂度:归并排序的时间复杂度为O(n log n),其中n是数组的长度。在每一层递归中,合并操作的时间复杂度为O(n),而递归的层数为log n,因此总的时间复杂度为O(n log n)。
  • 空间复杂度:归并排序的空间复杂度也是O(n),因为需要额外的空间来创建临时数组。
  • 稳定性:归并排序是稳定的排序算法,即相等的元素在排序后的顺序与它们在原数组中的顺序相同。

总结:归并排序因其稳定的排序特性和较好的平均性能,在实际应用中非常广泛。特别是在数据量较大时,归并排序能够展现出其高效的排序能力。 

2.8 计数排序

计数排序概念:

     计数排序(Counting Sort)是一种非基于比较的排序算法,由Harold H. Seward在1954年提出。它适用于待排序元素为整数且范围较小的情况。计数排序的基本思想是统计每个元素的出现次数,然后利用这些信息将原始序列重新组合成有序序列。

一、计数排序的原理与步骤

计数排序的工作原理主要包括以下几个步骤:

  1. 统计元素出现次数

    • 遍历待排序的数组,统计每个元素出现的次数。这通常通过创建一个辅助数组(计数数组)来实现,该数组的长度等于待排序数组中元素的最大值加1(如果元素是非负整数)。
  2. 前缀和操作

    • 对计数数组进行前缀和操作,使得每个元素的值变为小于等于该元素的值的元素总数。这样,计数数组的每个位置就对应了原数组中元素在排序后数组中的位置。
  3. 重建有序数组

    • 遍历待排序数组,根据计数数组的信息,将元素放回其在有序数组中的正确位置。同时,更新计数数组中对应元素的值,以确保相同元素的相对顺序不变。

二、计数排序的示例

假设我们有一个待排序的数组arr = [4, 2, 2, 8, 3, 3, 1],我们可以按照计数排序的步骤对其进行排序:

  1. 统计元素出现次数

    • 遍历数组arr,得到计数数组count = [0, 1, 2, 2, 2, 0, 1, 1](假设数组中的元素都是非负整数,且最大值不超过7)。
  2. 前缀和操作

    • 对计数数组进行前缀和操作,得到count = [0, 1, 3, 5, 7, 7, 7, 8]。
  3. 重建有序数组

    • 遍历数组arr,根据计数数组的信息将元素放回有序数组中的正确位置。排序后的数组为sorted_arr = [1, 2, 2, 3, 3, 4, 8]。
 计数排序代码实现:
void CountSort(int* a, int n)
{int max = a[0], min = a[0];for (int i = 0; i < n; i++){if (a[i] > max){max = a[i];}if (a[i] < min){min = a[i];}}int range = max - min + 1;int* count = (int*)calloc(range, sizeof(int));if (count == NULL){perror("calloc fail");}for (int i = 0; i <n; i++){count[a[i] - min]++;}int j = 0;for (int i = 0; i < range; i++){while (count[i]--){a[j++] = i + min;}}}

给一组无序数测试一下:

int a[] = { 2,4,76,87654,98,12,76,454,23,98 };

 

    虽然我们的排序成功了,但是这个程序内部开辟了非常多的空间,所以当一组数的最大值和最小值相差太多时,不建议使用计数排序

三、注意事项

  • 在使用计数排序时,需要确保待排序数组中的元素都是非负整数或可映射到非负整数范围内。如果待排序的元素不满足这个要求,就需要对其进行映射转换。
  • 当待排序元素的范围非常大时,计数排序可能会消耗大量的内存空间,因此在实际应用中需要注意这一点。

四、计数排序的特点

  1. 时间复杂度

    • 计数排序的时间复杂度为O(n+k),其中n是待排序数组的长度,k是待排序数组中元素的范围。当k不是很大时,计数排序的时间复杂度接近线性,快于任何基于比较的排序算法(如快速排序、归并排序等,它们的时间复杂度在理论上的下限是O(n log n))。
  2. 空间复杂度

    • 计数排序的空间复杂度为O(k),其中k是待排序数组中元素的范围。因此,计数排序是一种牺牲空间换取时间的排序算法。
  3. 稳定性

    • 计数排序是稳定的排序算法,即相等的元素在排序后的序列中保持它们原有的先后顺序。
  4. 适用场景

    • 计数排序特别适用于整数排序,特别是当整数的范围不是很大时。对于非整数类型的数据或整数范围非常大的情况,计数排序可能不适用或效率较低。

 本章完。

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

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

相关文章

Github界面学习

之前并没有使用到其他功能大多数是看代码&#xff0c;然后看discussion&#xff1b; now,在做毕设的时候发现了一个gymnasium关于异步环境的bug&#xff0c;查看github发现已经被修复了&#xff1b; 因此希望学习一下修复者是在哪个module修复以及如何修复以及提交代码&#…

Lesson1 - 操作系统概述与硬件视角

文章目录 什么是操作系统操作系统的形成 从程序看OS提出问题&#xff1a;从hello world文件开始目前编译器帮我们解决了诸多问题gcc的编译过程 CPU的运作CPU对任务的切换 什么是操作系统 操作系统 Operating System 是一组控制和管理计算机 硬件 和 软件 资源合理地对各类作业…

移动硬盘无法读取:问题解析与高效数据恢复实战

一、移动硬盘无法读取的困扰 在数字化时代&#xff0c;移动硬盘作为数据存储和传输的重要媒介&#xff0c;承载着大量珍贵的数据资源。然而&#xff0c;当移动硬盘突然无法读取时&#xff0c;我们往往会陷入深深的困扰之中。这种无法读取的现象可能表现为插入电脑后毫无反应、…

为什么e^x的导数是本身

参考Why is the derivative of exex?的解法如下。 主要是利用导数的定义&#xff0c;将 f ′ ( x ) f(x) f′(x)转化为另一个公式&#xff0c;其值为1。 lim ⁡ h → 0 e h − 1 h \lim_{h \to 0} \frac{e^h - 1}{h} h→0lim​heh−1​ 而如何求这个公式的值&#xff1f;有人…

【论文速看】DL最新进展20241005-Transformer、目标跟踪、Diffusion Transformer

目录 【Transformer】【目标跟踪】【Diffusion Transformer】 【Transformer】 [NeurlPS 2024] Parameter-Inverted Image Pyramid Networks 机构&#xff1a;清华大学、上海AI Lab、上交、港中文、商汤 论文链接&#xff1a;https://arxiv.org/pdf/2406.04330 代码链接&…

【文献阅读】Attention Bottlenecks for Multimodal Fusion

Abstract 在多模态视频分类中&#xff0c;将各模态的最终表示或预测进行后期融合&#xff08;“后期融合”&#xff09;仍然是主流范式。为此&#xff0c;本文提出了一种基于 Transformer 的新型架构&#xff0c;该架构使用“融合瓶颈”在多个层次进行模态融合。与传统的成对自…

D28【python 接口自动化学习】- python基础之输入输出与文件操作

day28 输入 学习日期&#xff1a;20241005 学习目标&#xff1a;输入输出与文件操作&#xfe63;-40 输入&#xff1a;如何接收用户通过键盘输入的数据&#xff1f; 学习笔记&#xff1a; 输入设备与输入方式 Input函数 命令行参数 可选参数 必填参数 强制转换参数类型 总…

Linux环境搭建git服务器和代码自动化部署

在开发过程中&#xff0c;我们经常遇到的问题就是提交代码到测试地址&#xff0c;然后进行线上测试。 要实现Git代码的自动化部署&#xff0c;考虑以下几种方法 FTP提交&#xff1a;可以使用FTP将代码上传到服务器自动化部署工具&#xff1a;如Jenkins、当代码被推送到仓库时…

【Kubernetes】常见面试题汇总(五十五)

目录 121. POD 创建失败&#xff1f; 122. POD 的 ready 状态未进入&#xff1f; 特别说明&#xff1a; 题目 1-68 属于【Kubernetes】的常规概念题&#xff0c;即 “ 汇总&#xff08;一&#xff09;~&#xff08;二十二&#xff09;” 。 题目 69-113 属于【Kube…

Java项目实战II基于Java+Spring Boot+MySQL的宠物咖啡馆平台的设计与实现(源码+数据库+文档)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者 一、前言 在快节奏的城市生活中&#xff0c;宠物咖啡馆作为一种结合了休闲与宠物陪伴的新型业态&#xff0c;正…

重学SpringBoot3-集成Redis(三)

更多SpringBoot3内容请关注我的专栏&#xff1a;《SpringBoot3》 期待您的点赞&#x1f44d;收藏⭐评论✍ 重学SpringBoot3-集成Redis&#xff08;三&#xff09; 1. 引入 Redis 依赖2. 配置 RedisCacheManager 及自定义过期策略2.1 示例代码&#xff1a;自定义过期策略 3. 配置…

I/O多路转接

目录 一、select 1.1、select概念 1.2、select 函数原型 1.3、理解 select 执行过程 1.4、select就绪条件 1.4.1、读就绪 1.4.2、写就绪 1.4.3、异常就绪&#xff08;了解&#xff09; 1.5、select 基本工作流程 1.6、select服务器 1.6.1、Sock.hpp 1.6.2、selectS…

【复习】html最重要的表单和上传标签

文章目录 imgforminput img <img src"https://tse1-mm.cn.bing.net/th/id/OIP-C._XVJ53-pN6sDMXp8W19F4AAAAA?rs1&pidImgDetMain"alt"二次元"height"350px"width"200px"/>常用 没啥说的&#xff0c;一般操作css多一些 for…

CSP-J/S复赛算法 动态规划初步

文章目录 前言动态规划动态规划常见形式动态规划求最值的几个例子1. **背包问题**2. **最短路径问题**3. **最小硬币找零问题**4. **最长递增子序列** 总结 最优子结构举个简单的例子其他例子条件 DP的核心就是穷举具体解释 递归的算法时间复杂度dp数组的迭代解法通俗易懂的解释…

LabVIEW提高开发效率技巧----使用动态事件

在LabVIEW开发过程中&#xff0c;用户交互行为可能是多样且不可预知的。为应对这些变化&#xff0c;使用动态事件是一种有效的策略。本文将从多个角度详细介绍动态事件的概念及其在LabVIEW开发中的应用技巧&#xff0c;并结合实际案例&#xff0c;说明如何通过动态事件提高程序…

招联2025校招内推倒计时

【投递方式】 直接扫下方二维码&#xff0c;或点击内推官网https://wecruit.hotjob.cn/SU61025e262f9d247b98e0a2c2/mc/position/campus&#xff0c;使用内推码 igcefb 投递&#xff09; 【招聘岗位】 后台开发 前端开发 数据开发 数据运营 算法开发 技术运维 软件测试 产品策…

8648 图的深度遍历

### 思路 1. **图的邻接表存储结构**&#xff1a;使用邻接表存储图的顶点和边信息。 2. **基本操作函数**&#xff1a;包括创建图、查找顶点、获取顶点值、获取第一个邻接顶点、获取下一个邻接顶点等。 3. **深度优先遍历&#xff08;DFS&#xff09;**&#xff1a;从某个顶点出…

车载项目:HIL测试、功能安全测试、CAN一致性测试、UDS测试、ECU测试、OTA测试、TBOX测试、导航测试、车控测试

FOTA模块中OTA的知识点&#xff1a;1.测试过程中发现哪几类问题&#xff1f; 可能就是一个单键的ecu&#xff0c;比如升了一个门的ecu&#xff0c;他的升了之后就关不上&#xff0c;还有就是升级组合ecu的时候&#xff0c;c屏上不显示进度条。 2.在做ota测试的过程中&#xff…

今日指数项目个股描述功能实现

个股描述功能实现 1 个股描述功能实现说明 1&#xff09;原型示意 2&#xff09;接口说明 功能描述&#xff1a;个股主营业务查询接口 服务路径&#xff1a;/api/quot/stock/describe 服务方法&#xff1a;GET 请求参数&#xff1a;code #股票编码 响应参数&#xff1a; {…

java计算机毕设课设—坦克大战游戏

这是什么系统&#xff1f; 坦克大战游戏是一款以坦克为主题的射击游戏&#xff0c;旨在为玩家提供一个刺激、有趣的游戏体验。该游戏不仅拥有丰富的功能&#xff0c;还注重玩家的互动体验。此系统是使用Java语言实现坦克大战游戏程序&#xff0c;玩家通过连接访问进入游戏&…