更新时间:2022-08-25 12:26
“分而治之”( Divide and conquer)方法(又称“分治术”) ,是有效算法设计中普遍采用的一种技术。
分而治之方法与软件设计的模块化方法非常相似。为了解决一个大的问题,可以:
1) 把它分成两个或多个更小的问题;
2) 分别解决每个小问题;
3) 把各小问题的解答组合起来,即可得到原问题的解答。小问题通常与原问题相似,可以递归地使用分而治之策略来解决。分而治之方法可以用于实现不同的排序方法,这里介绍两种排序法:快速排序(quick sort)和归并排序。
在快速排序中,n 个元素被分成三段(组):左段left,右段right 和中段middle。中段仅包含一个元素。左段中各元素都小于等于中段元素,右段中各元素都大于等于中段元素。因此left 和right 中的元素可以独立排序,并且不必对left 和right 的排序结果进行合并。middle 中的元素被称为支点( pivot )。下面给出快速排序的伪代码。
使用快速排序方法对a [ 0 : n- 1 ] 排序。
从a [ 0 : n- 1 ] 中选择一个元素作为middle,该元素为支点把余下的元素分割为两段left 和right,使得left中的元素都小于等于支点,而right 中的元素都大于等于支点。
递归地使用快速排序方法对left 进行排序。
递归地使用快速排序方法对right 进行排序。
所得结果为left + middle + right。
考察元素序列[ 4 , 8 , 3 , 7 , 1 , 5 , 6 , 2 ]。
假设选择元素6 作为支点,则6 位于middle;4,3,1,5,2 位于l e f t;8,7 位于right。当left 排好序后,所得结果为1,2,3,4,5;当right 排好序后,所得结果为7,8。把right 中的元素放在支点元素之后,left 中的元素放在支点元素之前,即可得到最终的结果[ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 ]。
把元素序列划分为left、middle 和right 可以就地进行。在程序1 中,支点总是取位置1 中的元素。也可以采用其他选择方式来提高排序性能。
程序1:快速排序
#define MAXSIZE 20
typedef int KeyType;
typedef struct {
KeyType key;
InfoType otherinfo;
} RedType;
typedef struct {
RedType r [MAXSIZE+1];
int length;
} SqList;
int Partition (SqList &L, int low, int high) {
L.r [0] =L.r [low];
Pivotkey=L.r [low] .key;
While (low While (low --high; L.r [low] =L.r [high]; While (low +low; L.r [high] =L.r [low]; } L.r [low] =L.r [0]; Return low; } void Qsort (SqList &L, int low, int high) { if (low pivotloc=Partition (L, low, high); QSort (L, low, pivotloc-1); Qsort (L, pivotloc+1, high); } } void QuickSort (SqList &L) { Qsort (L, 1, L.length); } 用求顺序统计量问题最能说明“分治术” 算法设计思想,所谓顺序统计问题是“从有n个元素的序列中选出第k个最小元素”,解此问题最容易想到的办法是:将这n个元素按从小到大顺序排序,然后从排序后的序列中先取第k个元素,即为本问题的解,而排序n个元素最快的排序算法平均需要进行。o(nlogn)次比较,即用排序方法求顺序统计量问题的期望时间复杂性为o(nlogn)。通过仔细分析,使用“分而治之”的思想,我们可以找到一个时间耗费为o(n)算法,其算法如下: Procedure Select(S,K) Begin if|S|<50 Then begin 将S从小到大排序; Return S 的k 个元素; end Eles begin 把S分为各有5个元素的[|S|/5]个子序列; 如果有剩余元素,则将剩余元素作为最后一个子序列; 将每个有5个元素的子序列排序; 设M是所有5——元素的自序列的中值序列; U<-Select(M,[M/2]); 设S1、S2、S3是S的分别小于、等于和大于U的元素序列 if|S|>=k Then Return Select(S1,k) Eles if(|S1|+|S2|>=k) Then Return u Eles Return Select(S3,k-|S1|-|S2|) End