学习10大经典算法的第一天:
快速排序算法
先呈上没有优化的快排代码:
//todo 【快速排序算法(分治法)】
/**
* 这些是我测试出来的结果,10000条数据下他的表现
* TimeCost(运行时间): 112ms
* MemoryCost(内存消耗): 2084760KB
* TimeCost(运行时间): 112ms
* MemoryCost(内存消耗): 2084768KB
* TimeCost(运行时间): 117ms
* MemoryCost(内存消耗): 2084768KB
*/
public static int NUMBER = 0;
/**
* 1 .从数列中挑出一个元素,称为 “基准”(pivot),
*
* 2. 重新排序数列,所有元素比基准值小的摆放在基准前面,
* 所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
*
* 3. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
*
* 递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,
* 但是这个算法总会退出,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。
* @param args
*/
public static void main(String[] args) {
Runtime r = Runtime.getRuntime();
r.gc();//垃圾回收
long start = System.currentTimeMillis();//开始时间
long startMem = r.freeMemory(); // 开始Memory
//程序主体部分
int [] nums =new int[10000];
numberFactory(10000,nums);
quicklysortB(nums);
System.out.println(Arrays.toString(nums));
System.out.println(NUMBER);
//程序主体部分结束
long endMem =r.freeMemory(); // 末尾Memory
long end = System.currentTimeMillis();//末尾Time
//输出
System.out.println("(运行时间): "+String.valueOf(end - start)+"ms");
System.out.println("(内存消耗): "+String.valueOf((startMem- endMem))+"KB");
}
/**
* TimeCost(运行时间): 0ms
* MemoryCost(内存消耗): 681632KB
*
* @param nums 快速排序算法
* @return {@link int[]}
*/
public static final int[] quicklysortA(int [] nums){
int i=0;
while(i<nums.length){
int j = i+1;
while(j<nums.length){
if(nums[i]>nums[j]){
transformation(nums,i,j);
}
j++;
NUMBER++;
}
i++;
}
return nums;
}
/**
* TimeCost(运行时间): 1ms
* MemoryCost(内存消耗): 681632KB
*处理100条数据时 681984KB 2ms
*处理10000条数据时 1403176KB 108ms
* 2084768KB
* @param nums 快速排序算法
* @return {@link int[]}
*/
public static final int []quicklysortB(int[]nums){
for(int i =0,length = nums.length;i<length;i++){
for(int j=i+1;j<length;j++){
if (nums[i] > nums[j]) {
transformation(nums,i,j);
}
NUMBER++;
}
}
return nums;
}
public static final void transformation(int[]nums,int i,int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
/**
* 随机生成100的数字
*
* @param numbers 数字
* @param nums 数字工厂
*/
public static void numberFactory(int numbers,int[]nums){
for(int i= 0;i<numbers;i++){
nums[i] =(int)(Math.random()*100);
}
}
不要在意那个while的写法和for的写法的区别,他俩的区别非常小微乎其微。
优化后(这里的优化仅仅针对他的基点优化)
/**
* 这是测试10000条数据的结果 效率提高了近10倍,内存消耗也减少了近一半
* TimeCost(运行时间): 13ms
* MemoryCost(内存消耗): 1403632KB
* TimeCost(运行时间): 14ms
* MemoryCost(内存消耗): 1403176KB
* TimeCost(运行时间): 17ms
* MemoryCost(内存消耗): 1403176KB
*/
// 定义数组的最大长度
static final int num = 10000;
public static void main(String[] args) {
Runtime r = Runtime.getRuntime();
r.gc();//垃圾回收
long start = System.currentTimeMillis();//开始时间
long startMem = r.freeMemory(); // 开始Memory
//这个是优化后的。
int arr[] = new int[num];
numberFactory(num,arr);
int length = arr.length-1;
// 调用排序方法对数组进行排序
System.out.println(Arrays.toString(arr));
quickSort(arr, 0, length);
System.out.println("排序后的数组:");
System.out.println(Arrays.toString(arr));
//程序主体结束
long endMem =r.freeMemory(); // 末尾Memory
long end = System.currentTimeMillis();//末尾Time
//输出
System.out.println("TimeCost(运行时间): "+String.valueOf(end - start)+"ms");
System.out.println("MemoryCost(内存消耗): "+String.valueOf((startMem- endMem))+"KB");
}
public static void quickSort(int arr[], int low, int high) {
int keyIndex;
if (low < high) {
keyIndex = sort(arr, low, high);
//递归调用对分成的两部分进行排序
quickSort(arr, low, keyIndex - 1);
quickSort(arr, keyIndex + 1, high);
}
}
//排序方法
private static int sort(int[] arr, int low, int high) {
//计算数组中间的元素的下标
int mid=low+(high-low)/2;
//交换左端与右端的数据,保证左端较小
if(arr[low]>arr[high]){
swap(arr,low,high);
}
//交换中间与右端的数据,保证中间较小
if(arr[mid]>arr[high]){
swap(arr,mid,high);
}
//交换中间与左端的数据,保证左端是中数
if(arr[mid]>arr[low]){
swap(arr,mid,low);
}
//将枢纽关键字备份到arr[0]
int temp = arr[low];
while (low < high) {
while (low < high && arr[high] >= temp) {
high--;
}
//为了防止high--后low==high 所以再进行一次判断
if(low<high){
//采用替换而不是交换的方式进行操作
arr[low]=arr[high];
low++;
}
while (low < high && arr[low] <= temp) {
low++;
}
if(low<high){
//采用替换而不是交换的方式进行操作
arr[high]=arr[low];
high--;
}
}
//在一次循环完成后将枢纽放到相应的位置
arr[low]=temp;
return low;
}
// 交换两个元素的方法
private static void swap(int[] arr, int low, int high) {
int temp = arr[low];
arr[low] = arr[high];
arr[high] = temp;
}
public static void numberFactory(int numbers,int[]nums){
for(int i= 0;i<numbers;i++){
nums[i] =(int)(Math.random()*100);
}
}
说真的时间大幅度的缩短了,内存消耗也降低了,虽然我不知道这些算法的应用场景在哪儿,但是我知道,面试的时候大家都写的一样,你突出了,你就是那个靓仔,加油!算法共同进步第一练排序算法。
(PS:其实这个优化,就是把他的基点从固定的值变成了每一次都是拿到的尽量靠中间值的基点数据,所以在数据量较为庞大的情况下效果较好,要是数据量少的话,我不推荐用快速排序,总觉得他好麻烦)