舍伍德(Sherwood)算法学习笔记

一.概念引入

        设A是一个确定性算法,当它的输入实例为x时所需的计算时间记为tA(x)。设Xn是算法A的输入规模为n的实例的全体,则当问题的输入规模为n时,算法A所需的平均时间为。这显然不能排除存在x∈Xn使得的可能性。希望获得一个随机化算法B,使得对问题的输入规模为n的每一个实例均有。这就是舍伍德算法设计的基本思想。当s(n)与tA(n)相比可忽略时,舍伍德算法可获得很好的平均性能。

        概率算法的一个特点是对同一实例多次运用同一概率算法结果可能同。舍伍德算法(O(sqrt(n)),综合了线性表和线性链表的优点)总能求的问题的一个正确解,当一个确定性算法在最坏情况和平均情况下差别较大时可在这个确定性算法中引入随机性将之改造成一个舍伍德算法;引入随机性不是为了消除最坏,而是为了减少最坏和特定实例的关联性。比如线性表a的查找若是找10(独一无二),如果在a[0]则为O(1),若是最后一个则O(n),可见时间与输入实例有关,此时可引入随机性将之改造成一个舍伍德算法。

        有时候无法直接把确定性算法改造为舍伍德算法,这时候对输入洗牌。

        下面是洗牌算法源代码:

import java.util.Random;

public class Shuffle {

    public static void main(String[] args) {
        int a[] = new int[]{1,2,4,5,8};
        /*
         * Collections.shuffle(list)参数只能是list
         */
        myShuffle(a);
        for(int i:a) {
            //犯了个低级错误,输出了a[i],结果数组下标越界异常
            System.out.print(i+" ");
        }
        System.out.println();
    }

    private static void myShuffle(int[] a) {

        int len = a.length;
        for(int i=0; i<len; i++) {
            Random r = new Random();
            //直接Random.nextInt(len)提示静态方法里无法引用
            int j = r.nextInt(len);
            //Collections.swap(list,i,j)必须是list类型
            if(i!=j) {//原来没加这个条件
                int temp = a[i];
                a[i] = a[j];
                a[j] = temp;
            }
        }
    }
}

二.舍伍德思想解决迅雷2010年校招--发牌

        问题描述:52张扑克牌分发给4人,每人13张,要求保证随机性。已有随机整数生成函数rand(),但开销较大。请编写函数实现void deal(int a[],int b[],int c[],int d[]),扑克牌用序号0-51表示,分别存在大小为13的a,b,c,d四个数组中,要求尽可能高效。

import java.util.Random;

public class Poker {

    /*
     * 这道题确实不怎么明白,直接初始化后洗牌算法不得了
     * 不过解答只是替换nextInt,直接线性同余了,交换次数也减少了
     * 交换次数是随机产生的
     */
    //为方便swap和deal函数使用
    static int array[] = new int[52];

    public static void main(String[] args) {

        for(int i=0; i<array.length; i++) {
            array[i] = i;
        }
        int a[] = new int[13];
        int b[] = new int[13];
        int c[] = new int[13];
        int d[] = new int[13];
        deal(a,b,c,d);
        //这样输出方便
        for(int i=0; i<13; i++) {
            System.out.println(a[i]+" "+b[i]+" "+c[i] + " "+d[i]);
        }

    }

    private static void deal(int[] a, int[] b, int[] c, int[] d) {

        int m = 10;
        int p = 31;//需要素数
        int q = 10;
        Random r = new Random();
        int num = r.nextInt(52);//循环次数

        for(int i=0; i<num; i++) {
            m = m*p + q;
            m = m%(51-i);
            int j = 51 - m;
            if(i!=j) {
                swap(array,i,j);
            }
        }

        for(int i=0; i<13; i++) {
            a[i] = array[i];
            b[i] = array[i+13];
            c[i] = array[i+26];
            d[i] = array[i+39];
        }
    }

    private static void swap(int[] a, int i, int j) {
        //交换是正确的
        int temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }
}

三.舍伍德思想快拍算法解决第k小问题

import java.util.Arrays;
import java.util.Random;

/*
 * 目前还不知道找不到咋办?
 * 这是个愚蠢的问题,肯定找得到,因为是找第k个
 * 只需要判断k的合法性,在selectK函数外部
 */
public class SherwoodQsort {
    /**
     *舍伍德思想快拍算法解决第k小问题(就是正所第k个)
     *记得看算法导论时提出一个算法是维护一个k大小数组,扫描原有数组不断插入排序,最后第k个元素就是所求
     *这样等于说是求出了前k小,并不仅仅是第k小,肯定效率不如下面。
     */
    public static void main(String[] args) {

        //注意:数组a的最后一项表示最大值
        int a[] = new int[]{1,8,4,9,0,32,45,27,6,5,65535};
        int b[] = new int[a.length];
        b = Arrays.copyOf(a, a.length);
        //Collections.sort只对list可用
        Arrays.sort(b);
        System.out.print("待排序数组排序后为:");
        for(int i:b) {
            System.out.print(i+" ");
        }
        System.out.println();

        int k = 5;
        //注意:没把数组a的最后一项算进去
        int ans = selectK(a,0,a.length-1,k);
        System.out.print("第k(5)个数组元素是:"+ans+"\n");
    }

    private static int selectK(int[] a, int left, int right, int k) {

        //注意right=a.length-1,没把数组a的最后一项算进去
        while(true) {//更新left,right,k的值,直到找到为止

            if(left>=right) {
                return a[left];
            }

            //随机选择划分项,注意right=a.length-1,没把数组a的最后一项算进去
            int r = createRandom(left,right);
            int i = left;
            /*
             * 注意:数组a的最后一项65535表示最大值,是特地加上去的
             * 产生的r最多是a.length-1(因为right=a.length-1)
             * 这样下面的j=r+1才绝对不会越界,大多是这么处理的
             */
            int j = right+1;//right=a.length-1,就是数组最大项65535
            if(i!=r) {
                //注意是和r交换
                swap(a,a[i],a[r]);
            }

            //实际上是partion函数,由于需要返回p和j,就不单独写了
            int p = a[left];//虽然初试i=left,但下标不可是i
            while(true) {
                //直到左边小于划分项,右边大于为止
                while(a[++i]<p);
                while(a[--j]>p);
                //写在交换之前
                if(i>=j) {
                    break;
                }
                swap(a,i,j);
            }

            //交换,完成一次划分
            a[left] = a[j];
            a[j] = p;

            int t = j-left+1;
            if(t==k) {
                return p;//或者a[j]
            }else if(t>k) {//在左边
                right = j - 1;
            }else {
                /*
                 * 原来这个顺序错了,结果一直数组下标越界
                 */
                k = k - t;
                left = j+1;
            }
        }
    }

    private static void swap(int[] a, int i, int j) {
        //交换是正确的
        int temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }

    private static int createRandom(int left, int right) {

        Random r = new Random();
        return r.nextInt(right-left+1) + left;
    }

}

四.舍伍德随机化思想搜索有序表

  • 问题描述

            用两个数组来表示所给的含有n个元素的有序集S。用value[0:n]存储有序集中的元素,link[0:n]存储有序集中元素在数组value中位置的指针(实际上使用数组模拟链表)。link[0]指向有序集中的第一个元素,集value[link[0]]是集合中的最小元素。一般地,如果value[i]是所给有序集S中的第k个元素,则value[link[i]]是S中第k+1个元素。S中元素的有序性表现为,对于任意1<=i<=n有value[i]<=value[link[i]]。对于集合S中的最大元素value[k]有,link[k]=0且value[0]是一个大数。

  • 举例

  • 搜索思想

            随机抽取数组元素若干次,从较接近搜索元素x的位置开始做顺序搜索。

import java.util.Random;

public class SearchK {

    public static void main(String[] args) {
        int value[] = new int[]{65535,2,3,13,1,5,21,8};
        int link[] = new int[]{4,2,5,6,1,7,0,3};
        //查看是否存在元素k
        int k = 13;
        boolean flag = searchK(value,link,k);
        System.out.println("元素K(13)是否找到:"+flag);
    }

    private static boolean searchK(int[] value, int[] link, int x) {

        int max = value[1];
        int m = (int)Math.sqrt(value.length-1);

        Random r = new Random();
        int index = 1;//这个初始化本是为了不让编译器报错(未初始化)
        for(int i=0; i<m; i++) {
            //随机产生元素位置,加1是为了不取到value[0]
            int j = r.nextInt(value.length-1) + 1;
            int y = value[j];
            /*
             * 不明白max作用
             * value[index]一定小于x,所以下面才可以顺序搜索
             */
            if(max<y&&y<x) {
                max = y;
                index = j;
            }
        }
        //顺序搜索
        while(value[link[index]]<x) {
            index = link[index];
        }
        return value[link[index]]==x;
    }
}

/*
 *不懂,n个元素
 * if(!searchK(value,link,x))
    {
        value[++n] = x;
        link[n] = link[index];
        link[index] = n;
    } 

//删除集合中指定元素
template<class Type>
void OrderedList<Type>::Delete(Type k)
{
    int index;
    if(searchK(value,link,x))
    {
        int p = link[index];
        if(p == n)
        {
            link[index] = link[p];
        }
        else
        {
            if(link[p]!=n)
            {
                int q = SearchLast();
                link[q] = p;
                link[index] = link[p];
            }
            value[p] = value[n];//删除元素由最大元素来填补
            link[p] = link[n];
        }
        n--;
    }
}
 */

五.舍伍德算法解决跳跃表问题

        舍伍德型算法的设计思想还可用于设计高效的数据结构,提高有序链表效率的一个技巧是在有序链表的部分结点处增设附加指针以提高其搜索性能。在增设附加指针的有序链表中搜索一个元素时,可借助于附加指针跳过链表中若干结点,加快搜索速度。这种增加了向前附加指针的有序链表称为跳跃表。

            有空写吧……

六.随机抽题算法

  共有n道题,要求以相同概率随机抽取m道不重复试题。可以编号为1到n,围成一圈,每次抽取round,并出圈,下次再选到时候忽略如此直到选好了m题;不过若是n比较大会占用比较多的时间,先分析出圈的影响,round出圈后小于round的编号不变,大于的编号减一;对于已经抽到的题目(共k道),存入数组并由小到大排好序,再次选择roundk+1,如果大于等于round1则roundk+1加1,一直进行比较到roundk,不过这样可能会死循环,可以在中间判断,如果和roundi相等则加一过后如果小于roundi+1,则则直接插入已选题数组,否则和roundi+2比较,如此进行。

七.总结

        很多问题还是没闹明白,主要是资料太少,我查万方和维普数据库总共找到不超过10篇介绍舍伍德算法的,其中大部分都是泛泛而谈。

        遗留问题:搜索有序表时怎么初始化link数组?value[0]为什么搞个无穷大?初试找index为什么是sqrt(n)?查了n多资料也没头绪,懂的朋友给指点下。

时间: 2024-10-26 07:26:24

舍伍德(Sherwood)算法学习笔记的相关文章

Efficient Color Boundary Detection with Color-opponent Mechanisms算法学习笔记

这是一篇基于视觉颜色机制的边缘检测论文,原文分中文和英文版 中文版链接:中文版PDF 英文版链接:英文版PDF 项目主页:http://www.neuro.uestc.edu.cn/vccl/projcvpr2013.html 以下是我个人学习该算法后的理解,希望各位看官批评指正! 整个算法可分为以下几步: 1.输入一张彩色图像 2. 分别提取R-G-B三种颜色信息,并计算Y颜色信息,进行高斯滤波得到 3.设置连接权重ω ,通过式(1)得到R+wG和wR+G两种连接权值的的结果 $$Srg.Sg

SPFA算法学习笔记

一.理论准备         为了学习网络流,先水一道spfa.         SPFA算法是1994年西南交通大学段凡丁提出,只要最短路径存在,SPFA算法必定能求出最小值,SPFA对Bellman-Ford算法优化的关键之处在于意识到:只有那些在前一遍松弛中改变了距离估计值的点,才可能引起他们的邻接点的距离估计值的改变.为什么队列为空就不改变了呢?就是因为要到下一点必须经过它的前一个邻接点..SPFA可以处理负权边.很多时候,给定的图存在负权边,这时类似Dijkstra等算法便没有了用武之

Improved SLIC 算法学习笔记

之前有关于SLIC Superpixel算法的个人理解,这篇文章是对其改进算法Improved SLIC算法的理解. 改进点: sigma filter 用来避免错误分割: 聚类结束后,会基于颜色相似度将小聚类融入临近的聚类中. 改进聚类中心 原SLIC算法 使用平均值更新聚类中心 Improved SLIC算法 采用如下方法更新聚类中心,对应于改进点1: 其中δ_j表示,属于该聚类的所有像素点的亮度L的标准差,α是一个常数. 改进点2 原来的SLIC算法中,在进行迭代聚类后,得到一些小的聚类,

SLIC Superpixels 算法学习笔记

算法流程梳理如下: 原文下载:http://www.kev-smith.com/papers/SLIC_Superpixels.pdf 1.初始化: 通过对图像像素进行抽样,初始化k个聚类中心C_k ,步长为初始化聚类大小S,即将图像分为k个网格,取每个网格中心为初始聚类中心: 初始化每个像素点的标签lable为-1,每个像素点与聚类中心的距离distance为无穷大. 2.对初始化的聚类中心进行移动: 在该聚类中心相邻的8个像素点中,找到最小梯度方向,并将该点设为新的聚类中心,直至聚类中心不再

银行家算法学习笔记

一.概念引入         银行家算法( banker's algorithm )由 Dijkstra于1965提出,关键是将死锁的问题演示为一个银行家贷款的模型,由于能用于银行系统的现金贷款而出名.一个银行家向一群客户发放信用卡,每个客户有不同的信用额度.每个客户可以提出信用额度内的任意额度的请求,直到额度用完后再一次性还款.银行家承诺每个客户最终都能获得自己需要的额度.所谓"最终",是说银行家可以先挂起某个额度请求较大的客户的请求,优先满足小额度的请求,等小额度的请求还款后,再处

【学习】 R语言与机器学习学习笔记(1)K-近邻算法

前言 最近在学习数据挖掘,对数据挖掘中的算法比较感兴趣,打算整理分享一下学习情况,顺便利用R来实现一下数据挖掘算法. 数据挖掘里我打算整理的内容有:分类,聚类分析,关联分析,异常检测四大部分.其中分类算法主要介绍:K-近邻算法,决策树算法,朴素贝叶斯算法,支持向量机,神经网络,logistic回归. 写这份学习笔记主要以学校data mining课程的课件为主,会参考一堆的baidu,一堆的google,一堆的blog,一堆的book以及一堆乱七八糟的资料,由于精力有限,恕不能一一列出,如果有认

MySQL数据库学习笔记(一)

mysql|笔记|数据|数据库         我一直从事Informix和Oracle数据库开发,有一天发现网络上有一种小巧别致的数据库,被广泛使用,从MySQL的网站http://www.mysql.com/我下载了它的数据库软件,使用过后觉得真的挺好,这是我的一点学习笔记希望对各位初学者有点帮助. 1.       MySQL数据库介绍 MySQL 是瑞典的MySQL AB公司开发的一个可用于各种流行操作系统平台的关系数据库系统,它具有客户机/服务器体系结构的分布式数据库管理系统.MySQ

Hadoop学习笔记一 简要介绍

这里先大致介绍一下Hadoop. 本文大部分内容都是从官网Hadoop上来的.其中有一篇介绍HDFS的pdf文档,里面对Hadoop介绍的比较全面了.我的这一个系列的Hadoop学习笔记也是从这里一步一步进行下来的,同时又参考了网上的很多文章,对学习Hadoop中遇到的问题进行了归纳总结. 言归正传,先说一下Hadoop的来龙去脉.谈到Hadoop就不得不提到Lucene和Nutch.首先,Lucene并不是一个应用程序,而是提供了一个纯Java的高性能全文索引引擎工具包,它可以方便的嵌入到各种

作为一个新手的Oracle(DBA)学习笔记

Oracle数据库笔记 Jack Chaing 作者QQ595696297 交流群 127591054 祝大家学习进步. 如果大家想看Word版本的可以去下载:Word排版比较清晰一些. http://download.csdn.net/detail/jack__chiang/9810532 此笔记是作者本人去年开始从一个DBA新人的学习笔记,积累至今,希望拿出来给那些对DBA有兴趣的童孩学习,大家一起努力嘛. 此笔记记录了作者工作学习中从零基础的学习的记录,和从中遇见的问题与问题的解决!很高兴