原始版本:
package com.duoduo.test1;
/*
* 快速排序:基于分治策略
* 算法思想:1 分解(取基准元素,将其左右两侧划分
* 2 治理:对两个子序列进行快速排序
* 3 合并: 将排好序的两个子序列合并在一起,得到原问题的解
* 执行过程:取基准元素 从右向左扫描 找<基准元素的值 进行交换i++
* 从左向右扫描 找到>基准元素的值 交换值并j-- 不断重复步骤 直到i ,j 指针重合
* 返回该位置mid=i 恰好是基准元素的位置
* 之后分别对左右两侧的子序列进行排序 合并结果
*
* */
import java.util.Scanner;
public class QuickSort {
public static void main(String [] args) {
Scanner sc=new Scanner(System.in); //系统键盘录入数据
System.out.println("请先输入要排序的数据的个数:");
int N=sc.nextInt();
System.out.println("请输入要排序的数据 :");
int [] arr=new int[N];
for(int i=0;i<N;i++) {
arr[i]=sc.nextInt();
}
quickSort(arr,0,N-1); //快速排序
System.out.println("排序后的序列为:");
for(int i=0;i<N;i++)
System.out.print(arr[i]+" ");
}
/*快速排序递归算法*/
public static void quickSort(int [] arr,int low,int high) {
int mid;
if(low<high) {
mid=partition(arr,low,high); //基准位置
quickSort(arr,low,mid-1); //左子序列
quickSort(arr,mid+1,high); //右子序列
}
}
/*划分序列,找到基准元素位置*/
public static int partition(int [] arr,int low,int high) {
int i=low;
int j=high;
int temp=arr[low];
while(i<j) {
while(i<j&&arr[j]> temp) //从右往左扫描 找到比基准元素小的值为止 跳出循环
j--;
if(i<j) {
int tmp=arr[i]; //交换元素位置
arr[i]=arr[j];
arr[j]=tmp;
i++;
} //交换二者的值 并i++ 右移
while(i<j&&arr[i] <=temp) //从左往右扫描 找到比基准元素大的值为止
i++;
if(i<j) {
int tmp=arr[i]; //交换位置
arr[i]=arr[j];
arr[j]=tmp;
j--; //交换二者的值 并j--
}
}
return i; //返回最终划分完成后基准元素所在的位置
}
}
结果:
优化版本:
原始版本每次都是和基准元素进行交换,没必要。游湖版本交换元素的个数减少~
/*划分序列,找到基准元素位置*/
public static int partition(int [] arr,int low,int high) {
int i=low;
int j=high;
int temp=arr[low];
while(i<j) {
while(i<j&&arr[j]>temp) j--; //向左扫描
while(i<j&&arr[i]<=temp) i++; //向右扫描
if(i<j) { //找到在右边比基准元素小的 和在左边比基准大的两个值
int tmp; //r[i]和r[j]交换 i++ j--
tmp=arr[i];
arr[i]=arr[j];
arr[j]=tmp;
i++;
j--;
}
}
if(arr[i]>temp) { //i=j 停止 判断arr[i]和基准元素
int tmp; //若arr[i]> temp 则arr[i-1] 和arr[low] 交换
tmp=arr[i-1];
arr[i-1]=arr[low];
arr[low]=tmp;
return i-1; //返回位置i-1
}
int tmp; //若arr[i]<=temp
tmp=arr[i]; //arr[i] 和 arr[low]交换
arr[i]=arr[low];
arr[low]=tmp;
return i; //返回位置i
}
结果:
最终版本(“填坑”)
package com.duoduo.day316;
import java.util.Scanner;
public class QuickSort {
public static void main(String [] args) {
Scanner sc=new Scanner(System.in); //系统键盘录入数据
System.out.println("请先输入要排序的数据的个数:");
int N=sc.nextInt();
System.out.println("请输入要排序的数据 :");
int [] arr=new int[N];
for(int i=0;i<N;i++) {
arr[i]=sc.nextInt();
}
quickSort(arr,0,N-1); //快速排序
System.out.println("排序后的序列为:");
for(int i=0;i<N;i++)
System.out.print(arr[i]+" ");
}
/*快速排序递归算法*/
public static void quickSort(int [] arr,int low,int high) {
int mid;
if(low<high) {
mid=partition(arr,low,high); //基准位置
quickSort(arr,low,mid-1); //左子序列
quickSort(arr,mid+1,high); //右子序列
}
}
/*划分序列,找到基准元素位置*/
public static int partition(int [] arr,int low,int high) {
int i=low;
int j=high;
int temp=arr[low];
while(i<j) {
while(i<j&&arr[j]> temp) //从右往左扫描 找到比基准元素小的值为止 跳出循环
j--;
if(i<j) {
arr[i++]=arr[j]; //交换二者的值 并i++ 右移
}
while(i<j&&arr[i] <=temp) //从左往右扫描 找到比基准元素大的值为止
i++;
if(i<j) {
arr[j--]=arr[i]; //交换二者的值 并j--
}
}
arr[i]=temp; //填充基准元素
return i; //返回最终划分完成后基准元素所在的位置
}
}
分析时间复杂度:
best 最好时间复杂度:
分解: 划分函数partition () 扫描元素O(n)
解决子问题:每次都能分解为规模n/2的子问题 2T(n/2)
合并: 原地排序 无需操作 已经有序
T(n)=2T(n/2)+O(n)=O(nlogn)
空间复杂度: 辅助变量O(1) 递归调用O(logn)
worst最坏时间复杂度:
分解:O(n)
解决子问题 :T(n-1) 基准元素左(右侧)没有元素 单侧递归树
总:T(n)=T(n-1)+O(n)=O(1)+O(2)+....O(n)= O(n(n+1)/2) -----O(n的平方)
空间递归 O(n)
平均时间/空间复杂度:
k-1 基准元素位置K n-k
O(nlogn)--------------------------------O(logn)