划分算法

1 划分算法思想
2 代码实现
3 时间复杂度
4 讨论


1 划分算法思想
划分(partition)就是将数据项分成两组,一组大于某个特定的数据项,而另一组小于某个特定的数据项。在划分算法中,这个特定的数据项叫做枢纽(pivot)。
划分算法的思想是中间线代表枢纽;数据项的左端和右端分别有两个指针(leftPtr和rightPtr); leftPtr从左向右遍历元素,rightPtr从右向左遍历元素,当leftPtr遇到比枢纽元素大的元素时停止,当rightPtr遇到比枢纽元素小的元素时停止,然后将这两个元素交换位置;接下来,leftPtr继续向右遍历,rightPtr继续向左遍历,重复上面的操作;当两个指针相遇时遍历结束。



2 代码实现

  1. [java] view plaincopyprint?

  2. public static int portionIt(int[] a,int left, int right, long pivot)  
  3. {  
  4.     int leftPtr=left-1;  
  5.     int rightPtr=right+1;  
  6.     while(true)  
  7.     {  
  8.         //from left to pivot   
  9.         while(leftPtr<right && a[++leftPtr]<pivot);  
  10.         //from right to pivot   
  11.         while(rightPtr>left && a[--rightPtr]>pivot);  
  12.         //base case   
  13.         if(leftPtr>=rightPtr)  
  14.             break;  
  15.         //swap   
  16.         else  
  17.             swap(a,leftPtr,rightPtr);  
  18.     }  
  19.   
  20.     return leftPtr;  
  21. }          public static int portionIt(int[] a,int left, int right, long pivot)
  22.         {
  23.                 int leftPtr=left-1;
  24.                 int rightPtr=right+1;
  25.                 while(true)
  26.                 {
  27.                         //from left to pivot
  28.                         while(leftPtr<right && a[++leftPtr]<pivot);
  29.                         //from right to pivot
  30.                         while(rightPtr>left && a[--rightPtr]>pivot);
  31.                         //base case
  32.                         if(leftPtr>=rightPtr)
  33.                                 break;
  34.                         //swap
  35.                         else
  36.                                 swap(a,leftPtr,rightPtr);
  37.                 }

  38.                 return leftPtr;
  39.         }
复制代码




  1. [java] view plaincopyprint?

  2. private static void swap(int[] a,int left, int right)  
  3. {  
  4.     int temp=a[right];  
  5.     a[left]=a[right];  
  6.     a[right]=temp;  
  7. }          private static void swap(int[] a,int left, int right)
  8.         {
  9.                 int temp=a[right];
  10.                 a[left]=a[right];
  11.                 a[right]=temp;
  12.         }
复制代码


3 时间复杂度


算法时间复杂度O(N)
当在划分的2端有相同的数据需要比较和交换时,比较和交换各位N/2次,所以划分算法的时间复杂度为O(N)

4 讨论
4.1 为什么循环while(leftPtr<right && a[++leftPtr]<pivot)中要有leftPtr<right这个条件?  如果数组中所有元素都小于枢纽pivot的值,那么leftPtr就会从左向右遍历元素,直到右边界的右边(当leftPtr到了数组最右边时leftPtr<a.length-1,那么进入下一次循环a[++leftPtr]<pivot,此时++leftPtr=a.length,数组越界了!),这样会造成数组越界,所以要有leftPtr<right来检查是否到了数组边界。同样的道理while(rightPtr>left && a[--rightPtr]>pivot)也要有rightPtr>left来检查是否数组越界。
4.2   Delicate Code 
The code in the while loops is rather delicate. For example, you might be tempted to remove the increment operators from the inner while loops and use them to replace the nop statements. (Nop refers to a statement consisting only of a semicolon, and means no operation). For example, you might try to change this:
while(leftPtr < right && theArray[++leftPtr] < pivot); // (nop)
  to this:
  while(leftPtr < right && theArray[leftPtr] < pivot)
  ++leftPtr;
and similarly for the other inner while loop. These changes would make it possible for the initial values of the pointers to be left and right, which is somewhat clearer than left-1 and right+1. However, these changes result in the pointers being incremented only when the condition is satisfied. The pointers must move in any case, so two extra statements within the outer while loop would be required to bump the pointers. The nop version is the most efficient solution.(from《Data Structure and Algrithem in Java》)
4.3为什么循环while(leftPtr<right && a[++leftPtr]<pivot)中不是a[++leftPtr]<=pivot?
If you run the partitionIt() method on items that are all equal to the pivot value, you will find that every comparison leads to a swap. Swapping items with equal keys seems like a waste of time. The < and > operators that compare pivot with the array elements in the while loops cause the extra swapping. However, suppose you try to fix this by replacing them with <= and >= operators. This indeed prevents the swapping of equal elements, but it also causes leftPtr and rightPtr to end up at the ends of the array when the algorithm has finished. As we’ll see in the section on quicksort, it’s good for the pointers to end up in the middle of the array, and very bad for them to end up at the ends. So if partitionIt() is going to be used for quicksort, the < and > operators are the right way to go, even if they cause some unnecessary swapping.(from《Data Structure and Algrithem in Java》)
4.2 划分算法在排序中的应用
划分算法是快速排序的基础,在快速排序中关键是选择划分算法中的枢纽,选择的枢纽尽可能使划分后的2个分支(左分支和右分支)概率均等,即平均切分。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值