您的位置:首页 > 理论基础 > 数据结构算法

快速排序(方式一)

2017-01-17 00:00 127 查看

快速排序

毫无疑问,快速排序是最流行的排序算法,因为有充足的理由,在大多数情况下,快速排序都是最快的,执行时间为O(N*logN)级,(这只是对内部排序或者说随机存储器内的排序而言,对于磁盘文件中的数据进行的排序,其他的排序算法可能更好)。

快速排序算法本质上通过把一个数组划分为两个子数组,然后递归的调用自身为每个子数组进行快速排序实现的。但是对这个基本的设计还需要进一步加工,算法还必须要选择枢纽以及对小的划分区域进行排序。

快速排序算法基本有三个步骤:

1、把数组或者子数组划分成左边(较小的关键字)的一组和右边(较大的关键字)的一组。

2、调用自身对左边的一组进行划分排序。

3、再次调用自身对右边的一组进行划分排序。

经过一次划分以后,所有左边子数组的数据项都小雨右边子数组的数据项,只要对左边子数组和右边数组分辨进行排序,整个数组就是有序的了,对子数组进行排序用递归调用排序算法自身即可。

在本例中选择最右边的数作为枢纽基值。

以下是实现代码(方式一):

// quickSort1.java
// demonstrates simple version of quick sort
// to run this program: C>java QuickSort1App
////////////////////////////////////////////////////////////////
class ArrayIns
{
private long[] theArray;          // ref to array theArray
private int nElems;               // number of data items
//--------------------------------------------------------------
public ArrayIns(int max)          // constructor
{
theArray = new long[max];      // create the array
nElems = 0;                    // no items yet
}
//--------------------------------------------------------------
public void insert(long value)    // put element into array
{
theArray[nElems] = value;      // insert it
nElems++;                      // increment size
}
//--------------------------------------------------------------
public void display()             // displays array contents
{
System.out.print("A=");
for(int j=0; j<nElems; j++)    // for each element,
System.out.print(theArray[j] + " ");  // display it
System.out.println("");
}
//--------------------------------------------------------------
public void quickSort()
{
recQuickSort(0, nElems-1);
}
//--------------------------------------------------------------
public void recQuickSort(int left, int right)
{
if(right-left <= 0)              // if size <= 1,
return;                      //    already sorted
else                             // size is 2 or larger
{
long pivot = theArray[right];      // rightmost item
// partition range
int partition = partitionIt(left, right, pivot);
recQuickSort(left, partition-1);   // sort left side
recQuickSort(partition+1, right);  // sort right side
}
}  // end recQuickSort()
//--------------------------------------------------------------
public int partitionIt(int left, int right, long pivot)
{
int leftPtr = left-1;           // left    (after ++)
int rightPtr = right;           // right-1 (after --)
while(true)
{                            // find bigger item
while( theArray[+
3ff0
+leftPtr] < pivot )
;  // (nop)
// find smaller item
while(rightPtr > 0 && theArray[--rightPtr] > pivot)
;  // (nop)

if(leftPtr >= rightPtr)      // if pointers cross,
break;                    //    partition done
else                         // not crossed, so
swap(leftPtr, rightPtr);  //    swap elements
}  // end while(true)
swap(leftPtr, right);           // restore pivot
return leftPtr;                 // return pivot location
}  // end partitionIt()
//--------------------------------------------------------------
public void swap(int dex1, int dex2)  // swap two elements
{
long temp = theArray[dex1];        // A into temp
theArray[dex1] = theArray[dex2];   // B into A
theArray[dex2] = temp;             // temp into B
}  // end swap(
//--------------------------------------------------------------
}  // end class ArrayIns
////////////////////////////////////////////////////////////////
class QuickSort1App
{
public static void main(String[] args)
{
int maxSize = 16;             // array size
ArrayIns arr;
arr = new ArrayIns(maxSize);  // create array

for(int j=0; j<maxSize; j++)  // fill array with
{                          // random numbers
long n = (int)(java.lang.Math.random()*99);
arr.insert(n);
}
arr.display();                // display items
arr.quickSort();              // quicksort them
arr.display();                // display them again
}  // end main()
}  // end class QuickSort1App

选择枢纽的第二种方法(左中右三数据项取中):

以下是实现代码:

// quickSort2.java
// demonstrates quick sort with median-of-three partitioning
// to run this program: C>java QuickSort2App
////////////////////////////////////////////////////////////////
class ArrayIns
{
private long[] theArray;          // ref to array theArray
private int nElems;               // number of data items
//--------------------------------------------------------------
public ArrayIns(int max)          // constructor
{
theArray = new long[max];      // create the array
nElems = 0;                    // no items yet
}
//--------------------------------------------------------------
public void insert(long value)    // put element into array
{
theArray[nElems] = value;      // insert it
nElems++;                      // increment size
}
//--------------------------------------------------------------
public void display()             // displays array contents
{
System.out.print("A=");
for(int j=0; j<nElems; j++)    // for each element,
System.out.print(theArray[j] + " ");  // display it
System.out.println("");
}
//--------------------------------------------------------------
public void quickSort()
{
recQuickSort(0, nElems-1);
}
//--------------------------------------------------------------
public void recQuickSort(int left, int right)
{
int size = right-left+1;
if(size <= 3)                  // manual sort if small
manualSort(left, right);
else                           // quicksort if large
{
long median = medianOf3(left, right);
int partition = partitionIt(left, right, median);
recQuickSort(left, partition-1);
recQuickSort(partition+1, right);
}
}  // end recQuickSort()
//--------------------------------------------------------------
public long medianOf3(int left, int right)
{
int center = (left+right)/2;
// order left & center
if( theArray[left] > theArray[center] )
swap(left, center);
// order left & right
if( theArray[left] > theArray[right] )
swap(left, right);
// order center & right
if( theArray[center] > theArray[right] )
swap(center, right);

swap(center, right-1);             // put pivot on right
return theArray[right-1];          // return median value
}  // end medianOf3()
//--------------------------------------------------------------
public void swap(int dex1, int dex2)  // swap two elements
{
long temp = theArray[dex1];        // A into temp
theArray[dex1] = theArray[dex2];   // B into A
theArray[dex2] = temp;             // temp into B
}  // end swap(
//--------------------------------------------------------------
public int partitionIt(int left, int right, long pivot)
{
int leftPtr = left;             // right of first elem
int rightPtr = right - 1;       // left of pivot

while(true)
{
while( theArray[++leftPtr] < pivot )  // find bigger
;                                  //    (nop)
while( theArray[--rightPtr] > pivot ) // find smaller
;                                  //    (nop)
if(leftPtr >= rightPtr)      // if pointers cross,
break;                    //    partition done
else                         // not crossed, so
swap(leftPtr, rightPtr);  // swap elements
}  // end while(true)
swap(leftPtr, right-1);         // restore pivot
return leftPtr;                 // return pivot location
}  // end partitionIt()
//--------------------------------------------------------------
public void manualSort(int left, int right)
{
int size = right-left+1;
if(size <= 1)
return;         // no sort necessary
if(size == 2)
{               // 2-sort left and right
if( theArray[left] > theArray[right] )
swap(left, right);
return;
}
else               // size is 3
{               // 3-sort left, center, & right
if( theArray[left] > theArray[right-1] )
swap(left, right-1);                // left, center
if( theArray[left] > theArray[right] )
swap(left, right);                  // left, right
if( theArray[right-1] > theArray[right] )
swap(right-1, right);               // center, right
}
}  // end manualSort()
//--------------------------------------------------------------
}  // end class ArrayIns
////////////////////////////////////////////////////////////////
class QuickSort2App
{
public static void main(String[] args)
{
int maxSize = 16;             // array size
ArrayIns arr;                 // reference to array
arr = new ArrayIns(maxSize);  // create the array

for(int j=0; j<maxSize; j++)  // fill array with
{                          // random numbers
long n = (int)(java.lang.Math.random()*99);
arr.insert(n);
}
arr.display();                // display items
arr.quickSort();              // quicksort them
arr.display();                // display them again
}  // end main()
}  // end class QuickSort2App

以上算法是以3为界限划分的,如果是三个数时就不用快速排序了,否则用快速排序,以下又是一种如果数少的话用插入排序,如果数多的话用快速排序算法,是两种排序算法的组合使用。

下面是java代码:

// quickSort3.java
// demonstrates quick sort; uses insertion sort for cleanup
// to run this program: C>java QuickSort3App
////////////////////////////////////////////////////////////////
class ArrayIns
{
private long[] theArray;          // ref to array theArray
private int nElems;               // number of data items
//--------------------------------------------------------------
public ArrayIns(int max)          // constructor
{
theArray = new long[max];      // create the array
nElems = 0;                    // no items yet
}
//--------------------------------------------------------------
public void insert(long value)    // put element into array
{
theArray[nElems] = value;      // insert it
nElems++;                      // increment size
}
//--------------------------------------------------------------
public void display()             // displays array contents
{
System.out.print("A=");
for(int j=0; j<nElems; j++)    // for each element,
System.out.print(theArray[j] + " ");  // display it
System.out.println("");
}
//--------------------------------------------------------------
public void quickSort()
{
recQuickSort(0, nElems-1);
// insertionSort(0, nElems-1); // the other option
}
//--------------------------------------------------------------
public void recQuickSort(int left, int right)
{
int size = right-left+1;
if(size < 10)                   // insertion sort if small
insertionSort(left, right);
else                            // quicksort if large
{
long median = medianOf3(left, right);
int partition = partitionIt(left, right, median);
recQuickSort(left, partition-1);
recQuickSort(partition+1, right);
}
}  // end recQuickSort()
//--------------------------------------------------------------
public long medianOf3(int left, int right)
{
int center = (left+right)/2;
// order left & center
if( theArray[left] > theArray[center] )
swap(left, center);
// order left & right
if( theArray[left] > theArray[right] )
swap(left, right);
// order center & right
if( theArray[center] > theArray[right] )
swap(center, right);

swap(center, right-1);           // put pivot on right
return theArray[right-1];        // return median value
}  // end medianOf3()
//--------------------------------------------------------------
public void swap(int dex1, int dex2)  // swap two elements
{
long temp = theArray[dex1];        // A into temp
theArray[dex1] = theArray[dex2];   // B into A
theArray[dex2] = temp;             // temp into B
}  // end swap(
//--------------------------------------------------------------
public int partitionIt(int left, int right, long pivot)
{
int leftPtr = left;             // right of first elem
int rightPtr = right - 1;       // left of pivot
while(true)
{
while( theArray[++leftPtr] < pivot )  // find bigger
;                                  // (nop)
while( theArray[--rightPtr] > pivot ) // find smaller
;                                  // (nop)
if(leftPtr >= rightPtr)      // if pointers cross,
break;                    //    partition done
else                         // not crossed, so
swap(leftPtr, rightPtr);  // swap elements
}  // end while(true)
swap(leftPtr, right-1);         // restore pivot
return leftPtr;                 // return pivot location
}  // end partitionIt()
//--------------------------------------------------------------
// insertion sort
public void insertionSort(int left, int right)
{
int in, out;
//  sorted on left of out
for(out=left+1; out<=right; out++)
{
long temp = theArray[out];    // remove marked item
in = out;                     // start shifts at out
// until one is smaller,
while(in>left && theArray[in-1] >= temp)
{
theArray[in] = theArray[in-1]; // shift item to right
--in;                      // go left one position
}
theArray[in] = temp;          // insert marked item
}  // end for
}  // end insertionSort()
//--------------------------------------------------------------
}  // end class ArrayIns
////////////////////////////////////////////////////////////////
class QuickSort3App
{
public static void main(String[] args)
{
int maxSize = 16;             // array size
ArrayIns arr;                 // reference to array
arr = new ArrayIns(maxSize);  // create the array

for(int j=0; j<maxSize; j++)  // fill array with
{                          // random numbers
long n = (int)(java.lang.Math.random()*99);
arr.insert(n);
}
arr.display();                // display items
arr.quickSort();              // quicksort them
arr.display();                // display them again
}  // end main()
}  // end class QuickSort3App

消除递归:对于现在的系统来说,消除递归所带来的改进并不是很明显,因为现在的系统可以更为有效的处理方法调用。

快速排序的效率

快速排序的时间复杂度为O(N*logN),对于分治算法来说都是这样的,在分治算法中用递归的方法把一列数据项分为两组,然后调用自身来分别处理每一组数据项,在这种情况下,算法实际上是以2为底的,运行时间和N*log2N成正比。

以上所述快速排序是用递归实现的,根据排序代码的思路来说,排序方法是:选择数组最右端的数位枢纽基数,然后从最左边开始用第一个数和枢纽相比,若比枢纽数小则继续向右走,用第二个数和枢纽比较,直到有一个数比枢纽数大时停下来,记住此时概数的下标为m,然后用倒数第二个数(倒数第一个数是枢纽)和枢纽比较,若比枢纽大则继续向左,用倒数第三个数和枢纽比较,直到有一个数比枢纽数小则停下来,记住该数的下标为n,假设数组名为array,此时用array[m]和array
交换,然后再继续刚才的比较步骤,左边的指针(此处指针并不是C++中的指针,次数只是标记的意思)继续向右,右边的指针继续向左,直至两个指针相碰或者相交,就停止,然后把左边的指针的指向的值(这个值总是比枢纽值大的第一个数)跟枢纽值交换,枢纽值就归位了,此时一趟排序完成,枢纽的左边和右边在按照刚才的步骤进行排序。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息