一.概念引入

设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多资料也没头绪,懂的朋友给指点下。

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

  1. POJ 矩阵相乘 (随机化算法-舍伍德(Sherwood))

    周三的算法课,主要讲了随机化算法,介绍了拉斯维加斯算法,简单的理解了为什么要用随机化算法,随机化算法有什么好处. 在处理8皇后问题的时候,穷举法是最费时的,回朔比穷举好点,而当数据量比较大的时候,如1 ...

  2. C / C++算法学习笔记(8)-SHELL排序

    原始地址:C / C++算法学习笔记(8)-SHELL排序 基本思想 先取一个小于n的整数d1作为第一个增量(gap),把文件的全部记录分成d1个组.所有距离为dl的倍数的记录放在同一个组中.先在各组 ...

  3. Manacher算法学习笔记 | LeetCode#5

    Manacher算法学习笔记 DECLARATION 引用来源:https://www.cnblogs.com/grandyang/p/4475985.html CONTENT 用途:寻找一个字符串的 ...

  4. Johnson算法学习笔记

    \(Johnson\)算法学习笔记. 在最短路的学习中,我们曾学习了三种最短路的算法,\(Bellman-Ford\)算法及其队列优化\(SPFA\)算法,\(Dijkstra\)算法.这些算法可以快 ...

  5. 某科学的PID算法学习笔记

    最近,在某社团的要求下,自学了PID算法.学完后,深切地感受到PID算法之强大.PID算法应用广泛,比如加热器.平衡车.无人机等等,是自动控制理论中比较容易理解但十分重要的算法. 下面是博主学习过程中 ...

  6. Johnson 全源最短路径算法学习笔记

    Johnson 全源最短路径算法学习笔记 如果你希望得到带互动的极简文字体验,请点这里 我们来学习johnson Johnson 算法是一种在边加权有向图中找到所有顶点对之间最短路径的方法.它允许一些 ...

  7. 算法学习笔记——sort 和 qsort 提供的快速排序

    这里存放的是笔者在学习算法和数据结构时相关的学习笔记,记录了笔者通过网络和书籍资料中学习到的知识点和技巧,在供自己学习和反思的同时为有需要的人提供一定的思路和帮助. 从排序开始 基本的排序算法包括冒泡 ...

  8. R语言实现关联规则与推荐算法(学习笔记)

    R语言实现关联规则 笔者前言:以前在网上遇到很多很好的关联规则的案例,最近看到一个更好的,于是便学习一下,写个学习笔记. 1 1 0 0 2 1 1 0 0 3 1 1 0 1 4 0 0 0 0 5 ...

  9. 二次剩余Cipolla算法学习笔记

    对于同余式 \[x^2 \equiv n \pmod p\] 若对于给定的\(n, P\),存在\(x\)满足上面的式子,则乘\(n\)在模\(p\)意义下是二次剩余,否则为非二次剩余 我们需要计算的 ...

随机推荐

  1. [转] Initial Impressions on GraphQL & Relay

    https://kadira.io/blog/graphql/initial-impression-on-relay-and-graphql http://graphql.org/blog/subsc ...

  2. Change Fragment layout on orientation change

    Warning: this may be a pre-Lollipop answer. A Fragment doesn't get re-inflated on configuration chan ...

  3. Linux yum命令重装mysql

    如果是 rpm 安装的话,可以用 rpm -e mysql-server 如果是yum安装的,可以用 yum remove mysql* 删除MySQL安装文件夹 然后使用yum安装mysql: 1. ...

  4. Springmvc中@RequestParam传值中文乱码解决方案(转)

    @RequestMapping(value={"/list"},method=RequestMethod.GET) @ResponseBody public DeviceList ...

  5. HttpClient使用cookie

    import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; ...

  6. java 字符串转int

    //字符转整形 String aa = "23"; //int bb = Integer.parseInt(aa);//两种方式都是可以的 int bb = new Integer ...

  7. 表中查询重复的数据,如何通过sql语句查询?

    1.最直观的思路:要知道所有名字有重复人资料,首先必须知道哪个名字重复了:select name from emp group by name having count(*)>1所有名字重复人的 ...

  8. Nginx和Apache共存环境下apache获得真实IP

    自从Nginx出现以后,我们都喜欢让 Nginx 跑在前方处理静态文件,然后通过 proxy 把动态请求过滤给 apache.这么有个问题,跑在后方 apache 上的应用获取到的IP都是Nginx所 ...

  9. iOS 常见错误:CALayer position contains NaN: [14 nan]

    Terminating app due to uncaught exception 'CALayerInvalidGeometry', reason: 'CALayer position contai ...

  10. Linux命令:chmod命令

    chmod命令:改变文件或目录的存取权限 #权限代号 -r 文件被读取 4 -w 文件被写入 2 -x 文件被执行 1 #权限范围 -u 文件所有者 -g 文件所有者所在组 -o 其他 -a 全部 # ...