分而治之方法

更新时间: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=pivotkey)

--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

免责声明
隐私政策
用户协议
目录 22
0{{catalogNumber[index]}}. {{item.title}}
{{item.title}}