划分算法与快速排序

Posted Orlion

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了划分算法与快速排序相关的知识,希望对你有一定的参考价值。

原文链接:http://www.orlion.ga/201/

一、划分算法

1、划分

    划分是快速排序的根本机制。划分数据就是把数据分成两组,所有大于特定值的数据在一组,所有小于特定值的在一组。比如将{3,1,9,0,4,7,2,6,5,8}以特定值为5划分为{3,1,0,4,5}和{9,0,7,6,8}

2、划分算法

    划分算法由两个指针来完成,这两个指针分别指向数组的两头,左指针leftPtr向右移动而右指针rightPtr向左移动,实际上leftPtr和rightPtr初始化时是在左右边的各减一位的位置,这是因为它开始算法前它们都要分别的加一和减一。

    当leftPtr遇到比特定值小的值时它继续右移,因为这个数据项的位置已经在数组的小于特定值得一边了。当遇到比特定值大的数时,它就停下来。类似的,当rightPtr遇到比特定值大的数时就继续左移,当遇到比特定值小的数时就停下来。当都停下来的时候leftPtr和rightPtr都指向了在数组错误一方位置上的数据项,所以交换这两个数据项。交换之后,继续移动两个指针,当指向的数据项在数组的错误的一方时,再次停止然后交换数据。

3、划分算法的java描述

        // 划分算法
	public static void divide(long[] arr , int eleNum){
		
		int leftPtr = 0 , rightPtr = eleNum-1;
		int middle = 5;
		while (true) {
			while (leftPtr < eleNum && arr[leftPtr] < middle) {leftPtr++;}
			while (rightPtr > -1 && arr[rightPtr] > middle){rightPtr--;}
			
			if (leftPtr >= rightPtr){
				// 已经划分完毕
				break;
			} else {
				// 交换
				arr[leftPtr] = arr[leftPtr] ^ arr[rightPtr];
				arr[rightPtr] = arr[rightPtr] ^ arr[leftPtr];
				arr[leftPtr] = arr[leftPtr] ^ arr[rightPtr];
			}
		}
		
		System.out.println(Arrays.toString(arr));
	}

 

二、快速排序

   1、快速排序算法

    在大多数情况下,快速排序都是最快的排序算法,时间复杂度为O(N*logN)(这只是对内部排序或者说是随机存储器内的排序而言,对在磁盘文件中的数据进行排序,其他的排序算法可能会更好)。

    快速排序算法本质上通过将一个数组通过划分算法划分为两个子数组,然后递归的调用自身为每一个子数组进行快速排序来实现。对这个基本的设计进行一些加工就是快速排序算法了。

    快速排序中对划分算法中中间值(即一中描述的特定值)的指定的方法有很多种,其中对算法效率比较好的就是"三数据项取中值"方法,具体就是取数组最左边值和最右边值以及数组中间位置值这三个数据项中的中间值。(在下面的代码中用方法medianOf3()进行了描述,该方法也做了一个操作就是对这三个数据项进行了排序。

   2、快速排序代码

    封装到一个QuickSort类中:

    package ml.orlion.sort;
    
    import java.util.Arrays;
    
    public class QuickSort {
    	
    	private long[] arr;
    	
    	public QuickSort(long[] arr){
    		this.arr = arr;
    	}
    	
    	// 快速排序算法
    	public void doQuickSort(int left , int right){
    		int center = medianOf3(left , right);
    		if (0 < center && center < right - 1) {
    			int middle = divide(left , right , arr[center]);
    			// 递归对左边的子数组进行排序
    			doQuickSort(0 , middle);
    			// 递归对右边的字数组进行排序
    			doQuickSort(middle , right);
    		}
    	}
    	
    	// 划分算法
    	public int divide(int left , int right , long middle){
    		int size = right - left + 1;
    		while(true){
    			while(left < size - 1 && arr[left] < middle){
    				left++;
    			}
    			while(right > -1 && arr[right] >= middle){
    				right--;
    			}
    			if (left > right) {
    				break;
    			} else {
    				swap(left , right);
    			}
    		}
    		return right+1;
    	}
    	
    	// 三数据项取中值
    	private int medianOf3(int left , int right){
    		int center = (right+left)/2;
    		if (arr[left] > arr[center])
    			swap(left , center);
    		if (arr[left] > arr[right])
    			swap(left , right);
    		if (arr[center] > arr[right])
    			swap(center , right);
    		
    		return center;
    	}
    	
    	// 交换两个数
    	private void swap(int left , int right){
    		arr[left] = arr[left] ^ arr[right];
    		arr[right] = arr[right] ^ arr[left];
    		arr[left] = arr[left] ^ arr[right];
    	}
    	
    	public void display(){
    		System.out.println(Arrays.toString(arr));
    	}
    }

    

然后调用测试:
    long[] arr = {7,1,2,4,5,3,0,6,8,9};
    QuickSort qs = new QuickSort(arr);
    qs.doQuickSort(0, 9);
    qs.display();

以上是关于划分算法与快速排序的主要内容,如果未能解决你的问题,请参考以下文章

算法笔记 | 快速排序的代码实现和复杂度分析

Java排序算法分析与实现:快排冒泡排序选择排序插入排序归并排序

C语言快速排序算法及代码

快速排序与二分查找

快速排序算法

随机选择第k小元素随机快速排序-算法设计与分析实验四