七大排序 (9000字详解直接插入排序,希尔排序,选择排序,堆排序,冒泡排序,快速排序,归并排序)

一:排序的概念及引入

1.1 排序的概念

1.1 排序的概念

  • 排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。

  • 稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。

在这里插入图片描述

  • 内部排序:数据元素全部放在内存中的排序。
  • 外部排序:数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序。

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

1.2常见的排序算法

常见的排序算法有七种,分别是直接插入排序,希尔排序,选择排序,堆排序,冒泡排序,快速排序,归并排序
在这里插入图片描述
下面我们对这些排序进行一 一讲解。

二:插入排序

2.1 直接插入排序

直接插入排序是一种简单的插入排序法,其基本思想是:

把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列 。实际中我们玩扑克牌时,就用了插入排序的思想。

在这里插入图片描述
插入排序是一种简单直观的排序算法。它的原理是将待排序的元素逐个插入到已排序序列的适当位置,从而形成一个有序序列。

该算法的工作原理如下:

  1. 从第二个元素开始,将其与前面已排序的元素逐个比较,找到合适的位置插入。
  2. 将当前元素与前面已排序的元素进行比较,如果当前元素小于前面的元素,则将前面的元素后移一位,直到找到合适的位置。
  3. 插入当前元素到合适的位置后,继续比较并插入下一个元素。
  4. 重复上述步骤,直到所有元素都被插入到合适的位置。

动图如下:

在这里插入图片描述

下面是一个使用Java实现插入排序的示例代码:

public class InsertionSort {public static void insertionSort(int[] arr) {int n = arr.length;for (int i = 1; i < n; i++) {int key = arr[i]; // 当前要插入的元素int j = i - 1; // 已经排好序的元素的最后一个索引// 将比 key 大的元素向后移动while (j >= 0 && arr[j] > key) {arr[j + 1] = arr[j]; // 向后移动元素j--; // 向前遍历已经排好序的元素}// 插入 key 到合适的位置arr[j + 1] = key; // 将 key 插入到正确的位置}}public static void main(String[] args) {int[] arr = {5, 2, 8, 9, 1, 3};insertionSort(arr); // 使用插入排序算法对数组进行排序System.out.println("排序后的数组:");for (int num : arr) {System.out.print(num + " "); // 输出排序后的数组}}
}

直接插入排序的特性总结:

  1. 元素集合越接近有序,直接插入排序算法的时间效率越高
  2. 时间复杂度:O(N^2)
  3. 空间复杂度:O(1),它是一种稳定的排序算法
  4. 稳定性:稳定

2.2 希尔排序( 缩小增量排序 )

希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数,把待排序文件中所有记录分成多个组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。然后,取,重复上述分组和排序的工作。当到达=1时,所有记录在统一组内排好序。

下面是希尔排序的工作原理:

  1. 选择一个增量序列,增量序列由一系列整数构成,通常是递减的,最后一个增量必须为1。
  2. 根据选定的增量序列,将待排序的数组分割成若干个子数组,每个子数组包含相同间隔的元素。
  3. 对每个子数组进行插入排序,即将每个子数组的元素依次与该子数组中的其他元素进行比较和交换,使得子数组中的元素逐渐有序。
  4. 重复以上步骤,缩小增量,直至增量为1。
  5. 最后进行一次完整的插入排序,以保证数组的最终有序性。

示图如下:
在这里插入图片描述

希尔排序的特性总结:

  1. 希尔排序是对直接插入排序的优化。
  2. 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很
    快。这样整体而言,可以达到优化的效果。
  3. 希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些树中给出的希尔排
    序的时间复杂度都不固定

动图如下:
在这里插入图片描述

因为咋们的gap是按照Knuth提出的方式取值的,而且Knuth进行了大量的试验统计,我们暂时就按照:O(n1.25)到O(1.6 * n1.25) 来算。

下面是一个使用Java实现的希尔排序示例代码:

public class ShellSort {public static void shellSort(int[] arr) {int n = arr.length;// 初始化增量为数组长度的一半int gap = n / 2;while (gap > 0) {for (int i = gap; i < n; i++) {int temp = arr[i];int j = i;// 插入排序while (j >= gap && arr[j - gap] > temp) {arr[j] = arr[j - gap];j -= gap;}arr[j] = temp;}// 缩小增量gap /= 2;}}public static void main(String[] args) {int[] arr = {9, 5, 2, 7, 1, 3, 6, 8, 4};System.out.println("原始数组:");for (int num : arr) {System.out.print(num + " ");}System.out.println();shellSort(arr);System.out.println("排序后的数组:");for (int num : arr) {System.out.print(num + " ");}}
}

希尔排序稳定性:不稳定

三:选择排序

3.1直接选择排序

当我们需要对一个数组进行排序时,选择排序是一种简单而直观的算法。它的工作原理是选择数组中最小的元素,将它与数组的第一个元素交换位置。然后,选择剩余元素中最小的元素,将它与数组的第二个元素交换位置。以此类推,直到整个数组排序完成

动图如下:
在这里插入图片描述

public class SelectionSort {public static void main(String[] args) {// 创建一个整数数组int[] arr = {64, 25, 12, 22, 11};// 调用选择排序方法selectionSort(arr);// 输出排序后的数组System.out.println("排序后的数组:");for(int i=0; i < arr.length; i++){System.out.print(arr[i] + " ");}}public static void selectionSort(int[] arr) {// 获取数组长度int n = arr.length;// 遍历整个数组for (int i = 0; i < n-1; i++) {// 假设当前索引为 i 的元素是最小值int minIndex = i;// 在剩余的元素中寻找最小值的索引for (int j = i+1; j < n; j++) {// 如果找到比当前最小值还小的值,则更新最小值的索引if (arr[j] < arr[minIndex]) {minIndex = j;}}// 将最小值与当前位置交换int temp = arr[minIndex];arr[minIndex] = arr[i];arr[i] = temp;}}
}

【直接选择排序的特性总结】

  1. 直接选择排序思考非常好理解,但是效率不是很好。实际中很少使用
  2. 时间复杂度:O(N^2)
  3. 空间复杂度:O(1)
  4. 稳定性:不稳定

3.2堆排序

堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据。需要注意的是排升序要建大堆,排降序建小堆。

在这里插入图片描述
堆排序具体的讲解可以查看这篇文章

【堆排序的特性总结】

  1. 堆排序使用堆来选数,效率就高了很多。
  2. 时间复杂度:O(N*logN)
  3. 空间复杂度:O(1)
  4. 稳定性:不稳定

四:交换排序

4.1冒泡排序

冒泡排序是一种简单但效率较低的排序算法。它的基本思想是通过不断比较相邻的两个元素并交换位置,从而将较大(或较小)的元素逐渐“冒泡”到数组的顶部(或底部)。这个过程会不断重复,直到数组中的所有元素都按照顺序排列。

下面是一个详细注释的 Java 示例代码:

public class BubbleSort {public static void bubbleSort(int[] arr) {int n = arr.length;// 外层循环控制比较的轮数,每轮比较后,最大的元素就会被冒泡到数组末尾for (int i = 0; i < n - 1; i++) {// 内层循环用于比较相邻的元素并交换位置// 每轮结束后,当前轮数已经排序完成的元素就会排在数组的最后// 所以下一轮比较时,不需要再考虑这些元素for (int j = 0; j < n - 1 - i; j++) {// 如果当前元素比下一个元素大,就交换它们的位置if (arr[j] > arr[j + 1]) {int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}}}public static void main(String[] args) {int[] arr = {64, 34, 25, 12, 22, 11, 90};System.out.println("原始数组:");for (int num : arr) {System.out.print(num + " ");}// 调用冒泡排序bubbleSort(arr);System.out.println("\n排序后的数组:");for (int num : arr) {System.out.print(num + " ");}}
}

动图如下:
在这里插入图片描述
【冒泡排序的特性总结】

  1. 冒泡排序是一种非常容易理解的排序
  2. 时间复杂度:O(N^2)
  3. 空间复杂度:O(1)
  4. 稳定性:稳定

4.2快速排序

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

4.2.1Hoare版

实现思路:
1: 首先,从数组的左端和右端分别设置一个指针,即i和j,以及选择一个基准值pivot。

2:通过循环,从数组的右端开始向左查找,找到第一个小于基准值的元素的下标,将该下标赋给j。然后从数组的左端开始向右查找,找到第一个大于基准值的元素的下标,将该下标赋给i。

3: 在找到两个元素的下标后,交换它们的位置,将小于基准值的元素移动到基准值的左边,大于基准值的元素移动到基准值的右边。然后继续循环,直到左指针i大于等于右指针j。

最后,将基准值放在正确的位置上,将其与左指针i所指向的元素进行交换。这样,基准值左边的元素都小于基准值,右边的元素都大于基准值。

需要注意的是:若选择最左边的数据作为key,则需要right先走;若选择最右边的数据作为key,则需要left先走

动图如下:
在这里插入图片描述

private static int partition(int[] array, int left, int right) {// 设置左右指针和基准值int i = left;int j = right;int pivot = array[left];// 在左指针小于右指针的条件下,进行循环while (i < j) {// 从右往左找到第一个小于基准值的元素的下标while (i < j && array[j] >= pivot) {j--;}// 从左往右找到第一个大于基准值的元素的下标while (i < j && array[i] <= pivot) {i++;}// 交换找到的两个元素的位置swap(array, i, j);}// 将基准值放在正确的位置上swap(array, i, left);// 返回基准值的下标return i;
}

4.2.2挖坑法

实现思路:
1: 首先,在函数内部定义两个指针i和j,分别指向分区的左侧和右侧。初始时,将left作为基准元素的索引,即基准元素为array[left]。
2: 然后,通过循环,不断将大于基准元素的元素移动到右侧,将小于基准元素的元素移动到左侧。具体的操作是,先从右侧开始,找到小于或等于基准元素的元素,然后将该元素移动到左侧指针i的位置。
3: 接着,从左侧开始,找到大于或等于基准元素的元素,然后将该元素移动到右侧指针j的位置。如此反复进行,直到指针i和j相遇。
4: 最后,将基准元素放置到它最终的位置上,也就是指针i的位置。这样,基准元素左侧的元素都小于或等于它,右侧的元素都大于或等于它。
5: 最后返回基准元素的索引i,用于后续的分区。

注意:若在最左边挖坑,则需要R先走;若在最右边挖坑,则需要L先走

动图如下:
在这里插入图片描述

private static int partition(int[] array, int left, int right) {// 设置指针i和j分别指向分区的左侧和右侧int i = left;int j = right;// 设置基准元素为分区的第一个元素int pivot = array[left];// 开始循环,直到指针i和j相遇while (i < j) {// 从右侧开始,寻找小于或等于基准元素的元素while (i < j && array[j] >= pivot) {j--;}// 找到后将该元素移动到左侧指针i的位置array[i] = array[j];// 从左侧开始,寻找大于或等于基准元素的元素while (i < j && array[i] <= pivot) {i++;}// 找到后将该元素移动到右侧指针j的位置array[j] = array[i];}// 将基准元素放置到它最终的位置上array[i] = pivot;// 返回基准元素的索引,用于后续的分区return i;
}

4.2.3前后指针

实现思路:

  1. 我们首先定义了两个变量 curprev,它们都指向数组的起始位置(cur = beginprev = begin - 1)。
  2. 我们选择数组的最后一个元素作为基准元素,将其索引保存在变量 keyi 中。
  3. 然后我们开始遍历数组,从头到尾比较每个元素与基准元素的大小。
  4. 如果当前元素小于基准元素,并且 prev 不等于 cur,则将当前元素与 prev 指向的元素交换位置。
  5. 随后,我们将 cur 向后移动一位。
  6. 当遍历完整个数组后,我们将基准元素与 prev 指向的元素交换位置,以确保基准元素的位置在整个数组中是正确的。
  7. 这样,数组被分成了两部分:左边是小于基准元素的部分,右边是大于基准元素的部分。基准元素的位置为 keyi
  8. 接下来,我们对左半部分(beginkeyi - 1)和右半部分(keyi + 1end)分别进行递归调用。
  9. 重复以上步骤,直到子数组的长度为 1 或 0,即递归终止条件。
//快速排序法  前后指针版本
void QuickSort2(int* arr, int begin, int end)
{if (begin >= end)return;int cur = begin, prev = begin - 1;int keyi = end;while (cur != keyi){if (arr[cur] < arr[keyi] && ++prev != cur){swap(&arr[cur], &arr[prev]);}++cur;}swap(&arr[++prev],&arr[keyi]);keyi = prev;//[begin,keyi -1]keyi[keyi+1,end]QuickSort2(arr, begin, keyi - 1);QuickSort2(arr, keyi + 1, end);}

快速排序优化

  1. 三数取中法选key (三个数中取中间的数为基准)
  2. 递归到小的子区间时,可以考虑使用插入排序

快速排序总结:

  1. 快速排序整体的综合性能和使用场景都是比较好的,所以才敢叫快速排序
  2. 时间复杂度:O(N*logN)
  3. 空间复杂度:O(logN)(特殊情况,如果数据本身有序或者逆序,那么时间复杂度为 O (N2))
  4. 稳定性:不稳定

时间复杂度示图:
在这里插入图片描述

五:归并排序

5.1 基本思想

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide andConquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。 归并排序核心步骤:

在这里插入图片描述
动图:
在这里插入图片描述
归并排序总结:

  1. 归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。
  2. 时间复杂度:O(N*logN)
  3. 空间复杂度:O(N)
  4. 稳定性:稳定

5.2 代码实现

public class MergeSort {// 归并排序入口函数public int[] mergeSort(int[] array) {// 特殊情况处理:当数组为空或只有一个元素时,无需排序,直接返回if (array == null || array.length <= 1) {return array;}// 调用归并排序算法进行排序mergeSort(array, 0, array.length - 1);return array;}// 归并排序递归函数private void mergeSort(int[] array, int start, int end) {// 当前排序范围只有一个元素,无需继续拆分if (start >= end) {return;}// 找到当前排序范围的中间位置int mid = start + (end - start) / 2;// 递归拆分左半部分mergeSort(array, start, mid);// 递归拆分右半部分mergeSort(array, mid + 1, end);// 合并左右两部分排序结果merge(array, start, mid, end);}// 归并两个有序数组private void merge(int[] array, int start, int mid, int end) {// 创建一个临时数组保存合并的结果int[] temp = new int[end - start + 1];int i = start;  // 左半部分起始位置int j = mid + 1;  // 右半部分起始位置int k = 0;  // 临时数组的索引// 遍历左右两部分数组,依次取出较小的元素放入临时数组中while (i <= mid && j <= end) {if (array[i] < array[j]) {temp[k++] = array[i++];} else {temp[k++] = array[j++];}}// 处理剩余的元素while (i <= mid) {temp[k++] = array[i++];}while (j <= end) {temp[k++] = array[j++];}// 将临时数组中的元素拷贝回原数组中for (i = 0; i < temp.length; i++) {array[start + i] = temp[i];}}
}

下面对这段代码进行详细的讲解:

  1. 首先我们定义了一个公共类MergeSort,用于实现归并排序算法。
  2. mergeSort方法是入口函数,接收一个整型数组作为参数,并返回一个排序后的整型数组。在这个方法中,首先判断特殊情况,即当数组为空或只有一个元素时,无需排序,直接返回原数组;否则,调用归并排序算法进行排序。
  3. 归并排序的核心是递归拆分和合并两个有序数组。
  4. mergeSort方法是一个递归函数,接收一个整型数组array和两个整型变量start和end作为参数,表示当前排序范围的起始位置和结束位置。首先判断当前范围是否只有一个元素,如果是,则无需继续拆分;否则,找到当前范围的中间位置mid,分别递归拆分左半部分和右半部分,然后将拆分后的结果合并起来。
  5. merge方法用于合并两个有序数组。它接收一个整型数组array和三个整型变量start、mid和end作为参数,表示需要合并的两个有序数组在原数组中的位置。首先创建一个临时数组temp,用于保存合并的结果,长度为end-start+1。然后设置三个指针i、j和k,分别表示左半部分数组的起始位置、右半部分数组的起始位置和临时数组的索引。接下来,遍历左右两部分数组,依次取出较小的元素放入临时数组中,直到其中一个部分的元素取完。最后,如果左半部分数组还有剩余的元素,将其全部复制到临时数组中;如果右半部分数组还有剩余的元素,也将其全部复制到临时数组中。最后,将临时数组中的元素拷贝回原数组中,完成合并过程。

5.3海量数据的排序问题

外部排序:排序过程需要在磁盘等外部存储进行的排序
前提:内存只有 1G,需要排序的数据有 100G因为内存中因为无法把所有数据全部放下,所以需要外部排序,而归并排序是最常用的外部排序

  1. 先把文件切分成 200 份,每个 512 M
  2. 分别对 512 M 排序,因为内存已经可以放的下,所以任意排序方式都可以
  3. 进行 2路归并,同时对 200 份有序文件做归并过程,最终结果就有序了

六:排序总结

6.1排序算法复杂度及稳定性分析

在这里插入图片描述

6.2各个排序的比较

排序方法最好平均最坏空间复杂度稳定性
冒泡排序O(n)O(n2)O(n2 )O(1)稳定
插入排序O(n)O(n2)O(n2)O(1)稳定
选择排序O(n^2)O(n2)O(n2)O(1)不稳定
希尔排序O(n)O(n1.3)O(n2)O(1)不稳定
堆排序O(n*log n)O(n*log n)O(n*log n)O(1)不稳定
快速排序O(n*log n)O(n*log n)O(n2)O(log n)~O(n)不稳定
归并排序O(n*log n)O(n*log n)O(n*log n)O(n)稳定

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

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

相关文章

【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中

![请 https://cloud.tencent.com/act/cps/redirect?redirect2446&cps_key2e531299bf7e92946df4c3162a81b552&fromconsole

详解cv2.addWeighted函数【使用 OpenCV 添加(混合)两个图像-Python版本】

文章目录 简介函数原型代码示例参考资料 简介 有的时候我们需要将两张图片在alpha通道进行混合&#xff0c;比如深度学习数据集增强方式MixUp。OpenCV的addWeighted提供了相关操作&#xff0c;此篇博客将详细介绍这个函数&#xff0c;并给出代码示例。&#x1f680;&#x1f6…

数据结构--B树

目录 回顾二叉查找树 如何保证查找效率 B树的定义 提炼 B树的插入和删除 概括B树的插入方法如下 B树的删除 导致删除时&#xff0c;结点不满足关键字的个数范围时&#xff08;需要借&#xff09; 如果兄弟不够借&#xff0c;需要合体 回顾B树的删除 B树 B树的查找 …

Windows服务器安装php+mysql环境的经验分享

php mysql环境 下载IIS Php Mysql环境集成包,集成包下载地址: 1、Windows Server 2008 一键安装Web环境包 x64 适用64位操作系统服务器:下载地址:链接: https://pan.baidu.com/s/1MMOOLGll4D7Eb5tBrdTQZw 提取码: btnx 2、Windows Server 2008 一键安装Web环境包 32 适…

Halcon中涉及的数字图像十大理论知识

1.图像处理知识 2.图像的灰度变换 3.图像增强 4.图像的几何变换 5.图像分割 6.图像的频域 7.图像的形态学 8.图像的复原 9.运动图像 10.图像配准

【二层环路】交换机二次原路排查思路

以太网交换网络中为了提高网络可靠性&#xff0c;通常会采用冗余设备和冗余链路&#xff0c;然而现网中由于组网调整、配置修改、升级割接等原因&#xff0c;经常会造成数据或协议报文环形转发&#xff0c;不可避免的形成环路。如图1所示&#xff0c;三台设备两两相连就会形成环…

SNAP对Sentinel-1预处理

SNAP对Sentinel-1预处理 一、导入数据 二、轨道校正 点击run开始处理 三、噪声去除 打开S-1 Thermal Noise Removal工具 如果选中了VH&#xff0c;就只会输出一个VH极化结果 四、辐射定标 Run 五、滤波处理 六、地形校正 这边的dem需要自己下载 dem下载地址 如果一格…

力扣-python-两数之和

题解&#xff1a; class Solution(object):def twoSum(self, nums, target):# 遍历列表for i in range(len(nums)):# 计算需要找到的下一个目标数字res target-nums[i]# 遍历剩下的元素&#xff0c;查找是否存在该数字if res in nums[i1:]:# 若存在&#xff0c;返回答案。这里…

论文阅读:Seeing in Extra Darkness Using a Deep-Red Flash

论文阅读&#xff1a;Seeing in Extra Darkness Using a Deep-Red Flash 今天介绍的这篇文章是 2021 年 ICCV 的一篇 oral 文章&#xff0c;主要是为了解决极暗光下的成像问题&#xff0c;通过一个深红的闪光灯补光。实现了暗光下很好的成像效果&#xff0c;整篇文章基本没有任…

C++项目实战——基于多设计模式下的同步异步日志系统-⑪-日志器管理类与全局建造者类设计(单例模式)

文章目录 专栏导读日志器建造者类完善单例日志器管理类设计思想单例日志器管理类设计全局建造者类设计日志器类、建造者类整理日志器管理类测试 专栏导读 &#x1f338;作者简介&#xff1a;花想云 &#xff0c;在读本科生一枚&#xff0c;C/C领域新星创作者&#xff0c;新星计…

HarmonyOS 语言基础类库开发指南上线啦!

语言基础类库提供哪些功能&#xff1f;多线程并发如何实现&#xff1f;TaskPool&#xff08;任务池&#xff09;和 Worker 在实现和使用场景上有何不同&#xff1f; 针对开发者关注的并发等语言基础类库的相关能力&#xff0c;我们在新推出的语言基础类库开发指南中提供了详细的…

MATLAB——RBF、GRNN和PNN神经网络案例参考程序

欢迎关注“电击小子程高兴的MATLAB小屋” %————RBF程序实例 %% I. 清空环境变量 clear all clc %% II. 训练集/测试集产生 %% % 1. 导入数据 load spectra_data.mat %% % 2. 随机产生训练集和测试集 temp randperm(size(NIR,1)); % 训练集——50个样本 P_train NIR(t…

子组件监听父组件消息,随之变化与不变化

父组件通过props传递给子组件消息&#xff0c;子组件有两种情况接收处理&#xff1a; 1、子组件监听父组件props的变化&#xff0c;同时随之变化【可以直接取props中的值展示&#xff0c;也可以监听值得变化处理】 2、子组件初始化时更新&#xff0c;随后不再随父组件变化 示…

【MySQL系列】- SELECT语句执行顺序

【MySQL系列】- SELECT语句执行顺序 文章目录 【MySQL系列】- SELECT语句执行顺序一、MYSQL逻辑查询处理的步骤图二、MYSQL执行顺序详解2.1 执行FROM操作2.2 应用ON过滤器2.3 JOIN外部行2.4 应用WHERE过滤器2.5 GROUP BY分组2.6 应用ROLLUP 或 CUBE2.7 HAVING过滤2.8 处理SELEC…

源码编译安装部署lnmp

源码编译安装部署lnmp 文章目录 源码编译安装部署lnmp1.简介&#xff1a;2.环境说明&#xff1a;3.部署前的准备工作4.安装nginx4.1.进入官网拉取nginx源码包4.2.通过IP地址访问nginx的web页面 5.安装mysql5.1.安装依赖包5.2.创建用户和组5.3.下载源码包并解压到/usr/local/5.4…

深入理解Scrapy

Scrapy是什么 An open source and collaborative framework for extracting the data you need from websites. In a fast, simple, yet extensible way. Scrapy是适用于Python的一个快速、简单、功能强大的web爬虫框架&#xff0c;通常用于抓取web站点并从页面中提取结构化的数…

靶机 Chill_Hack

Chill_Hack 信息搜集 存活检测 arp-scan -l 详细扫描 扫描结果 显示允许 ftp 匿名链接 FTP 匿名登录 匿名登陆 ftp 下载文件并查看 anonymous10.4.7.139下载命令 get note.txt查看文件 译 Anurodh告诉我&#xff0c;在命令 Apaar 中有一些字符串过滤后台扫描 扫描结果…

leetCode 5. 最长回文子串 动态规划 + 优化空间 / 中心扩展法 + 双指针

5. 最长回文子串 - 力扣&#xff08;LeetC5. 最长回文子串 - 力扣&#xff08;LeetCode&#xff09;5. 最长回文子串 - 力扣&#xff08;LeetC 给你一个字符串 s&#xff0c;找到 s 中最长的回文子串。如果字符串的反序与原始字符串相同&#xff0c;则该字符串称为回文字符串。…

模型的选择与调优(网格搜索与交叉验证)

1、为什么需要交叉验证 交叉验证目的&#xff1a;为了让被评估的模型更加准确可信 2、什么是交叉验证(cross validation) 交叉验证&#xff1a;将拿到的训练数据&#xff0c;分为训练和验证集。以下图为例&#xff1a;将数据分成4份&#xff0c;其中一份作为验证集。然后经过…

VulnHub lazysysadmin

一、信息收集 1.nmap扫描开发端口 开放了&#xff1a;22、80、445 访问80端口&#xff0c;没有发现什么有价值的信息 2.扫描共享文件 enum4linux--扫描共享文件 使用&#xff1a; enum4linux 192.168.103.182windows访问共享文件 \\192.168.103.182\文件夹名称信息收集&…