Blog·Tanky WooABOUTRSS

随机化算法(3) — 舍伍德(Sherwood)算法

08 Dec 2010
这篇博客是从旧博客 WordPress 迁移过来,内容可能存在转换异常。

已出连载:

1.《随机化算法(1) — 随机数》

2.《随机化算法(2) — 数值概率算法》

正文:

这一章怎么说呢,我个人感觉不好理解,在网上查了一些资料,没发现有具体对舍伍德算法的介绍。

迄今为止看的最全面的就是王晓东的《计算机算法设计与分析》里讲的了。在网上查的一些资料也基本全和这本书上讲的一样,至于是这本书先写的,还是其他位置先写的,我就不做评论了。

(有时间我把那本书上讲舍伍德的一段给拍下来放到文章里)

书上对舍伍德讲的比较详细,但是不太好理解,一定要多看几遍。

我这里只说下他的基本思想:在一般输入数据的程序里,输入多多少少会影响到算法的计算复杂度。这时可用舍伍德算法消除算法所需计算时间与输入实例间的这种联系。

联系例子,在快速排序中,我们是以第一个元素为基准开始排序时,为了避免这样的情况,可以用舍伍德算法解决,也就是使第一个基准元素是随机的。

事先说明下:以后章节,若在代码中头文件里包含了RandomNumber.h头文件,请查看前面写的《概率算法(1) — 随机数》里的伪随机数类RandomNumber.我以后不再提醒。

这是一个非递归版的舍伍德快速排序算法:

/*
* Author: Tanky woo
* Blog:   www.WuTianQi.com
* Date:   2010.12.8
* 舍伍德(Sherwood)算法运用(1) -- 线性时间选择算法
* 代码来至王晓东《计算机算法设计与分析》
*/

#include "RandomNumber.h"
#include 
#include 
#include 
using namespace std;
const int INF = 9999;

// 交换a, b的值
template 
void Swap(Type &a;, Type &b;)
{
    Type temp;
    temp = a;
    a = b;
    b = temp;
}

template 
Type select(Type a[], int lt, int rt, int k)
{
    // 计算a[lt:rt]中第k小元素
    static RandomNumber rnd;
    while(true)
    {
        if(lt > rt)
            return a[lt];
        int i = lt, j = lt+rnd.Random(rt-lt+1);   // 随机选择的划分基准
        Swap(a[i], a[j]);
        j = rt+1;
        Type pivot = a[lt];
        //以划分基准为轴作元素交换
        while(true)
        {
            while(a[++i] < pivot);
            while(a[--j] > pivot);
            if(i >= j)
                break;
            Swap(a[i], a[j]);
        }
        if(j - lt + 1 == k)
            return pivot;
        a[lt] = a[j];
        a[j] = pivot;
        // 对子数组重复划分过程
        if(j - lt + 1 < k)
            {
                k = k - j + lt - 1;
                lt = j + 1;
            }
        else
            rt = j - 1;
    }
}

template 
Type Select(Type a[], int n, int k)
{
    // 计算a[0: n-1]中第k小元素
    // 假设a[n]是一个键值无穷大的元素
    if(k < 1 || k > n)
        cerr << "Wrong!" << endl;
    return select(a, 0, n-1, k);
}

int main()
{
    int arr[7] = {3, 2, 5, 7, 10, INF};
    cout << Select(arr, 6, 4) << endl;
}

当然,舍伍德算法也不是万能的。有时也会遇到这样的情况,即所给的确定性算法无法直接改造成舍伍德型算法。此时可借助于随机预处理技术,不改变原有的确定性算法,仅对其输入进行随机洗牌,同样可收到舍伍德算法的效果。

以下是随机洗牌算法

/*
* Author: Tanky woo
* Blog:   www.WuTianQi.com
* Date:   2010.12.8
* 和舍伍德算法效果类似的一个程序 -- 随机洗牌
* 代码来至王晓东《计算机算法设计与分析》
*/

#include "RandomNumber.h"
#include 
#include 
#include 
using namespace std;

// 交换a, b的值
template 
void Swap(Type &a;, Type &b;)
{
    Type temp;
    temp = a;
    a = b;
    b = temp;
}

template 
void Shuffle (Type a[], int len)
{
    // 随机洗牌算法
    static RandomNumber rnd;
    for (int i = 0; i < len; ++i) 
    {
        int j = rnd.Random(len-i) + i;      
        Swap (a[i], a[j]) ;    
    }
}

template 
void Print (Type a[], int len)
{
    for(int i=0; iwww.WuTianQi.com Tanky Woo原创,欢迎转载,转载请附上链接,请不要私自删除文章内任何关于本博客的链接。



Tanky Woo 标签: [舍伍德算法](http://www.example.com/%e8%88%8d%e4%bc%8d%e5%be%b7%e7%ae%97%e6%b3%95),[随机算法](http://www.example.com/%e9%9a%8f%e6%9c%ba%e7%ae%97%e6%b3%95),[Tanky Woo](http://www.example.com/Tanky+Woo)