public class QuickSort
{
private long[] arr; //要排序的數組
private int size; //初始化數組大小
private int length; //數組實際大小(即有多少個值)
public QuickSort(int size){
this.arr=new long[size];
this.size = size;
length = 0;
}
//往數組添加值
public void add(long value){
if(length < size)
arr[length++] = value;
}
//打印
public void display(){
for(int i=0; i<length; i++){
System.out.print(arr[i]+" ");
}
System.out.println(" ");
}
//簡單排序
public void sortSmall(int left, int right){
if(right-left==1){
if(arr[left]>arr[right]){
swap(left,right);
}
}
}
//交換數組兩個位置的數據
public void swap(int left, int right){
long tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
}
/**
* 比較數組的第一個,中間一個,最後一個; 將最小的 放到第一個位置,中間值放到最後位置
* 如[4,6,3,7,9],比較4,3,9 ; 3最小放第一個位置,4爲中間值放到最後的位置,結果[3,6,9,7,4]
* 最後一位的值4,作爲"中間值"
* @param left
* @param right
* @return
*/
public long setMiddle(int left, int right){
int middle = (left+right)/2;
if(arr[left]>arr[right]){
swap(left,right);
}
if(arr[left]>arr[middle]){
swap(left,middle);
}
if(arr[middle]<arr[right]){
swap(middle,right);
}
return arr[right];
}
/**
* 取數組最後一個數作爲"中間值",將數組分成比"中間值"小和比"中間值"大的兩部分
* 將"中間值"交換到兩部分數據的中間位置
* 然後對"中間值"兩邊的數組,遞歸的執行該操作...
* @param left
* @param right
*/
public void sort(int left, int right){
//遞歸執行到數組很小時(10個以內),可以選擇其他排序方式,如插入排序等 ,這裏僅僅數組大小<=2時
if(right-left<=1){
this.sortSmall(left, right);
return;
}
int leftIndex = left;
int rightIndex = right;
//比較數組的第一個,中間一個,最後一個; 取一個合適的"中間值"
long flag = this.setMiddle(left, right);
while(leftIndex<rightIndex){
//從左往右查找,遇到比"中間值"大的數停止
while(arr[++leftIndex]<flag && leftIndex<rightIndex);
//從右往左查找,遇到比"中間值"小的數停止
while(rightIndex>leftIndex && arr[--rightIndex]>=flag);
//如果查找沒有結束, 交換這個兩個數, 繼續...
if(leftIndex<rightIndex)
swap(leftIndex,rightIndex);
//如果左右指針指向了同一位置,說明查找結束, 將"中間值"交換到合適的位置
else if(leftIndex==rightIndex && arr[leftIndex]<flag){
arr[right]=arr[++leftIndex];
arr[leftIndex]=flag;
++rightIndex;
}else if(leftIndex==rightIndex && arr[leftIndex]>flag){
arr[right]=arr[leftIndex];
arr[leftIndex]=flag;
}
}
//遞歸的執行操作
if(left<leftIndex)
sort(left, leftIndex-1);
if(rightIndex<right)
sort(rightIndex+1,right);
}
public static void main(String[] args){
QuickSort sort = new QuickSort(100);
for(int i=0; i<20; i++){
sort.add((long)(Math.random()*100));
}
sort.display();
sort.sort(0, sort.length-1);
sort.display();
}
}
------------------------------------------------------------------
利用上面遞歸算法進行排序時 當排序數組較大時
會出現堆棧溢出的異常 這是以爲內遞歸調用的次數太多造成的
可以改用"棧+循環的方式 代替
遞歸調用
import java.text.SimpleDateFormat;
import java.util.Date;
public class QuickSort
{
private long[] arr; //要排序的數組
private int size; //初始化數組大小
private int length; //數組實際大小(即有多少個值)
public QuickSort(int size){
this.arr=new long[size];
this.size = size;
length = 0;
}
//往數組添加值
public void add(long value){
if(length < size)
arr[length++] = value;
}
//打印
public void display(){
for(int i=0; i<length; i++){
System.out.print(arr[i]+" ");
}
System.out.println(" ");
}
//簡單排序
public void sortSmall(int left, int right){
if(right-left==1){
if(arr[left]>arr[right]){
swap(left,right);
}
}
}
//交換數組兩個位置的數據
public void swap(int left, int right){
long tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
}
/**
* 比較數組的第一個,中間一個,最後一個; 將最小的 放到第一個位置,中間值放到最後位置
* 如[4,6,3,7,9],比較4,3,9 ; 3最小放第一個位置,4爲中間值放到最後的位置,結果[3,6,9,7,4]
* 最後一位的值4,作爲"中間值"
* @param left
* @param right
* @return
*/
public long setMiddle(int left, int right){
int middle = (left+right)/2;
if(arr[left]>arr[right]){
swap(left,right);
}
if(arr[left]>arr[middle]){
swap(left,middle);
}
if(arr[middle]<arr[right]){
swap(middle,right);
}
return arr[right];
}
/**
* 劃分操作
* -----------------------------------------------------------------------
* 取數組最後一個數作爲"中間值",將數組分成比"中間值"小和比"中間值"大的兩部分
* 將"中間值"交換到兩部分數據的中間位置
* 然後對"中間值"兩邊的數組,遞歸的執行該操作...
* @param left
* @param right
*/
public int sort(int left, int right){
//遞歸執行到數組很小時(10個以內),可以選擇其他排序方式,如插入排序等 ,這裏僅僅數組大小<=2時
if(right-left<=1){
this.sortSmall(left, right);
return 0;
}
int leftIndex = left;
int rightIndex = right;
//比較數組的第一個,中間一個,最後一個; 取一個合適的"中間值"
long flag = this.setMiddle(left, right);
while(leftIndex<rightIndex){
//從左往右查找,遇到比"中間值"大的數停止
while(arr[++leftIndex]<flag && leftIndex<rightIndex);
//從右往左查找,遇到比"中間值"小的數停止
while(rightIndex>leftIndex && arr[--rightIndex]>=flag);
//如果查找沒有結束, 交換這個兩個數, 繼續...
if(leftIndex<rightIndex)
swap(leftIndex,rightIndex);
//如果左右指針指向了同一位置,說明查找結束, 將"中間值"交換到合適的位置
else if(leftIndex==rightIndex && arr[leftIndex]<flag){
arr[right]=arr[++leftIndex];
arr[leftIndex]=flag;
++rightIndex;
}else if(leftIndex==rightIndex && arr[leftIndex]>flag){
arr[right]=arr[leftIndex];
arr[leftIndex]=flag;
}
}
//遞歸的執行操作
/*if(left<leftIndex)
sort(left, leftIndex-1);
if(rightIndex<right)
sort(rightIndex+1,right);*/
//這裏leftIndex,rightIndex最後都指向同一個位置,所以返回哪個都一樣的
return leftIndex;
}
/**
* 使用棧+循環,代替遞歸調用
*/
public void sort(){
Stack stack = new Stack();
//將要進行"劃分"部分的"開始位置"和"結束位置"壓入棧
stack.push(0);
stack.push(length-1);
while(stack.length>=2){
//從棧裏取出"開始位置"和"結束位置",進行"劃分"操作
int right = stack.pop();
int left = stack.pop();
int middle = this.sort(left, right);
//將"劃分"之後的左右兩個無序數組的起始位置 壓入棧,待處理
if(middle>0){
stack.push(left);
stack.push(middle-1);
stack.push(middle+1);
stack.push(right);
}
}
}
public static void main(String[] args){
QuickSort sort = new QuickSort(1000000);
for(int i=0; i<1000000; i++){
sort.add((long)(Math.random()*100));
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss ms");
System.out.println(sdf.format(new Date()));
sort.display();
sort.sort();
sort.display();
System.out.println(sdf.format(new Date()));
}
}