在这里我们将待生成的数据结构称为IntSet,接口定义如下:

class IntSetImp
{
public:
IntSetImp(int maxelements,int maxval);
void insert(int t);
int size();
void report(int *v);//将集合中的元素写入到向量v中
};

一个使用的范例是:

void gensets(int m,int maxval)
{
int *v = new int[m];
IntSetImp S(m,maxval);
while(S.size()<m) {
S.insert(bigrand()%maxval);
}
S.report(v);
for (int i = ; i < m; ++i)
{
cout<<v[i]<<"\n";
}
}

下面我们来探讨如何实现这个问题,用各种数据结构来实现我们想要的功能以及比较他们的性能。

1:使用强大而通用的set模板

class IntSetSTL
{
private:
set<int> S;
public:
IntSetSTL(int maxelements,int maxval){}
int size(){return S.size();}
void insert(int t){S.insert(t);}
void report(int *v)
{
int j=;
set<int>::iterator i;
for(i=S.begin();i!=S.end();++i)
{
v[j++]=*i;
}
}
};

基本都利用了标准模板库的相应部分

2:相对采用标准模板库,我们可以用最简单的结构--数组来简历一个集合的实现

class IntSetArray
{
private:
int n,*x;//n保存元素个数,x保存数组
public:
IntSetArray(int maxelements,int maxval)
{
x=new int[+maxelements];
n=;
x[]=maxval;//maxval 作为哨兵,总是位于已排序元素的最后
}
int size(){return n;}
void insert(int t)
{
int i;//record
for(i=;x[i]<t;i++) ;
if(x[i]==t) return;//already in array
for(int j=n;j>=i;j--)
x[j+]=x[j];
x[i]=t;
n++
}
void report(int *v)
{
for (int i = ; i < n; ++i)
{
v[i]=x[i];
}
}
};

如果实现知道数组(集合)的大小,那么数组将会是一种比较较理想的结构,因为数组是有序的,并且支持随机访问,可以用二分搜索建立一个运行时间为O(logN)的搜索函数

3:但如果不知道集合的大小,那么链表将会是表示集合的首选结构,并且链表还能省去插入时元素移动的开销

class IntSetList
{
private:
int n;
struct node
{
int val;
node *next;
node(int v,node *p){val=v;next=p;}
};
node *head,*sentinel;
node *rinsert(node *p,int t)
{
if(p->val<t) p->next=rinsert(p->next,t);
else if(p->val>t)
{
p=new node(t,p);
n++;
}
return p;
}
public:
IntSetList(int maxelements,int maxval)
{
head=sentinel=new node(maxval,);
n=;
}
int size(){return n;}
int insert(int t){head=rinsert(head,t);}
void report(int *v)
{
int j=;
for(node *p=head;p!=sentinel;p=p->next) v[j++]=p->val;
}
};

4:下面考虑支持快速搜索和插入的结构--二分搜索树

class IntSetBST
{
private:
int n,*v,vn;
struct node
{
int val;
node *left,*right;
node(int i){val=i;left=right=;}
};
void rinsert(p,t)
{
if(p==)
{
p= new node(t);
n++;
}
else if(t<p->val) p->left=rinsert(p->left,t);
else if(t>p->val) p->right=rinsert(p->right,t);
return p;
}
void traverse(p)
{
if(p==) return;
traverse(p->left);
v[vn++]=p->val;
traverse(p->right);
}
public:
IntSetBST(int maxelements,int maxval){root=;n=;}
int size(){return n;}
void insert(int t) {root=rinsert(root,t);}
void report(int *x){ v=x;vn=;traverse(root);}
};

5:现在我们将看到一个更高级的结构,利用整数特性的结构--位向量

class IntSetBitVec
{
private:
enum { BITSPERWORD=,SHIFT=,MASK=0x1F;};//BITSPERWORD和 SHIFT 是对应的, 0x1F的是31,即是11111,五位的掩码
int n,*x,hi;
void set(int i) { x[i>>SHIFT] |= (<<(i & MASK));}//i & MASK 取出i的后五位,1<<(i & MASK)=2的(i & MASK)次幂
void clr(int i) { x[i>>SHIFT] &= ~(<<(i & MASK));}
void test(int i){ return x[i>>SHIFT] & (<<(i & MASK));}
/*i = 42 --> i&MASK 1<<(i&MASK) ~(1<<10) i>>SHIFT
42=101010 101010 1<<10=2^10 =~10000000000 =101010>>5
& 11111 =10000000000 = 01111111111 =1
-------
001010=10
clr(i) --> x[i>>SHIFT]=0
set(i) --> x[i>>SHIFT]=0|2的(i & MASK)次幂=2的(i & MASK)次幂
test(i) -> 如果已经set(i) 2的(i & MASK)次幂 & 2的(i & MASK)次幂=2的(i & MASK)次幂 返回True
否则 0 & 。。。=0 返回False
*/
public:
IntSetBitVec(int maxelements,int maxval)
{
hi=maxval;
x= new int[+hi/BITSPERWORD];
for(int i=;i<hi;i++) clr(i);
n=;
}
int size() {return n;}
void insert(int t)
{
if(test(i)) return;
set(t);
n++;
}
void report(int *v)
{
int j=;
for (int i = ; i < hi; ++i)
{
if(test(i)) v[j++]=i;
}
}
};

位向量的不足是如果n比较大,需要的内存也是比较大的

6:最后的一个数据结构结合了链表和位向量的优点,她在箱序列中放入整数

class IntSetBins
{
private:
int n,bins,maxval;
struct node
{
int val;
node *next;
node(int v,node *p) { val=v;next=p;}
};
node **bin,*sentinel;
node *rinsert(node *p,int t)
{
if(p->val<t ) p->next=rinsert(p->next,t);
else if(p->val>t)
{
p = new node(t,p);n++;
}
return p;
}
public:
IntSetBins(int maxelements,int pmaxval)
{
bins = maxelements;
maxval = pmaxval;
bin = new node*[bins];
sentinel = new node(maxval,);
for (int i = ; i < bins; ++i)
bin[i]=sentinel;
n=;
}
int size() {return n;}
void insert(int t)
{
int i=t/(+maxval/bins);
bin[i] = rinsert(bin[i],t);
}
void report(int *v)
{
int j=;
for (int i = ; i < bins; ++i)
for(node *p = bin[i];p!=sentinel;p=p->next)
v[j++] = p->val;
}
~IntSetBins();
};

如何生成[0,maxval]范围内m个随机整数的无重复的有序序列的更多相关文章

  1. qmake.exe是在Qt安装编译时生成的,里面内嵌了Qt相关的一些路径(最简单的方法是保持一样的安装路径,最方便的办法是设置qt.conf文件)

    在网上直接下载别人编译好的Qt库,为自己使用省了不少事.但往往也会遇到些问题,其中Qt version is not properly installed,please run make instal ...

  2. JS生成限定整数区间范围内的随机整数

    对于整数区间获取随机整数: m,n均为整数,且n>m. 获取[m,n)区间内的随机整数: 1 var aNumber = (n - m) * Math.random() + m; 2 var r ...

  3. 图文解说PhpStorm 7.0版本新增内置工具

    很多PHP开发者,都比较关心PhpStorm 7.0版本的内置工具.今天我们将测试内置的Vagrant工具和SSH远端控制台工具. Vagrant工具集成在PhpStorm 7.0版本中,提高了IDE ...

  4. php lcg_value与mt_rand生成0~1随机小数的效果比较

    因工作需要使用PHP生成0~1随机小数,之前写过一篇<php生成0~1随机小数方法>,基于mt_rand()及mt_getrandmax()实现. 后来有网友评论,php原生方法lcg_v ...

  5. C语言实现随机生成0~100的数

    #include <iostream> #include <time.h> int main() { srand((unsigned)time(NULL));//srand() ...

  6. C语言实现随机生成0或1

    rand函数在产生随机数前,需要系统提供的生成伪随机数序列的种子,rand根据这个种子的值产生一系列随机数.如果系统提供的种子没有变化,每次调用rand函数生成的伪随机数序列都是一样的.srand(u ...

  7. 已知可生成0~4的rand5(),实现生成0~6的rand7()

    若已知生成0~6的rand7(),求生成0~4的rand5(),则一个方法就是不断生成0~7的数,直到这个数满足0~4就返回. int rand5(){ int res; do{ res = rand ...

  8. velocity.ui2.0所有的内置动画名称

    velocity升级到2.0后api发生了变化,按照原来的名称已经不能调用原来的动画效果,新的名称如下:velocity.ui2.0所有的内置动画名称 bounce flash headShake j ...

  9. js生成一定范围内的随机整数

    Math.floor(Math.random()*(m-n+1)+n) Math.floor(Math.random() * (50 - 1 + 1) + 1): 生成1-50内的随机整数

随机推荐

  1. bzoj1656: [Usaco2006 Jan] The Grove 树木 (bfs+新姿势)

      题目大意:一个n*m的图中,“.”可走,“X”不可走,“*”为起点,问从起点开始绕所有X一圈回到起点最少需要走多少步. 一开始看到这题,自己脑洞了下怎么写,应该是可过,然后跑去看了题解,又学会了一 ...

  2. Picture POJ - 1177 (线段树-扫描线)

    A number of rectangular posters, photographs and other pictures of the same shape are pasted on a wa ...

  3. centOS升级部分功能后,不能进入桌面(桌面)

    在Linux中安装nginx,安装过程中需要安装c++等一部分环境,装完后,莫名奇妙的centos就不能进入桌面了,命令窗口可以进去. 网上查了查资料,说是升级了一部分功能,和内核有冲突.需要更新下系 ...

  4. ZooKeeper动态配置(十四)

    概述 在3.5.0发行之前,ZK的全体成员和所有其它的配置参数是静态加载的在启动的时候并且在运行的时候不可变.操作员诉诸于"滚动重启" - 一个手动密集和改变配置文件容易出错的方法 ...

  5. 选择排序Selection sort

    顾名思意,就是直接从待排序数组里选择一个最小(或最大)的数字,每次都拿一个最小数字出来, 顺序放入新数组,直到全部拿完 再简单点,对着一群数组说,你们谁最小出列,站到最后边 然后继续对剩余的无序数组说 ...

  6. UITableView的代理方法

    一.点击某个cell调用 /** * 点击了第几行调用 */ -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NS ...

  7. Python编写在Maya中查看文件列表的插件

    之前写过一篇用Python遍历文件夹的文章,今天把代码扩展一下,做成一个有UI用户界面的Maya插件,可以直接在Maya中运行: 功能是显示磁盘分区目录下的文件列表,通过定制也可以查看任意目录下的文件 ...

  8. Vuejs - 深入浅出响应式系统

    Vue 最独特的特性之一,是其非侵入性的响应式系统.数据模型仅仅是普通的 Javascript 对象.而当你修改它们时,视图会进行更新.这使得状态管理非常简单直接,不过理解其工作原理同样非常重要,这样 ...

  9. 【洛谷 P4320】 道路相遇 (圆方树,LCA)

    题目链接 题意:给一张无向图和\(M\)个询问,问\(u,v\)之间的路径的必经之点的个数. 对图建出圆方树,然后必经之点就是两点路径经过的原点个数,用\((dep[u]+dep[v]-dep[LCA ...

  10. 最短路之spfa系列

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2544 Problem Description 在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t ...