今天是算法学习的第三天,这几天太忙,没有学的太多,昨天花了时间去把排序算法的基础实现弄懂,今天抽个时间来把博客写了。
前几天学了选择排序,插入排序,归并排序,今天来学习一门O(n)级别的算法,也是现在最重要的基础排序算法之一,快速排序。
这是一门十分重要的排序算法,这是公认的最伟大的排序算法之一,为什么会中这么说,因为他在效率方面提升了提多,相比于前面提到的几种排序算法,到底提升了多少,稍后我们进行真实的代码检测。
废话不多说,开始快速排序算法介绍:
思想:
每一轮排序中,将一个数字放到排好序后它应该在的位置。一般这个数字我们都选择数组的第一个数字。这个过程我们一般叫做partition,每一轮patition过后,都会返回一个坐标,这个坐标的上的数字已经处在了一个正确的位置。然后递归对这个数字左边和右边的区间进行排序,(因为这个数字已经排好了,所以只需要考虑它左边和右边),而且每轮partition还会使得这个坐标左右的数都小于等于这个数,这个坐标右边的数都会大于等于这个数。
好像有点绕口,可能会有些难以理解
做法:
定义两个坐标,i,j
i:数组循环的索引,用来表示当前需要进行比对的数字的下表
j:我们的标杆最后应该处的位置(这个过程是动态的,需要不断的进行遍历,最终停下来的位置就是我们要找的位置)
从第二个数字开始依次和我们的标杆(一般是本轮循环中的区间中,数组第一个元素)进行比较,
如果这个数字比我们的标杆大,那就不必理会,因为我们需要的就是使得标杆右边的数字都比我们的标杆大
如果这个数字比我们的标杆小,那就让他和我们的j位置的后一位进行交换
当 i 循环到最后一个元素的时候,此时我们的 j 位置就是我们的标杆应该处在的位置,这时候我们的标杆还在数组的第一个位置,所以我们需要将 j 位置的数字和我们的标杆数字进行交换,然会 j ;这样下来,j 左边的数字都不大于它,它右边的数字都不小于它,这就是我们要的结果
不知道我表达的是否清楚,这个过程有点晦涩难懂,下面是我的代码,小伙伴可以跟着代码走一遍,有疑问的可以评论,我们一起交流。
package com.smarking.lzy.part1;
public class QuitSort {
public static void sort(int [] arr,int left,int right) {
if(left >= right) {
return;
}
int p = partition(arr,left,right);
sort(arr,left,p - 1);
sort(arr,p + 1,right);
}
private static int partition(int [] arr ,int left,int right) {
int value = arr[left];
int j = left;
for(int i = left + 1;i <= right;i++) {
if(arr[i] < value) {
j++;//要先移动j的位置,再进行交换,因为这样可以保证第一个元素(参考值)不被移动
/*试想,如果刚开始的时候元素都小于value,那么如果先交换再进行j的自增,那么就会造成一种情况
* 在arr[l]的位置,存放的值就不是value了,这时候当我们退出for循环的时候,这时候交换arr[i]和arr[j]
* 就没什么意义了,因为交换完成之后,arr[j]存放的值就不是value了
*
*
* */
SortTestHelper.swap(arr, i, j);
}
}
SortTestHelper.swap(arr, left, j);
return j;
}
public static void main(String[] args) {
int testTime = 1000000;
int maxValue = 100;
int maxSize = 100;
boolean success = true;
for(int i = 0;i < testTime;i++) {
int [] arr1 = SortTestHelper.generateRandomArray(maxSize, maxValue);
int [] arr2 = SortTestHelper.copyArray(arr1);
sort(arr1,0,arr1.length-1);
SortTestHelper.comparator(arr2);
if(!SortTestHelper.isEqual(arr1, arr2)) {
success = false;
SortTestHelper.printArray(arr1);
SortTestHelper.printArray(arr2);
break;
}
}
if(success) {
System.out.println("Nice!!!");
}else {
System.out.println("Fuck!");
}
}
}
顺便贴上SortTestHelper的代码,这是一个辅助类
package com.smarking.lzy.part1;
import java.util.Arrays;
/**
* 排序校验工具类
* */
public class SortTestHelper {
//交换arr数组中,i和j位置上的数字
public static void swap(int [] arr,int i,int j) {
int value = arr[i];
arr[i] = arr[j];
arr[j] = value;
}
public static void heapSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
for (int i = 0; i < arr.length; i++) {
heapInsert(arr, i);
}
int size = arr.length;
swap(arr, 0, --size);
while (size > 0) {
heapify(arr, 0, size);
swap(arr, 0, --size);
}
}
public static void heapInsert(int[] arr, int index) {
while (arr[index] > arr[(index - 1) / 2]) {
swap(arr, index, (index - 1) / 2);
index = (index - 1) / 2;
}
}
public static void heapify(int[] arr, int index, int size) {
int left = index * 2 + 1;
while (left < size) {
int largest = left + 1 < size && arr[left + 1] > arr[left] ? left + 1 : left;
largest = arr[largest] > arr[index] ? largest : index;
if (largest == index) {
break;
}
swap(arr, largest, index);
index = largest;
left = index * 2 + 1;
}
}
// for test
public static void comparator(int[] arr) {
Arrays.sort(arr);
}
// for test
public static int[] generateRandomArray(int maxSize, int maxValue) {
int[] arr = new int[(int) ((maxSize + 1) * Math.random())];
for (int i = 0; i < arr.length; i++) {
arr[i] = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());
}
return arr;
}
// for test
public static int[] copyArray(int[] arr) {
if (arr == null) {
return null;
}
int[] res = new int[arr.length];
for (int i = 0; i < arr.length; i++) {
res[i] = arr[i];
}
return res;
}
// for test
public static boolean isEqual(int[] arr1, int[] arr2) {
if ((arr1 == null && arr2 != null) || (arr1 != null && arr2 == null)) {
return false;
}
if (arr1 == null && arr2 == null) {
return true;
}
if (arr1.length != arr2.length) {
return false;
}
for (int i = 0; i < arr1.length; i++) {
if (arr1[i] != arr2[i]) {
return false;
}
}
return true;
}
// for test
public static void printArray(int[] arr) {
if (arr == null) {
return;
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
public static void mPrint(int [] arr) {
if(arr.length == 0 || arr == null) {
throw new RuntimeException("Array could not be noll!!");
}
int len = arr.length;
for(int i = 0;i < len;i++) {
System.out.println(arr[i]);
}
}
}
以上就是快速排序基础版本的实现代码,随时欢迎评论交流
为了测试快速排序的速度,我自己做了一个简单的测试demo,分别用选择排序,插入排序,快速排序进行排序,并输出他们的用时,结果如下
QuitSort time : 6ms
InsertSort time : 586ms
mergeSort time : 1010ms
测试代码如下:
package com.smarking.lzy.part1;
public class Test {
private static long startTime;
private static long endTime;
private static long time;
public static void main(String[] args) {
QuitSort quitSort = new QuitSort();
InserSort insertSort = new InserSort();
MergeSort mergeSort = new MergeSort();
int maxValue = 10000;
int maxSize = 100000;
int [] arr = SortTestHelper.generateRandomArray(maxSize, maxValue);
int [] arr1 = SortTestHelper.copyArray(arr);
int [] arr2 = SortTestHelper.copyArray(arr);
int [] arr3 = SortTestHelper.copyArray(arr);
startTime = System.currentTimeMillis();
quitSort.sort(arr1, 0, arr1.length -1 );
endTime = System.currentTimeMillis();
time = endTime - startTime;
System.out.println("QuitSort time : " + time+"ms");
startTime = System.currentTimeMillis();
insertSort.sort(arr2);
endTime = System.currentTimeMillis();
time = endTime - startTime;
System.out.println("InsertSort time : " + time+"ms");
startTime = System.currentTimeMillis();
mergeSort.sort(arr3,0,arr3.length - 1);
endTime = System.currentTimeMillis();
time = endTime - startTime;
System.out.println("mergeSort time : " + time+"ms");
}
}
算法是计算机的灵魂,也是一名优秀的软件工程师必备的技能,算法的学习是漫长,需要积淀的过程,可能其中很长一段时间都看不到显著的成功,但是我会坚持下去,我知道,这是一次长久的投资,坚持下去,必定成功!一旦成功,那将是自己崭新未来的开始!
有想要一起学习的朋友可以评论留下联系方式,我们一起共同探讨,共同监督!