一,单路快排
1.测试用例:

  1. #ifndef INC_06_QUICK_SORT_DEAL_WITH_NEARLY_ORDERED_ARRAY_SORTTESTHELPER_H
  2. #define INC_06_QUICK_SORT_DEAL_WITH_NEARLY_ORDERED_ARRAY_SORTTESTHELPER_H
  3. #include <iostream>
  4. #include <algorithm>
  5. #include <string>
  6. #include <ctime>
  7. #include <cassert>
  8. using namespace std;
  9. namespace SortTestHelper {
  10. // 生成有n个元素的随机数组,每个元素的随机范围为[rangeL, rangeR]
  11. int *generateRandomArray(int n, int range_l, int range_r) {
  12. int *arr = new int[n];
  13. srand(time(NULL));
  14. for (int i = ; i < n; i++)
  15. arr[i] = rand() % (range_r - range_l + ) + range_l;
  16. return arr;
  17. }
  18. // 生成一个近乎有序的数组
  19. // 首先生成一个含有[0...n-1]的完全有序数组, 之后随机交换swapTimes对数据
  20. // swapTimes定义了数组的无序程度
  21. int *generateNearlyOrderedArray(int n, int swapTimes){
  22. int *arr = new int[n];
  23. for(int i = ; i < n ; i ++ )
  24. arr[i] = i;
  25. srand(time(NULL));
  26. for( int i = ; i < swapTimes ; i ++ ){
  27. int posx = rand()%n;
  28. int posy = rand()%n;
  29. swap( arr[posx] , arr[posy] );
  30. }
  31. return arr;
  32. }
  33. // 拷贝整型数组a中的所有元素到一个新的数组, 并返回新的数组
  34. int *copyIntArray(int a[], int n){
  35. int *arr = new int[n];
  36. copy(a, a+n, arr);
  37. return arr;
  38. }
  39. // 打印arr数组的所有内容
  40. template<typename T>
  41. void printArray(T arr[], int n) {
  42. for (int i = ; i < n; i++)
  43. cout << arr[i] << " ";
  44. cout << endl;
  45.  
  46. return;
  47. }
  48. // 判断arr数组是否有序
  49. template<typename T>
  50. bool isSorted(T arr[], int n) {
  51. for (int i = ; i < n - ; i++)
  52. if (arr[i] > arr[i + ])
  53. return false;
  54. return true;
  55. }
  56. // 测试sort排序算法排序arr数组所得到结果的正确性和算法运行时间
  57. template<typename T>
  58. void testSort(const string &sortName, void (*sort)(T[], int), T arr[], int n) {
  59. clock_t startTime = clock();
  60. sort(arr, n);
  61. clock_t endTime = clock();
  62. cout << sortName << " : " << double(endTime - startTime) / CLOCKS_PER_SEC << " s"<<endl;
  63. assert(isSorted(arr, n));
  64. return;
  65. }
  66. };
  67. #endif

2.归并排序:

  1. #ifndef INC_06_QUICK_SORT_DEAL_WITH_NEARLY_ORDERED_ARRAY_MERGESORT_H
  2. #define INC_06_QUICK_SORT_DEAL_WITH_NEARLY_ORDERED_ARRAY_MERGESORT_H
  3. #include <iostream>
  4. #include <algorithm>
  5. #include "InsertionSort.h"
  6. using namespace std;
  7. // 将arr[l...mid]和arr[mid+1...r]两部分进行归并
  8. template<typename T>
  9. void __merge(T arr[], int l, int mid, int r){
  10. T aux[r-l+];
  11. //T *aux = new T[r-l+1];
  12. for( int i = l ; i <= r; i ++ )
  13. aux[i-l] = arr[i];
  14. // 初始化,i指向左半部分的起始索引位置l;j指向右半部分起始索引位置mid+1
  15. int i = l, j = mid+;
  16. for( int k = l ; k <= r; k ++ ){
  17. if( i > mid ){ // 如果左半部分元素已经全部处理完毕
  18. arr[k] = aux[j-l]; j ++;
  19. }
  20. else if( j > r ){ // 如果右半部分元素已经全部处理完毕
  21. arr[k] = aux[i-l]; i ++;
  22. }
  23. else if( aux[i-l] < aux[j-l] ) { // 左半部分所指元素 < 右半部分所指元素
  24. arr[k] = aux[i-l]; i ++;
  25. }
  26. else{ // 左半部分所指元素 >= 右半部分所指元素
  27. arr[k] = aux[j-l]; j ++;
  28. }
  29. }
  30. //delete[] aux;
  31. }
  32. // 使用优化的归并排序算法, 对arr[l...r]的范围进行排序
  33. template<typename T>
  34. void __mergeSort(T arr[], int l, int r){
  35. // 对于小规模数组, 使用插入排序
  36. if( r - l <= ){
  37. insertionSort(arr, l, r);
  38. return;
  39. }
  40. int mid = (l+r)/;
  41. __mergeSort(arr, l, mid);
  42. __mergeSort(arr, mid+, r);
  43. // 对于arr[mid] <= arr[mid+1]的情况,不进行merge
  44. // 对于近乎有序的数组非常有效,但是对于一般情况,有一定的性能损失
  45. if( arr[mid] > arr[mid+] )
  46. __merge(arr, l, mid, r);
  47. }
  48. template<typename T>
  49. void mergeSort(T arr[], int n){
  50. __mergeSort( arr , , n- );
  51. }
  52. #endif

3.优化时要用的插入排序:

  1. #ifndef INC_06_QUICK_SORT_DEAL_WITH_NEARLY_ORDERED_ARRAY_INSERTIONSORT_H
  2. #define INC_06_QUICK_SORT_DEAL_WITH_NEARLY_ORDERED_ARRAY_INSERTIONSORT_H
  3. #include <iostream>
  4. #include <algorithm>
  5. using namespace std;
  6. template<typename T>
  7. void insertionSort(T arr[], int n){
  8. for( int i = ; i < n ; i ++ ) {
  9. T e = arr[i];
  10. int j;
  11. for (j = i; j > && arr[j-] > e; j--)
  12. arr[j] = arr[j-];
  13. arr[j] = e;
  14. }
  15. return;
  16. }
  17. // 对arr[l...r]范围的数组进行插入排序
  18. template<typename T>
  19. void insertionSort(T arr[], int l, int r){
  20. for( int i = l+ ; i <= r ; i ++ ) {
  21. T e = arr[i];
  22. int j;
  23. for (j = i; j > l && arr[j-] > e; j--)
  24. arr[j] = arr[j-];
  25. arr[j] = e;
  26. }
  27. return;
  28. }
  29. #endif

4.单路快排实现:

  1. #include <iostream>
  2. #include <algorithm>
  3. #include <ctime>
  4. #include "SortTestHelper.h"
  5. #include "MergeSort.h"
  6. #include "InsertionSort.h"
  7. using namespace std;
  8. // 对arr[l...r]部分进行partition操作
  9. // 返回p, 使得arr[l...p-1] < arr[p] ; arr[p+1...r] > arr[p]
  10. template <typename T>
  11. int _partition(T arr[], int l, int r){
  12. // 随机在arr[l...r]的范围中, 选择一个数值作为标定点pivot
  13. swap( arr[l] , arr[rand()%(r-l+)+l] );
  14. T v = arr[l];
  15. int j = l;
  16. for( int i = l + ; i <= r ; i ++ )
  17. if( arr[i] < v ){
  18. j ++;
  19. swap( arr[j] , arr[i] );
  20. }
  21. swap( arr[l] , arr[j]);
  22. return j;
  23. }
  24. // 对arr[l...r]部分进行快速排序
  25. template <typename T>
  26. void _quickSort(T arr[], int l, int r){
  27. // 对于小规模数组, 使用插入排序进行优化
  28. if( r - l <= ){
  29. insertionSort(arr,l,r);
  30. return;
  31. }
  32. int p = _partition(arr, l, r);
  33. _quickSort(arr, l, p- );
  34. _quickSort(arr, p+, r);
  35. }
  36. template <typename T>
  37. void quickSort(T arr[], int n){
  38. srand(time(NULL));
  39. _quickSort(arr, , n-);
  40. }
  41. // 比较Merge Sort和Quick Sort两种排序算法的性能效率
  42. int main() {
  43. int n = ;
  44. // 测试1 一般性测试(随机数)
  45. cout<<"Test for random array, size = "<<n<<", random range [0, "<<n<<"]"<<endl;
  46. int* arr1 = SortTestHelper::generateRandomArray(n,,n);
  47. int* arr2 = SortTestHelper::copyIntArray(arr1,n);
  48. SortTestHelper::testSort("Merge Sort", mergeSort, arr1, n);
  49. SortTestHelper::testSort("Quick Sort", quickSort, arr2, n);
  50. delete[] arr1;
  51. delete[] arr2;
  52. cout<<endl;
  53. // 测试2 测试近乎有序的数组
  54. // 加入了随机选择标定点的步骤后, 我们的快速排序可以轻松处理近乎有序的数组
  55. // 但是对于近乎有序的数组, 其效率比优化后的归并排序要低, 但完全再容忍范围里
  56. int swapTimes = ;
  57. cout<<"Test for nearly ordered array, size = "<<n<<", swap time = "<<swapTimes<<endl;
  58. arr1 = SortTestHelper::generateNearlyOrderedArray(n,swapTimes);
  59. arr2 = SortTestHelper::copyIntArray(arr1, n);
  60. SortTestHelper::testSort("Merge Sort", mergeSort, arr1, n);
  61. SortTestHelper::testSort("Quick Sort", quickSort, arr2, n);
  62. delete[] arr1;
  63. delete[] arr2;
  64. cout<<endl;
  65. // 测试3 测试存在包含大量相同元素的数组
  66. // 但此时, 对于含有大量相同元素的数组, 我们的快速排序算法再次退化成了O(n^2)级别的算法
  67. cout<<"Test for random array, size = "<<n<<", random range [0,10]"<<endl;
  68. arr1 = SortTestHelper::generateRandomArray(n,,);
  69. arr2 = SortTestHelper::copyIntArray(arr1, n);
  70. SortTestHelper::testSort("Merge Sort", mergeSort, arr1, n);
  71. SortTestHelper::testSort("Quick Sort", quickSort, arr2, n);
  72. delete[] arr1;
  73. delete[] arr2;
  74. return ;
  75. }

图解单路快排:

5.单路快排的测试结果:

可见单路快排在随机测试和近乎有序的情况下效率是完全可以接受的,但是在存在大量重复的元素中表现不是太好,下面我们进行一步一步的优化:
二,双路快排:
只需改一下主函数:

  1. #include <iostream>
  2. #include <algorithm>
  3. #include <ctime>
  4. #include "SortTestHelper.h"
  5. #include "MergeSort.h"
  6. #include "InsertionSort.h"
  7. using namespace std;
  8. // 对arr[l...r]部分进行partition操作
  9. // 返回p, 使得arr[l...p-1] < arr[p] ; arr[p+1...r] > arr[p]
  10. template <typename T>
  11. int _partition(T arr[], int l, int r){
  12. // 随机在arr[l...r]的范围中, 选择一个数值作为标定点pivot
  13. swap( arr[l] , arr[rand()%(r-l+)+l] );
  14. T v = arr[l];
  15. int j = l;
  16. for( int i = l + ; i <= r ; i ++ )
  17. if( arr[i] < v ){
  18. j ++;
  19. swap( arr[j] , arr[i] );
  20. }
  21. swap( arr[l] , arr[j]);
  22. return j;
  23. }
  24. // 双路快速排序的partition
  25. // 返回p, 使得arr[l...p-1] < arr[p] ; arr[p+1...r] > arr[p]
  26. template <typename T>
  27. int _partition2(T arr[], int l, int r){
  28. // 随机在arr[l...r]的范围中, 选择一个数值作为标定点pivot
  29. swap( arr[l] , arr[rand()%(r-l+)+l] );
  30. T v = arr[l];
  31. // arr[l+1...i) <= v; arr(j...r] >= v
  32. int i = l+, j = r;
  33. while( true ){
  34. // 注意这里的边界, arr[i] < v, 不能是arr[i] <= v
  35. while( i <= r && arr[i] < v )
  36. i ++;
  37. // 注意这里的边界, arr[j] > v, 不能是arr[j] >= v
  38. while( j >= l+ && arr[j] > v )
  39. j --;
  40. if( i > j )
  41. break;
  42. swap( arr[i] , arr[j] );
  43. i ++;
  44. j --;
  45. }
  46. swap( arr[l] , arr[j]);
  47. return j;
  48. }
  49. // 对arr[l...r]部分进行快速排序
  50. template <typename T>
  51. void _quickSort(T arr[], int l, int r){
  52. // 对于小规模数组, 使用插入排序进行优化
  53. if( r - l <= ){
  54. insertionSort(arr,l,r);
  55. return;
  56. }
  57. // 调用双路快速排序的partition
  58. int p = _partition2(arr, l, r);
  59. _quickSort(arr, l, p- );
  60. _quickSort(arr, p+, r);
  61. }
  62. template <typename T>
  63. void quickSort(T arr[], int n){
  64. srand(time(NULL));
  65. _quickSort(arr, , n-);
  66. }
  67. // 比较Merge Sort和双路快速排序两种排序算法的性能效率
  68. int main() {
  69. int n = ;
  70. // 测试1 一般性测试
  71. cout<<"Test for random array, size = "<<n<<", random range [0, "<<n<<"]"<<endl;
  72. int* arr1 = SortTestHelper::generateRandomArray(n,,n);
  73. int* arr2 = SortTestHelper::copyIntArray(arr1,n);
  74. SortTestHelper::testSort("Merge Sort", mergeSort, arr1, n);
  75. SortTestHelper::testSort("Quick Sort", quickSort, arr2, n);
  76. delete[] arr1;
  77. delete[] arr2;
  78. cout<<endl;
  79. // 测试2 测试近乎有序的数组
  80. // 双路快速排序算法也可以轻松处理近乎有序的数组
  81. int swapTimes = ;
  82. cout<<"Test for nearly ordered array, size = "<<n<<", swap time = "<<swapTimes<<endl;
  83. arr1 = SortTestHelper::generateNearlyOrderedArray(n,swapTimes);
  84. arr2 = SortTestHelper::copyIntArray(arr1, n);
  85. SortTestHelper::testSort("Merge Sort", mergeSort, arr1, n);
  86. SortTestHelper::testSort("Quick Sort", quickSort, arr2, n);
  87. delete[] arr1;
  88. delete[] arr2;
  89. cout<<endl;
  90. // 测试3 测试存在包含大量相同元素的数组
  91. // 使用双快速排序后, 我们的快速排序算法可以轻松的处理包含大量元素的数组
  92. cout<<"Test for random array, size = "<<n<<", random range [0,10]"<<endl;
  93. arr1 = SortTestHelper::generateRandomArray(n,,);
  94. arr2 = SortTestHelper::copyIntArray(arr1, n);
  95. SortTestHelper::testSort("Merge Sort", mergeSort, arr1, n);
  96. SortTestHelper::testSort("Quick Sort", quickSort, arr2, n);
  97. delete[] arr1;
  98. delete[] arr2;
  99. return ;
  100. }

图解双路快排:

 

双路快排测试结果:

可见优化后的双路快排在大量重复元素的数组测试中速度提升了近乎200倍,接下来让我们在来看看最棒的三路快排:
三,三路快排:
1.我们将刚才的双路快排写到一个头文件中以便等下测试:

#ifndef INC_07_QUICK_SORT_THREE_WAYS_QUICKSORT_H
#define INC_07_QUICK_SORT_THREE_WAYS_QUICKSORT_H
#include <iostream>
#include <ctime>
#include <algorithm>
#include "InsertionSort.h"
using namespace std;
// 对arr[l...r]部分进行partition操作
// 返回p, 使得arr[l...p-1] < arr[p] ; arr[p+1...r] > arr[p]
template <typename T>
int _partition(T arr[], int l, int r){
// 随机在arr[l...r]的范围中, 选择一个数值作为标定点pivot
swap( arr[l] , arr[rand()%(r-l+1)+l] );
T v = arr[l];
int j = l;
for( int i = l + 1 ; i <= r ; i ++ )
if( arr[i] < v ){
j ++;
swap( arr[j] , arr[i] );
}
swap( arr[l] , arr[j]);
return j;
}
// 双路快速排序的partition
// 返回p, 使得arr[l...p-1] < arr[p] ; arr[p+1...r] > arr[p]
template <typename T>
int _partition2(T arr[], int l, int r){
// 随机在arr[l...r]的范围中, 选择一个数值作为标定点pivot
swap( arr[l] , arr[rand()%(r-l+1)+l] );
T v = arr[l];
int i = l+1, j = r;
while( true ){
// 注意这里的边界, arr[i] < v, 不能是arr[i] <= v
while( i <= r && arr[i] < v )
i ++;
// 注意这里的边界, arr[j] > v, 不能是arr[j] >= v
while( j >= l+1 && arr[j] > v )
j --;
if( i > j )
break;
swap( arr[i] , arr[j] );
i ++;
j --;
}
swap( arr[l] , arr[j]);
return j;
}
// 对arr[l...r]部分进行快速排序
template <typename T>
void _quickSort(T arr[], int l, int r){
// 对于小规模数组, 使用插入排序进行优化
if( r - l <= 15 ){
insertionSort(arr,l,r);
return;
}
// 调用双路快速排序的partition
int p = _partition2(arr, l, r);
_quickSort(arr, l, p-1 );
_quickSort(arr, p+1, r);
}
template <typename T>
void quickSort(T arr[], int n){
srand(time(NULL));
_quickSort(arr, 0, n-1);
}
#endif

2.三路快排实现:

  1. #include <iostream>
  2. #include <algorithm>
  3. #include <ctime>
  4. #include "SortTestHelper.h"
  5. #include "MergeSort.h"
  6. #include "InsertionSort.h"
  7. #include "QuickSort.h"
  8. using namespace std;
  9. // 递归的三路快速排序算法
  10. template <typename T>
  11. void __quickSort3Ways(T arr[], int l, int r){
  12. // 对于小规模数组, 使用插入排序进行优化
  13. if( r - l <= ){
  14. insertionSort(arr,l,r);
  15. return;
  16. }
  17. // 随机在arr[l...r]的范围中, 选择一个数值作为标定点pivot
  18. swap( arr[l], arr[rand()%(r-l+)+l ] );
  19. T v = arr[l];
  20. int lt = l; // arr[l+1...lt] < v
  21. int gt = r + ; // arr[gt...r] > v
  22. int i = l+; // arr[lt+1...i) == v
  23. while( i < gt ){
  24. if( arr[i] < v ){
  25. swap( arr[i], arr[lt+]);
  26. i ++;
  27. lt ++;
  28. }
  29. else if( arr[i] > v ){
  30. swap( arr[i], arr[gt-]);
  31. gt --;
  32. }
  33. else{ // arr[i] == v
  34. i ++;
  35. }
  36. }
  37. swap( arr[l] , arr[lt] );
  38. __quickSort3Ways(arr, l, lt-);
  39. __quickSort3Ways(arr, gt, r);
  40. }
  41. template <typename T>
  42. void quickSort3Ways(T arr[], int n){
  43. srand(time(NULL));
  44. __quickSort3Ways( arr, , n-);
  45. }
  46. int main() {
  47. int n = ;
  48. // 测试1 一般性测试
  49. cout<<"一般随机测试:"<<endl;
  50. cout<<"Test for random array, size = "<<n<<", random range [0, "<<n<<"]"<<endl;
  51. int* arr1 = SortTestHelper::generateRandomArray(n,,n);
  52. int* arr2 = SortTestHelper::copyIntArray(arr1,n);
  53. int* arr3 = SortTestHelper::copyIntArray(arr1,n);
  54. SortTestHelper::testSort("Merge Sort", mergeSort, arr1, n);
  55. SortTestHelper::testSort("Quick Sort", quickSort, arr2, n);
  56. SortTestHelper::testSort("Quick Sort 3 Ways", quickSort3Ways, arr3, n);
  57. delete[] arr1;
  58. delete[] arr2;
  59. delete[] arr3;
  60. cout<<endl;
  61. // 测试2 测试近乎有序的数组
  62. cout<<"测试近乎有序的数组"<<endl;
  63. int swapTimes = ;
  64. cout<<"Test for nearly ordered array, size = "<<n<<", swap time = "<<swapTimes<<endl;
  65. arr1 = SortTestHelper::generateNearlyOrderedArray(n,swapTimes);
  66. arr2 = SortTestHelper::copyIntArray(arr1, n);
  67. arr3 = SortTestHelper::copyIntArray(arr1, n);
  68. SortTestHelper::testSort("Merge Sort", mergeSort, arr1, n);
  69. SortTestHelper::testSort("Quick Sort", quickSort, arr2, n);
  70. SortTestHelper::testSort("Quick Sort 3 Ways", quickSort3Ways, arr3, n);
  71. delete[] arr1;
  72. delete[] arr2;
  73. delete[] arr3;
  74. cout<<endl;
  75. // 测试3 测试存在包含大量相同元素的数组
  76. cout<<"测试存在包含大量相同元素的数组"<<endl;
  77. cout<<"Test for random array, size = "<<n<<", random range [0,10]"<<endl;
  78. arr1 = SortTestHelper::generateRandomArray(n,,);
  79. arr2 = SortTestHelper::copyIntArray(arr1, n);
  80. arr3 = SortTestHelper::copyIntArray(arr1, n);
  81. SortTestHelper::testSort("Merge Sort", mergeSort, arr1, n);
  82. SortTestHelper::testSort("Quick Sort", quickSort, arr2, n);
  83. SortTestHelper::testSort("Quick Sort 3 Ways", quickSort3Ways, arr3, n);
  84. delete[] arr1;
  85. delete[] arr2;
  86. delete[] arr3;
  87. return ;
  88. }

图解三路快排:

三路快排运行结果:

可见性能又进一步提升了:
比较Merge Sort和双路快速排序和三路快排三种排序算法的性能效率
对于包含有大量重复数据的数组, 三路快排有巨大的优势
对于一般性的随机数组和近乎有序的数组, 三路快排的效率虽然不是最优的, 但是在可以接受的范围里
因此, 在一些语言中, 三路快排是默认的语言库函数中使用的排序算法。比如Java:)

O(n*logn)级别的算法之二(快速排序)的三种实现方法详解及其与归并排序的对比的更多相关文章

  1. “全栈2019”Java多线程第十二章:后台线程setDaemon()方法详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  2. (二)线程Thread中的方法详解

    1.start() start()方法的作用讲得直白点就是通知"线程规划器",此线程可以运行了,正在等待CPU调用线程对象得run()方法,产生一个异步执行的效果.通过start( ...

  3. Java构造和解析Json数据的两种方法详解二

    在www.json.org上公布了很多JAVA下的json构造和解析工具,其中org.json和json-lib比较简单,两者使用上差不多但还是有些区别.下面接着介绍用org.json构造和解析Jso ...

  4. 《Android群英传》读书笔记 (5) 第十一章 搭建云端服务器 + 第十二章 Android 5.X新特性详解 + 第十三章 Android实例提高

    第十一章 搭建云端服务器 该章主要介绍了移动后端服务的概念以及Bmob的使用,比较简单,所以略过不总结. 第十三章 Android实例提高 该章主要介绍了拼图游戏和2048的小项目实例,主要是代码,所 ...

  5. Android群英传笔记——第十二章:Android5.X 新特性详解,Material Design UI的新体验

    Android群英传笔记--第十二章:Android5.X 新特性详解,Material Design UI的新体验 第十一章为什么不写,因为我很早之前就已经写过了,有需要的可以去看 Android高 ...

  6. qml学习笔记(二):可视化元素基类Item详解(上半场anchors等等)

    原博主博客地址:http://blog.csdn.net/qq21497936本文章博客地址:http://blog.csdn.net/qq21497936/article/details/78516 ...

  7. “全栈2019”Java第三十一章:二维数组和多维数组详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  8. Java构造和解析Json数据的两种方法详解二——org.json

    转自:http://www.cnblogs.com/lanxuezaipiao/archive/2013/05/24/3096437.html 在www.json.org上公布了很多JAVA下的jso ...

  9. java多线程并发(二)--线程的生命周期及方法详解

    上篇随笔介绍了线程的相关基础知识以及新启线程的几种方法,本片将继续介绍线程的生命周期及方法详解. 一.线程的生命周期 在Thread代码中,线程的状态被分为6种 public enum State { ...

随机推荐

  1. Excel大批量数据导出

    package com.tebon.ams.util; import lombok.extern.slf4j.Slf4j;import org.apache.poi.openxml4j.excepti ...

  2. 请输入一个大于7的整数,输出小于k并且至少满足下面2个条件中的1个条件的所有正整数

    import java.util.Scanner; /** * @author:(LiberHome) * @date:Created in 2019/3/6 22:06 * @description ...

  3. 用C#+Selenium+ChromeDriver 生成我的咕咚跑步路线地图

    先上结果: 之前 在公司业务中用过java+Selenium+ChromeDriver ,使用起来非常顺手,可以完美模拟真实的用户浏览行为.最近休息的时候想用C#也试一下,于是有了本文. 实现原理一样 ...

  4. Lesson 28 No parking

    Text Jasper White is one of those rare people who believes in ancient myths. He has just bought a ne ...

  5. WebGL绘制有宽度的线

    WebGL中有宽度的线一直都是初学者的一道门槛,因为在windows系统中底层的渲染接口都是D3D提供的,所以无论你的lineWidth设置为多少,最终绘制出来的只有一像素.即使在移动端可以设置有宽度 ...

  6. 写书好累 <HTTP抓包实战>终于出版

    我的新书<HTTP抓包实战>终于开始在京东销售了.内容是关于HTTP包,Fiddler抓包,JMeter发包,适合任何IT工程师阅读.我将自己十年所学的知识,融会贯通总结为一本书.阅读后肯 ...

  7. [译]async/await中阻塞死锁

    这篇博文主要是讲解在async/await中使用阻塞式代码导致死锁的问题,以及如何避免出现这种死锁.内容主要是从作者Stephen Cleary的两篇博文中翻译过来. 原文1:Don'tBlock o ...

  8. Nginx限流配置

    电商平台营销时候,经常会碰到的大流量问题,除了做流量分流处理,可能还要做用户黑白名单.信誉分析,进而根据用户ip信誉权重做相应的流量拦截.限制流量.Nginx自身有的请求限制模块ngx_http_li ...

  9. spring boot - 整合jpa多对对关系保存和查询示例

    pojo: package com.example.zs.springDataJpa; import org.hibernate.annotations.Proxy; import javax.per ...

  10. JSON 序列化的时候忽略无效的属性值

    例如我拥有以下代码. public class NewObject { public int? TestValue { get; set; } public int? Age { get; set; ...