快速排序
快速排序是冒泡排序的改进版,是目前已知的最快的排序方法。
已知一组无序数据a[1]、a[2]、……a[n],需将其按升序排列。首先任取数据a[x]作为基准(pivot)。比较a[x]与其它数据并排序,使a[x]排在数据的第k位,并且使a[1]~a[k-1]中的每一个数据<a[x],a[k+1]~a[n]中的每一个数据>a[x],然后采用分治的策略分别对a[1]~a[k-1]和a[k+1]~a[n]两组数据进行快速排序。
基本思想:
1、首先选取以及基准(pivot),这里选取数组最右侧的元素
2、将数组中比基数小的元素放在数组的左边,将数组中比基准大的元素放在基准的右边。具体的方法是设置两个扫描指针leftPtr和rightPtr。leftPtr指向数组的第一个元素的前一个位置,rightPtr指向数组倒数第一个元素。leftPtr向右扫描比基准(pivot)大的元素,leftPtr右移,rightPtr向左扫描比左准(pivot)小的元素,rightPtr左移,同时交换leftScan扫描到的比基准(pivot)大的元素和rightScan扫描到的比基准(pivot)小的元素。直到leftScan与rightScan相遇,一次分组完成。
3、依次对两组数组进行快速排序。
public class quickSort {
public static void main(String[] args)
{
int maxSize=100;
ArrayPar arr;
arr=new ArrayPar(maxSize);
arr.insert(77);
arr.insert(99);
arr.insert(44);
arr.insert(55);
arr.insert(22);
arr.insert(88);
arr.insert(11);
arr.insert(00);
arr.insert(66);
arr.insert(33);
arr.display();
arr.quickSort();
arr.display();
}
}
class ArrayPar
{
private int[] a;
private int nElems;
//构造函数
public ArrayPar(int max)
{
a=newint[max];
nElems=0;
}
//插入数据
public void insert(int value)
{
a[nElems]=value;
nElems++;
}
//显示数组数据
public void display()
{
for(int j=0;j<nElems;j++)
System.out.println(a[j]+" ");
System.out.println(" ");
}
//交换元素
public void swap(int one,int two)
{
int temp=a[one];
a[one]=a[two];
a[two]=temp;
}
//分组
public void reQuickSort(int left,int right)
{
if(right-left<=0)
return;
else
{
int pivot=a[right];
intpartition=partitionIt(left,right,pivot);
reQuickSort(left,partition-1);
reQuickSort(partition+1,right);
}
}
public void quickSort()
{
reQuickSort(0,nElems-1);
}
//分组
public int partitionIt(int left,int right,int pivot)
{
int leftPtr=left-1;
int rightPtr=right;
while(true)
{
while(a[++leftPtr]<pivot);
while(rightPtr>0&&a[--rightPtr]>pivot);
if(leftPtr>=rightPtr)
break;
else
swap(leftPtr,rightPtr);
}
swap(leftPtr,right);
return leftPtr;
}
}
分析快速排序分析:
第一次分组过程:(直到数组的leftPtr>=rightPtr,第一次分组过程结束)
原数组: 77 99 44 55 22 88 11 066 33 基准选最后一个元素 33
leftPtr=-1往右找比33大的数 往右找比33小的数rightPtr=9
找第一个比基准33大的元素和第一个比基准33小的元素
77 99 44 55 22 88 11 0 66 33 基准选最后一个元素 33
leftPtr=0往右找比33大的数 往右找比33小的数rightPtr=7
第一次交换后的数组:
0 99 4455 22 88 11 77 66 33
leftPtr=0 rightPtr=7
找第二个比基准33大的元素和第二个比基准33小的元素
0 99 44 55 22 88 11 77 66 33 基准选最后一个元素 33
leftPtr=1 rightPtr=6
第二次交换后的数组:
0 11 4455 22 88 99 77 66 33
leftPtr=1 rightPtr=6
找第三个比基准33大的元素和第二个比基准33小的元素
0 99 44 55 22 88 11 77 66 33 基准选最后一个元素 33
leftPtr=2 rightPtr=4
第三次交换后的数组:
0 11 22 55 44 88 99 77 66 33
leftPtr=2 rightPtr=4
找第四个比基准33大的元素和第四个比基准33小的元素
0 11 22 55 44 88 99 77 66 33 基准选最后一个元素 33
rightPtr=2 leftPtr=3
此时rightPtr<leftPtr,将leftPtr所指元素与基准交换位置,得到第一次的分组,第一次分组结束。
第一次分组后的数组:
0 11 22 33 44 88 99 77 66 55
一般情况下,快速排序的效率为:o(N*logN),是目前最快的排序算法。但是,当将本方法运用到完全逆序的数组排序时,效率降到了o(N*N)。
改进如下:
public class quickSort {
public static void main(String[] args)
{
int maxSize=100;
ArrayPar arr;
arr=new ArrayPar(maxSize);
arr.insert(77);
arr.insert(99);
arr.insert(44);
arr.insert(55);
arr.insert(22);
arr.insert(88);
arr.insert(11);
arr.insert(00);
arr.insert(66);
arr.insert(33);
arr.display();
arr.quickSort();
arr.display();
}
}
class ArrayPar
{
private int[] a;
private int nElems;
//构造函数
public ArrayPar(int max)
{
a=new int[max];
nElems=0;
}
//插入数据
public void insert(int value)
{
a[nElems]=value;
nElems++;
}
//显示数组数据
public void display()
{
for(int j=0;j<nElems;j++)
System.out.println(a[j]+" ");
System.out.println(" ");
}
//交换元素
public void swap(int one,int two)
{
int temp=a[one];
a[one]=a[two];
a[two]=temp;
}
//找出中间值作为基准
public int medianOf3(int left,int right)
{
int center=(left+right)/2;
if(a[left]>a[center])
swap(left,center);
if(a[left]>a[right])
swap(left,right);
if(a[center]>a[right])
swap(center,right);
swap(center,right-1);
return a[right-1];
}
public void manualSort(int left,int right)
{
int size=right-left+1;
if(size<=1)
return;
if(size==2)
{
if(a[left]<a[right])
swap(left,right);
return;
}
else
{
if(a[left]>a[right-1])
swap(left,right-1);
if(a[right-1]>a[right])
swap(right,right-1);
if(a[left]>a[right])
swap(left,right);
}
}
//分组
public void reQuickSort(int left,int right)
{
int size=right-left+1;
if(size<=3)
manualSort(left,right); //数组小进行手动排序
else //数组大进行快速排序
{
int median=medianOf3(left,right);
int partition=partitionIt(left,right,median);
reQuickSort(left,partition-1);
reQuickSort(partition+1,right);
}
}
public void quickSort()
{
reQuickSort(0,nElems-1);
}
public int partitionIt(int left,int right,int pivot)
{
int leftPtr=left;
int rightPtr=right-1;
while(true)
{
while(a[++leftPtr]<pivot);
while(rightPtr>0&&a[--rightPtr]>pivot);
if(leftPtr>=rightPtr)
break;
else
swap(leftPtr,rightPtr);
}
swap(leftPtr,right-1);
return leftPtr;
}
}