Carson带你学数据结构:手把手带你全面优化快速排序算法

2023-10-15 00:50

本文主要是介绍Carson带你学数据结构:手把手带你全面优化快速排序算法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

本文主要讲解排序算法中的快速排序 算法,希望你们会喜欢。


目录

示意图


1. 简介

示意图


2. 算法原理

步骤1:将待排序列 分割成独立的2个子序列

  • 在待排序 序列中选择1个基准数据元素(第1个 / 最后1个,称为:枢轴)
  • 通过比较 基准数据元素 与 序列其余元素 大小,将待排序列分成2部分:(右序列)1部分 > 基准元素、(左序列)1部分 < 基准元素

步骤2:通过递归,分别对这2个子序列 进行快速排序

通过步骤2的方式,最终达到整个序列有序的目的


3. 算法示意图

初始状态

待排序序列 = {50,10,90,30,70,40,80,60,20}

示意图

步骤1: 将待排序列 分割成独立的2个子序列

a. 在待排序 序列中选择1个基准数据元素(此处选第1个)

示意图

b. 分别对比 高位元素、低位元素 与 基准元素,具体规则如下:

示意图

具体对比过程如下:

对比1

对比2

对比3

对比4

对比5

对比6

对比7

对比8

示意图

步骤2:分别对这2个子序列 进行排序

示意图


4. 算法实现

4.1 快速排序算法实现(基础实现)

  • 步骤1:通过分区函数Partition()将序列分割成2个独立子序列(高、低)
  • 步骤2:对上述2个子序列使用快速排序方法进行递归
public class QuickSort {/*** 参数说明:* @param srcArray = 需排序的数组序列* @param low = 数组第1个元素下标* @param high = 数组最后1个元素下标*/public static void quickSort(int[] srcArray, int low, int high) {if (low < high) {// 1. 将待排序列 根据所选的枢纽位置,分割成独立的2个子序列// 最终返回的是枢纽位置int privot = Partition(srcArray, low, high);// 2. 分别对这2个子序列 进行排序// a. 通过递归 对低字表进行排序quickSort(srcArray, low, privot - 1);// b. 通过递归 对高字表进行排序quickSort(srcArray, privot + 1, high);}}

分区函数Partition()对于快速排序算法来说非常重要,下面将详细讲解

4.2 分区函数Partition()

  • 作用:将待排序列 根据所选的枢纽位置,分割成独立的2个子序列(基础实现)
  • 返回值:所选的枢纽位置
  • 原理:根据下面的规则比较高/低位元素与枢纽元素的区别。

示意图

    /*** 参数说明:* @param srcArray = 需排序的数组序列* @param low = 数组第1个元素下标* @param high = 数组最后1个元素下标*/public static int Partition(int[] srcArray, int low, int high) {// 1. 将子表的第1个个记录作为枢纽int tmp = srcArray[low];while (low < high) {// 2. 比较高位元素 & 枢纽元素while (low < high && srcArray[high] >= tmp) {high--;}int temp = srcArray[low];srcArray[low] = srcArray[high];srcArray[high] = temp;// 3. 比较低位元素 & 枢纽元素while (low < high && srcArray[low] <= tmp) {low++;}int temp1 = srcArray[high];srcArray[high] = srcArray[low];srcArray[low] = temp1;}// 4. 最终低位、高位都会指向枢纽位置,返回return low;}

4.3 执行 快速排序

    /*** 执行 快速排序*/public static void main(String[] args) {// 定义待排序数列int[] src = new int[]{ 50, 10, 90, 30, 70, 40, 80, 60, 20 };// 输出结果quickSort(src,0,src.length-1);// 输出 排序后的序列for (int a = 0; a < src.length; a++) {System.out.println(src[a]);}}
}

测试结果

10
20
30
40
50
60
70
80
90
  • Demo地址
    Carson_Ho的Github地址:快速排序

5. 算法优化

  • 算法优化概述

示意图

  • 下面,我将详细讲解具体的优化方案

5.1 枢轴的选取方式

  • 优化原因

示意图

  • 解决方案描述

示意图

下面,将演示 三数取中法 的代码实现。

主要修改处:在分区函数Partition()中将枢纽的选择方式改为三数取中,具体原理是:

  1. 找出中间元素
  2. 比较左、右端数据元素,保证左端较小(若左>右,就交换位置)
  3. 比较中、右端数据元素,保证中端较小(若中>右,就交换位置)
  4. 比较中、左端数据元素,保证中端较小(若中>左,就交换位置)
  /*** 参数说明:* @param srcArray = 需排序的数组序列* @param low = 数组第1个元素下标* @param high = 数组最后1个元素下标*/public static int Partition(int[] srcArray, int low, int high) {/*** 三数取中的方式*/// 1. 找出中间元素// 不是使用(low+high)/2的原因:容易溢出// 右移1位 = 除以2,但右移的运算速度更快int m = low + ( (high-low)>>1 );// 2. 比较左、右端数据元素,保证左端较小// 若左>右,就交换位置if(srcArray[low]>srcArray[high]) {int temp = srcArray[low];srcArray[low] = srcArray[high];srcArray[high] = temp;}// 3. 比较中、右端数据元素,保证中端较小// 若中>右,就交换位置if(srcArray[m]>srcArray[high]) {int temp1 = srcArray[m];srcArray[m] = srcArray[high];srcArray[high] = temp1;}// 4. 比较中、左端数据元素,保证中端较小if(srcArray[m]>srcArray[low]) {// 若中>左,就交换位置int temp2 = srcArray[m];srcArray[m] = srcArray[low];srcArray[low] = temp2;}// 此时,最低位 = srcArray[low] = 三数的中间数(即 最低位、最高位 & 中间数的中间值)// 将上述值作为枢纽int tmp = srcArray[low];System.out.println("枢轴位置 =" + srcArray[low]);/*** 下面代码类似未优化前(即,基础实现)*/while (low < high) {// 比较高位元素 & 枢纽元素while (low < high && srcArray[high] >= tmp) {high--;}int temp = srcArray[low];srcArray[low] = srcArray[high];srcArray[high] = temp;// 比较低位元素 & 枢纽元素while (low < high && srcArray[low] <= tmp) {low++;}int temp1 = srcArray[high];srcArray[high] = srcArray[low];srcArray[low] = temp1;}// 最终低位、高位都会指向枢纽位置,返回return low;}

完整实现

public class QuickSort {/*** 快速排序算法实现(基础实现)* 参数说明:* @param srcArray = 需排序的数组序列* @param low = 数组第1个元素下标* @param high = 数组最后1个元素下标*/public static void quickSort(int[] srcArray, int low, int high) {if (low < high) {// 1. 将待排序列 根据所选的枢纽位置,分割成独立的2个子序列// 最终返回的是枢纽位置(主要优化在取取枢纽值里)int privot = Partition(srcArray, low, high);// 2. 分别对这2个子序列 进行排序// a. 通过递归 对低字表进行排序quickSort(srcArray, low, privot - 1);// b. 通过递归 对高字表进行排序quickSort(srcArray, privot + 1, high);}}/*** 作用:将待排序列 根据所选的枢纽位置,分割成独立的2个子序列(优化 = 选取枢轴 = 三数取中)* 返回值:所选的枢纽位置* 参数说明:* @param srcArray = 需排序的数组序列* @param low = 数组第1个元素下标* @param high = 数组最后1个元素下标*/public static int Partition(int[] srcArray, int low, int high) {/*** 三数取中的方式*/// 1. 找出中间元素// 不是使用(low+high)/2的原因:容易溢出// 右移1位 = 除以2,但右移的运算速度更快int m = low + ( (high-low)>>1 );// 2. 比较左、右端数据元素,保证左端较小// 若左>右,就交换位置if(srcArray[low]>srcArray[high]) {int temp = srcArray[low];srcArray[low] = srcArray[high];srcArray[high] = temp;}// 3. 比较中、右端数据元素,保证中端较小// 若中>右,就交换位置if(srcArray[m]>srcArray[high]) {int temp1 = srcArray[m];srcArray[m] = srcArray[high];srcArray[high] = temp1;}// 4. 比较中、左端数据元素,保证中端较小if(srcArray[m]>srcArray[low]) {// 若中>左,就交换位置int temp2 = srcArray[m];srcArray[m] = srcArray[low];srcArray[low] = temp2;}// 此时,最低位 = srcArray[low] = 三数的中间数(即 最低位、最高位 & 中间数的中间值)// 将上述值作为枢纽int tmp = srcArray[low];System.out.println("枢轴位置 =" + srcArray[low]);/*** 下面代码类似未优化前(即,基础实现)*/while (low < high) {// 比较高位元素 & 枢纽元素while (low < high && srcArray[high] >= tmp) {high--;}int temp = srcArray[low];srcArray[low] = srcArray[high];srcArray[high] = temp;// 比较低位元素 & 枢纽元素while (low < high && srcArray[low] <= tmp) {low++;}int temp1 = srcArray[high];srcArray[high] = srcArray[low];srcArray[low] = temp1;}// 最终低位、高位都会指向枢纽位置,返回return low;}/*** 执行 快速排序*/public static void main(String[] args) {// 定义待排序数列int[] src = new int[]{ 50, 10, 90, 30, 70, 40, 80, 60, 20 };// 输出结果quickSort(src,0,src.length-1);// 输出 排序后的序列for (int a = 0; a < src.length; a++) {System.out.println(src[a]);}}
}

测试结果

枢轴位置 =50
枢轴位置 =30
枢轴位置 =10
枢轴位置 =80
枢轴位置 =60
10
20
30
40
50
60
70
80
90

5.2 减少不必要的交换

  • 问题描述

示意图

  • 解决方案
    将高、低位元素 与 枢轴元素比较后的操作进行修改:从 交换 -> 替换,具体请看下列代码演示

主要修改点时在分区函数Partition()

   /*** 参数说明:* @param srcArray = 需排序的数组序列* @param low = 数组第1个元素下标* @param high = 数组最后1个元素下标*/public static int Partition(int[] srcArray, int low, int high) {// 1. 将子表的第1个个记录作为枢纽int tmp = srcArray[low];while (low < high) {// 2. 比较高位元素 & 枢纽元素while (low < high && srcArray[high] >= tmp) {high--;}// 采用 替换操作 换掉之前的 交换操作srcArray[low] = srcArray[high];// 之前的交换操作// int temp = srcArray[low];// srcArray[low] = srcArray[high];// srcArray[high] = temp;// 3. 比较低位元素 & 枢纽元素while (low < high && srcArray[low] <= tmp) {low++;}// 采用 替换操作 换掉之前的 交换操作srcArray[high] = srcArray[low];// 之前的交换操作// int temp1 = srcArray[high];// srcArray[high] = srcArray[low];// srcArray[low] = temp1;}// 将枢轴元素替换到当前低位指针指向的元素 & 返回srcArray[low] = tmp;return low;}

完整实现

public class QuickSort {/*** 快速排序算法实现(优化 = 减少不必要的交换)* 参数说明:* @param srcArray = 需排序的数组序列* @param low = 数组第1个元素下标* @param high = 数组最后1个元素下标*/public static void quickSort(int[] srcArray, int low, int high) {if (low < high) {// 1. 将待排序列 根据所选的枢纽位置,分割成独立的2个子序列// 最终返回的是枢纽位置(主要优化在取枢纽值里)int privot = Partition(srcArray, low, high);// 2. 分别对这2个子序列 进行排序// a. 通过递归 对低字表进行排序quickSort(srcArray, low, privot - 1);// b. 通过递归 对高字表进行排序quickSort(srcArray, privot + 1, high);}}/*** 作用:将待排序列 根据所选的枢纽位置,分割成独立的2个子序列(优化 = 减少不必要的交换)* 返回值:所选的枢纽位置* 参数说明:* @param srcArray = 需排序的数组序列* @param low = 数组第1个元素下标* @param high = 数组最后1个元素下标*/public static int Partition(int[] srcArray, int low, int high) {// 1. 将子表的第1个个记录作为枢纽int tmp = srcArray[low];while (low < high) {// 2. 比较高位元素 & 枢纽元素while (low < high && srcArray[high] >= tmp) {high--;}// 采用 替换操作 换掉之前的 交换操作srcArray[low] = srcArray[high];// 之前的交换操作// int temp = srcArray[low];// srcArray[low] = srcArray[high];// srcArray[high] = temp;// 3. 比较低位元素 & 枢纽元素while (low < high && srcArray[low] <= tmp) {low++;}// 采用 替换操作 换掉之前的 交换操作srcArray[high] = srcArray[low];// 之前的交换操作// int temp1 = srcArray[high];// srcArray[high] = srcArray[low];// srcArray[low] = temp1;}// 将枢轴元素替换到当前低位指针指向的元素 & 返回srcArray[low] = tmp;return low;}/*** 执行 快速排序*/public static void main(String[] args) {// 定义待排序数列int[] src = new int[]{ 50, 10, 90, 30, 70, 40, 80, 60, 20 };// 输出结果quickSort(src,0,src.length-1);// 输出 排序后的序列for (int a = 0; a < src.length; a++) {System.out.println(src[a]);}}
}
  • 测试结果
10
20
30
40
50
60
70
80
90

5.3 优化数据量较小序列的排序方案

  • 问题描述

示意图

  • 解决方案
    1. 对于数据量较大的序列:采用快速排序

资料显示,当序列的数据量>7时,视为大数据量序列

  1. 对于数据量较小的序列:采用 直接插入排序

a. 直接插入排序是简单排序算法中性能最好的
b. 优化主要在quickSort()

  • 具体实现
public class QuickSort {/*** 快速排序算法实现(优化 = 优化数据量较小序列的排序方案)* 参数说明:* @param srcArray = 需排序的数组序列* @param low = 数组第1个元素下标* @param high = 数组最后1个元素下标*/public static void quickSort(int[] srcArray, int low, int high) {// 当序列的数据量>7时,视为大数据量序列,此时采用 快速排序if (high-low > 7) {if (low < high) {System.out.println("采用快排");int privot = Partition(srcArray, low, high);quickSort(srcArray, low, privot - 1);quickSort(srcArray, privot + 1, high);}}else{// 当序列的数据量<7时,视为小数据量序列,此时采用 直接插入排序insertSort(srcArray);System.out.println("采用直接插入排序");};}/*** 作用:将待排序列 根据所选的枢纽位置,分割成独立的2个子序列(优化 = 优化数据量较小序列的排序方案)* 返回值:所选的枢纽位置* 参数说明:* @param srcArray = 需排序的数组序列* @param low = 数组第1个元素下标* @param high = 数组最后1个元素下标*/public static int Partition(int[] srcArray, int low, int high) {// 1. 将子表的第1个个记录作为枢纽int tmp = srcArray[low];while (low < high) {// 2. 比较高位元素 & 枢纽元素// 若高位元素 > 枢纽元素,则继续比较前1个高位元素// 若高位元素 < 枢纽元素,则交换当前高位元素 与 低位元素 位置、开始比较低位元素 与 枢纽元素while (low < high && srcArray[high] >= tmp) {high--;}int temp = srcArray[low];srcArray[low] = srcArray[high];srcArray[high] = temp;// 3. 比较低位元素 & 枢纽元素// 若低位元素 < 基准元素,则继续比较下1个低位元素// 若低位元素 > 枢纽元素,就交换当前低位元素 与 高位元素 位置;重新开始比较高位元素 与 枢纽元素while (low < high && srcArray[low] <= tmp) {low++;}int temp1 = srcArray[high];srcArray[high] = srcArray[low];srcArray[low] = temp1;}// 最终低位、高位都会指向枢纽位置,返回return low;}/*** 直接插入排序 算法实现*/public static void insertSort(int[] srcArray) {int i; // 用于存放当前插入数据记录的数组下标int j; // 用于存放需要比较记录的下标int temp; // 用于交换数据// 从第1个数据记录 开始,该元素可以认为已经被排序for(i = 0 ; i < srcArray.length ; i++){temp = srcArray[i];// 取出下一个数据记录,在已经排序的序列中从后向前扫描// 将 当前数据记录 与 前面排序好的值进行比较for(j = i ; j > 0 && temp < srcArray[j-1] ; j --){// 按照顺序小 -> 大 将 当前需要插入的数据记录插入到合适位置 = 后移已排序好的元素 + 插入新的数据记录// a. 后移已排序好的元素srcArray[j] = srcArray[j-1];}// 插入新的数据记录srcArray[j] = temp;}}/*** 执行 快速排序*/public static void main(String[] args) {// 定义待排序数列int[] src = new int[]{ 50, 10, 90, 30, 70, 40, 80, 60, 20 };// 输出结果quickSort(src,0,src.length-1);// 输出 排序后的序列for (int a = 0; a < src.length; a++) {System.out.println(src[a]);}}
}

注:关于直接插入排序算法实现可自行了解。

  • 测试结果
采用快排
采用直接插入排序
采用直接插入排序
10
20
30
40
50
60
70
80
90

特别注意:此处的排序方式选择不只是第一次排序,而是贯穿 整个快速排序过程,即 由于快速排序过程 = 逐步划分成半子表的过程,所以最后几次的排序一定会使用 直接插入排序

5.4 优化递归操作

  • 问题描述

示意图

  • 解决方案实现
    将快速排序算法最后的 尾部递归操作 改成 迭代操作
  1. 可有效缩减所需的堆栈深度,从而有效提高性能
  2. 主要在主要算法的quickSort()
public class QuickSort {/*** 快速排序算法实现(优化 = 优化递归 = 采用 迭代操作 代替 递归操作)* 参数说明:* @param srcArray = 需排序的数组序列* @param low = 数组第1个元素下标* @param high = 数组最后1个元素下标*/public static void quickSort(int[] srcArray, int low, int high) {// 将if 改成 While,原来操作为:if (low < high)while (low < high) {int privot = Partition(srcArray, low, high);quickSort(srcArray, low, privot - 1);low = privot +1 ;// 将 尾递归中对高字表的排序 改成 low = privot +1,原来操作为:quickSort(srcArray, privot + 1, high);// 原因:在第1次循环后,后1次循环中的Partition(srcArray, low, high) = quickSort(srcArray, privot + 1, high)// 故可删去该递归}}/*** 作用:将待排序列 根据所选的枢纽位置,分割成独立的2个子序列(优化 = 优化递归 = 采用 迭代操作 代替 递归操作)* 返回值:所选的枢纽位置* 参数说明:* @param srcArray = 需排序的数组序列* @param low = 数组第1个元素下标* @param high = 数组最后1个元素下标*/public static int Partition(int[] srcArray, int low, int high) {// 1. 将子表的第1个个记录作为枢纽int tmp = srcArray[low];while (low < high) {// 2. 比较高位元素 & 枢纽元素while (low < high && srcArray[high] >= tmp) {high--;}int temp = srcArray[low];srcArray[low] = srcArray[high];srcArray[high] = temp;// 3. 比较低位元素 & 枢纽元素while (low < high && srcArray[low] <= tmp) {low++;}int temp1 = srcArray[high];srcArray[high] = srcArray[low];srcArray[low] = temp1;}// 最终低位、高位都会指向枢纽位置,返回return low;}/*** 执行 快速排序*/public static void main(String[] args) {// 定义待排序数列int[] src = new int[]{ 50, 10, 90, 30, 70, 40, 80, 60, 20 };// 输出结果quickSort(src,0,src.length-1);// 输出 排序后的序列for (int a = 0; a < src.length; a++) {System.out.println(src[a]);}}
}
  • 测试结果
10
20
30
40
50
60
70
80
90

5.5 总结

最终,总结4种优化方式 & 贴出最终优化后的快速排序算法

  • 方案总结

示意图

  • 具体代码
public class QuickSort {/*** 快速排序算法实现(优化 = 选取枢轴、减少不必要的交换次数、优化数据量较小序列的排序方案、将尾递归操作->迭代操作)* 参数说明:* @param srcArray = 需排序的数组序列* @param low = 数组第1个元素下标* @param high = 数组最后1个元素下标*/public static void quickSort(int[] srcArray, int low, int high) {/*** 优化3:优化数据量较小序列的排序方案 = 步骤8、9*/if (high-low > 7) {// 8. 当序列的数据量>7时,视为大数据量序列,此时采用 快速排序System.out.println("采用快排");/*** 优化4:将尾递归操作->迭代操作 = 步骤10、11*/// 10. 将if 改成 While,原来操作为:if (low < high)while (low < high) {int privot = Partition(srcArray, low, high);quickSort(srcArray, low, privot - 1);// 11. // 将 尾递归中对高字表的排序 改成 low = privot +1,原来操作为:quickSort(srcArray, privot + 1, high);// quickSort_RecursionOp(srcArray, middle + 1, high);low = privot +1 ;}}else{// 9. 当序列的数据量<7时,视为小数据量序列,此时采用 直接插入排序insertSort(srcArray);System.out.println("采用直接插入排序");}}/*** 快速排序算法中寻找中间元素 实现(优化 = 选取枢轴、减少不必要的交换次数、优化数据量较小序列的排序方案、将尾递归操作->迭代操作)* 参数说明:* @param srcArray = 需排序的数组序列* @param low = 数组第1个元素下标* @param high = 数组最后1个元素下标*/public static int Partition(int[] srcArray, int low, int high) {/*** 优化1:三数取中选取枢轴 = 步骤1、2、3、4、5*/// 1. 找出中间元素int m = low + (high - low) /2;// 2. 比较左、右端数据元素,保证左端较小// 若左>右,就交换位置if(srcArray[low]>srcArray[high]) {int temp = srcArray[low];srcArray[low] = srcArray[high];srcArray[high] = temp;}// 3. 比较中、右端数据元素,保证中端较小// 若中>右,就交换位置if(srcArray[m]>srcArray[high]) {int temp1 = srcArray[m];srcArray[m] = srcArray[high];srcArray[high] = temp1;}// 4. 比较中、左端数据元素,保证中端较小if(srcArray[m]>srcArray[low]) {// 若中>左,就交换位置int temp2 = srcArray[m];srcArray[m] = srcArray[low];srcArray[low] = temp2;}// 此时,最低位 = srcArray[low] = 三数的中间数(即 最低位、最高位 & 中间数的中间值)// 将上述值作为枢纽int tmp = srcArray[low];System.out.println("枢轴位置 =" + srcArray[low]);/*** 优化2:减少不必要的交换次数 = 步骤5.6.7*/while (low < high) {while (low < high && srcArray[high] >= tmp) {high--;}// 5. 采用 替换操作 换掉之前的 交换操作srcArray[low] = srcArray[high];// 之前的交换操作// int temp = srcArray[low];// srcArray[low] = srcArray[high];// srcArray[high] = temp;while (low < high && srcArray[low] <= tmp) {low++;}// 6. 采用 替换操作 换掉之前的 交换操作srcArray[high] = srcArray[low];// 之前的交换操作// int temp1 = srcArray[high];// srcArray[high] = srcArray[low];// srcArray[low] = temp1;}// 7. 将枢轴元素替换到当前低位指针指向的元素 & 返回srcArray[low] = tmp;return low;}/*** 直接插入排序 算法实现*/public static void insertSort(int[] srcArray) {int i; // 用于存放当前插入数据记录的数组下标int j; // 用于存放需要比较记录的下标int temp; // 用于交换数据// 从第1个数据记录 开始,该元素可以认为已经被排序for(i = 0 ; i < srcArray.length ; i++){temp = srcArray[i];// 取出下一个数据记录,在已经排序的序列中从后向前扫描// 将 当前数据记录 与 前面排序好的值进行比较for(j = i ; j > 0 && temp < srcArray[j-1] ; j --){// 按照顺序小 -> 大 将 当前需要插入的数据记录插入到合适位置 = 后移已排序好的元素 + 插入新的数据记录// a. 后移已排序好的元素srcArray[j] = srcArray[j-1];}// 插入新的数据记录srcArray[j] = temp;}}/*** 执行 快速排序*/public static void main(String[] args) {// 定义待排序数列int[] src = new int[]{ 50, 10, 90, 30, 70, 40, 80, 60, 20 };// 输出结果quickSort(src,0,src.length-1);// 输出 排序后的序列for (int a = 0; a < src.length; a++) {System.out.println(src[a]);}}
}
  • 测试结果
枢轴位置 =50
采用直接插入排序
枢轴位置 =70
采用直接插入排序
枢轴位置 =80
采用直接插入排序
10
20
30
40
50
60
70
80
90

6. 性能分析

以下将分析算法的性能:时间复杂度、空间复杂度、稳定性
示意图


总结

  • 本文对 全面讲解了快速排序
  • 接下来推出的文章,我将继续讲解数据结构的相关知识,感兴趣的读者可以继续关注我的博客哦:Carson_Ho的Android博客

请帮顶 / 评论点赞!因为你们的赞同/鼓励是我写作的最大动力!

这篇关于Carson带你学数据结构:手把手带你全面优化快速排序算法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/214286

相关文章

Python中图片与PDF识别文本(OCR)的全面指南

《Python中图片与PDF识别文本(OCR)的全面指南》在数据爆炸时代,80%的企业数据以非结构化形式存在,其中PDF和图像是最主要的载体,本文将深入探索Python中OCR技术如何将这些数字纸张转... 目录一、OCR技术核心原理二、python图像识别四大工具库1. Pytesseract - 经典O

一文详解如何在idea中快速搭建一个Spring Boot项目

《一文详解如何在idea中快速搭建一个SpringBoot项目》IntelliJIDEA作为Java开发者的‌首选IDE‌,深度集成SpringBoot支持,可一键生成项目骨架、智能配置依赖,这篇文... 目录前言1、创建项目名称2、勾选需要的依赖3、在setting中检查maven4、编写数据源5、开启热

全面解析HTML5中Checkbox标签

《全面解析HTML5中Checkbox标签》Checkbox是HTML5中非常重要的表单元素之一,通过合理使用其属性和样式自定义方法,可以为用户提供丰富多样的交互体验,这篇文章给大家介绍HTML5中C... 在html5中,Checkbox(复选框)是一种常用的表单元素,允许用户在一组选项中选择多个项目。本

一文全面详解Python变量作用域

《一文全面详解Python变量作用域》变量作用域是Python中非常重要的概念,它决定了在哪里可以访问变量,下面我将用通俗易懂的方式,结合代码示例和图表,带你全面了解Python变量作用域,需要的朋友... 目录一、什么是变量作用域?二、python的四种作用域作用域查找顺序图示三、各作用域详解1. 局部作

Nacos注册中心和配置中心的底层原理全面解读

《Nacos注册中心和配置中心的底层原理全面解读》:本文主要介绍Nacos注册中心和配置中心的底层原理的全面解读,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录临时实例和永久实例为什么 Nacos 要将服务实例分为临时实例和永久实例?1.x 版本和2.x版本的区别

Python数据分析与可视化的全面指南(从数据清洗到图表呈现)

《Python数据分析与可视化的全面指南(从数据清洗到图表呈现)》Python是数据分析与可视化领域中最受欢迎的编程语言之一,凭借其丰富的库和工具,Python能够帮助我们快速处理、分析数据并生成高质... 目录一、数据采集与初步探索二、数据清洗的七种武器1. 缺失值处理策略2. 异常值检测与修正3. 数据

MybatisX快速生成增删改查的方法示例

《MybatisX快速生成增删改查的方法示例》MybatisX是基于IDEA的MyBatis/MyBatis-Plus开发插件,本文主要介绍了MybatisX快速生成增删改查的方法示例,文中通过示例代... 目录1 安装2 基本功能2.1 XML跳转2.2 代码生成2.2.1 生成.xml中的sql语句头2

8种快速易用的Python Matplotlib数据可视化方法汇总(附源码)

《8种快速易用的PythonMatplotlib数据可视化方法汇总(附源码)》你是否曾经面对一堆复杂的数据,却不知道如何让它们变得直观易懂?别慌,Python的Matplotlib库是你数据可视化的... 目录引言1. 折线图(Line Plot)——趋势分析2. 柱状图(Bar Chart)——对比分析3

一文教你Java如何快速构建项目骨架

《一文教你Java如何快速构建项目骨架》在Java项目开发过程中,构建项目骨架是一项繁琐但又基础重要的工作,Java领域有许多代码生成工具可以帮助我们快速完成这一任务,下面就跟随小编一起来了解下... 目录一、代码生成工具概述常用 Java 代码生成工具简介代码生成工具的优势二、使用 MyBATis Gen

Java List排序实例代码详解

《JavaList排序实例代码详解》:本文主要介绍JavaList排序的相关资料,Java排序方法包括自然排序、自定义排序、Lambda简化及多条件排序,实现灵活且代码简洁,文中通过代码介绍的... 目录一、自然排序二、自定义排序规则三、使用 Lambda 表达式简化 Comparator四、多条件排序五、