Java实现快速排序

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()));
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值