java实现--交换排序

           很多人第一次接触的排序都是冒泡排序。

       上代码:

 

/**
	 * @Title: bubble
	 * @Description: TODO(冒泡排序)
	 * @param @param is 设定文件
	 * @return void 返回类型
	 */
	private static void bubble(int[] is) {
		boolean isChange = true;
		for (int i = 0; i < is.length && isChange; i++) {
			isChange = false;
			for (int j = is.length - 1; j > i; j--) {
				if (is[j] < is[j - 1]) {
					swap(is, j, j - 1);
					isChange = true;
				}
			}
		}
	}

 

private static void swap(int[] is, int i, int j) {
		is[i] = is[i] + is[j];
		is[j] = is[i] - is[j];
		is[i] = is[i] - is[j];
	}

 冒泡排序1000000个元素的int数组,耗时接近半小时。。。

 

 

程序执行了1636590毫秒  

 已经排好序的数组倒是超快的。。   1000万的数组,毫秒级搞定。

 

逆序。。。 没试。。   应该比乱序只高不低的。。。  有兴趣的可以试试

总结就是:   别用冒泡了。。

主函数:

/**
	 * @Title: main
	 * @Description: TODO(这里用一句话描述这个方法的作用)
	 * @param @param args 设定文件
	 * @return void 返回类型
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int[] is = new int[MAX];
		for (int i = 0; i < MAX; i++) {
			is[i] = new Random().nextInt(MAX);
//			 is[i] = i;
			// is[i] = MAX - i;
		}
//		 System.out.println(Arrays.toString(is));
		long start = System.currentTimeMillis();

		quickSort(is,0,is.length - 1);

		long end = System.currentTimeMillis();
//		 System.out.println(Arrays.toString(is));
		System.out.println("程序执行了" + (end - start) + "毫秒");
	}

 

 

接下来是重点:快排。

上代码:

 

/**
	 * 快排核心,选择基准并进行依次排列,并获取排序后基准所在位置
	 * 两个指针,left在最左边,right在最右边,left++,right--,当右边有大于基准的数或左边有大于基准的数时,交换
	 * 直到两个指针相遇,复杂度为O(right - left)
	 */
	private static int getMid(int[] is, int left, int right) {
		int temp = is[left]; // 基准
		while (left < right) {
			while (left < right && is[right] >= temp) {
				right--;
			}
			is[left] = is[right];
			while (left < right && is[left] <= temp) {
				left++;
			}
			is[right] = is[left];
		}
		is[left] = temp;
		return left;
	}

 

/**
	 * 快排核心,选择基准并进行依次排列,并获取排序后基准所在位置
	 * 两个指针,left在最左边,right在最右边,left++,right--,当右边有大于基准的数或左边有大于基准的数时,交换
	 * 直到两个指针相遇,复杂度为O(right - left)
	 */
	private static int getMid(int[] is, int left, int right) {
//		System.out.println("-----------------开始一次快排的排列---------");
//		System.out.println("排序前的数组为:"+Arrays.toString(is)+"\r\n");
//		System.out.println("这次排序以第"+(left + 1)+"个数"+is[left]+"为基准和开始,以第"+(right+1)+"个数"+is[right]+"为结束");
//		System.out.println("本次排列需要排列的分数组为:");
//		int row = left;
//		int hight = right;
//		print(is,row,hight);
		int temp = is[left]; // 基准
		while (left < right) {
			while (left < right && is[right] >= temp) {
				right--;
			}
			is[left] = is[right];
			while (left < right && is[left] <= temp) {
				left++;
			}
			is[right] = is[left];
		}
		is[left] = temp;
//		System.out.println("本次排列结束后分数组为:");
//		print(is,row,hight);
//		System.out.println("本次排列结束后整个数组为:");
//		System.out.println(Arrays.toString(is));
//		System.out.println("-------------------本次排列结束,本次排列中,比"+temp+"大的数换到它右边,比它小的数到它左边,"+temp+"被换到了第"+(left+1)+"个位置");
		return left;
	}

 下面是排列10个随机数,快排的过程:

 

 

[5, 3, 2, 2, 0, 5, 0, 1, 4, 5]
-----------------开始一次快排的排列---------
排序前的数组为:[5, 3, 2, 2, 0, 5, 0, 1, 4, 5]

这次排序以第1个数5为基准和开始,以第10个数5为结束
本次排列需要排列的分数组为:
5 3 2 2 0 5 0 1 4 5 
本次排列结束后分数组为:
4 3 2 2 0 5 0 1 5 5 
本次排列结束后整个数组为:
[4, 3, 2, 2, 0, 5, 0, 1, 5, 5]
-------------------本次排列结束,本次排列中,比5大的数换到它右边,比它小的数到它左边,5被换到了第9个位置
-----------------开始一次快排的排列---------
排序前的数组为:[4, 3, 2, 2, 0, 5, 0, 1, 5, 5]

这次排序以第1个数4为基准和开始,以第8个数1为结束
本次排列需要排列的分数组为:
4 3 2 2 0 5 0 1 
本次排列结束后分数组为:
1 3 2 2 0 0 4 5 
本次排列结束后整个数组为:
[1, 3, 2, 2, 0, 0, 4, 5, 5, 5]
-------------------本次排列结束,本次排列中,比4大的数换到它右边,比它小的数到它左边,4被换到了第7个位置
-----------------开始一次快排的排列---------
排序前的数组为:[1, 3, 2, 2, 0, 0, 4, 5, 5, 5]

这次排序以第1个数1为基准和开始,以第6个数0为结束
本次排列需要排列的分数组为:
1 3 2 2 0 0 
本次排列结束后分数组为:
0 0 1 2 2 3 
本次排列结束后整个数组为:
[0, 0, 1, 2, 2, 3, 4, 5, 5, 5]
-------------------本次排列结束,本次排列中,比1大的数换到它右边,比它小的数到它左边,1被换到了第3个位置
-----------------开始一次快排的排列---------
排序前的数组为:[0, 0, 1, 2, 2, 3, 4, 5, 5, 5]

这次排序以第1个数0为基准和开始,以第2个数0为结束
本次排列需要排列的分数组为:
0 0 
本次排列结束后分数组为:
0 0 
本次排列结束后整个数组为:
[0, 0, 1, 2, 2, 3, 4, 5, 5, 5]
-------------------本次排列结束,本次排列中,比0大的数换到它右边,比它小的数到它左边,0被换到了第1个位置
-----------------开始一次快排的排列---------
排序前的数组为:[0, 0, 1, 2, 2, 3, 4, 5, 5, 5]

这次排序以第4个数2为基准和开始,以第6个数3为结束
本次排列需要排列的分数组为:
2 2 3 
本次排列结束后分数组为:
2 2 3 
本次排列结束后整个数组为:
[0, 0, 1, 2, 2, 3, 4, 5, 5, 5]
-------------------本次排列结束,本次排列中,比2大的数换到它右边,比它小的数到它左边,2被换到了第4个位置
-----------------开始一次快排的排列---------
排序前的数组为:[0, 0, 1, 2, 2, 3, 4, 5, 5, 5]

这次排序以第5个数2为基准和开始,以第6个数3为结束
本次排列需要排列的分数组为:
2 3 
本次排列结束后分数组为:
2 3 
本次排列结束后整个数组为:
[0, 0, 1, 2, 2, 3, 4, 5, 5, 5]
-------------------本次排列结束,本次排列中,比2大的数换到它右边,比它小的数到它左边,2被换到了第5个位置
[0, 0, 1, 2, 2, 3, 4, 5, 5, 5]
程序执行了2毫秒

     接下来,就是看快排效率的时候了。前面实验了希尔排序,1000000个int数组的耗时分别为:

 

      乱序:  209毫秒      顺序:  66毫秒       逆序    82毫秒

      快排相同数据,乱序的结果:

 

程序执行了123毫秒

 顺序的时候,栈溢出了。。。

 

实现一下快排序的非递归:

 

/**  
	* @Title: quickSort  
	* @Description: TODO(快排的非递归实现)  
	* 类似递归,主要是利用堆栈保存还未排序的数组信息
	* @param @param a    设定文件  
	* @return void    返回类型   
	*/
	private static void quickSort(int a[]) {
		//堆栈,保存排列信息
		Stack<Integer> index = new Stack<Integer>();
		int start = 0;
		int end = a.length - 1;
		int mid;

		index.push(start);
		index.push(end);

		while (!index.isEmpty()) {
			end = index.pop();
			start = index.pop();
			mid = getMid(a, start, end);
			if (start < mid - 1) {
				index.push(start);
				index.push(mid - 1);
			}
			if (end > mid + 1) {
				index.push(mid + 1);
				index.push(end);
			}
		}
	}

 结果为

程序执行了268420毫秒

 逆序和顺序类似。

 

可以看到快排特别不适合已经基本有序的对象排序。

      记得在刚学排序算法的时候,书上说快排是现有的最好的排序算法。今天的实验也说明快排在乱序中,是优于希尔排序的。

      而且,快排有两个特点:

     其一是可以排列一个数组中任意两个位置中间的数。比如数组[0, 9, 3, 1, 5, 7, 6, 2, 7, 3]  排列这个数组第3个数到第5个数,结果为:[0, 9, 1, 3, 5, 7, 6, 2, 7, 3]。这种需求很少见,但是如果看见了应该能想到快排。

     还有一个特点就是快排在排列任意两个位置之间的数列时,对其他数列是没有影响的。所以快排很适合利用多线程优化它。

      比如说,快排一亿个数,可以分成10个线程,第一个线程快排第1个到第一千万个数,第二个线程快排第一千万到两千万之间的数。

 

 

你可能感兴趣的:(排序算法,快排)