关于不重复随机取值的问题

lgllps 2004-10-29 03:16:44
有一字符串mystr,比如其值为"abcdefghijklmnopqrstuvwxyz",我现在希望从中随机抽出5个不重复的字符,组成一个新的字符串num,不知如何以最高的效率来执行.下面是我写的代码,总觉得执行效率不够,因为temp不停地重新分配其值,可能影响速度.

var
k:integer;
mystr,temp:,num:string;

begin
mystr:='abcdefghijklmnopqrstuvwxyz';
temp:=mystr;
num:=stringofchar(' ',5);
randomize;

for k:=1 to 5 do
begin
n:=random(length(temp))+1;
num[k]:=temp[n];
delete(temp,n,1);
end;

end;
...全文
704 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
lgllps 2004-11-09
  • 打赏
  • 举报
回复
谢谢朋友们的指点!我大家的启发下,我作了如下改进,速度快多了!
label
88;
var
k,p,t:integer;
mystr,num:string;

begin
mystr:='abcdefghijklmnopqrstuvwxyz';
num:=stringofchar(' ',5);
randomize;

for k:=1 to 5 do
begin
n:=random(length(mystr))+1;

//在字符串中检查,如果已经取过,则取其后面一个值;
for p:=n to length(mystr) do
if mystr[p]<>' ' then
begin
n:=p
goto 88;
end;

for p:=1 to n-1 do
if mystr[p]<>' ' then
begin
n:=p
goto 88;
end;

88: num[k]:=mystr[n];
mystr[n]:=' ';
end;

end;
ffss239494 2004-11-05
  • 打赏
  • 举报
回复
以上说的“用数组找随机位置”的意思是:
用数组来代替delete的功能,来改变每次取数后的数组内容。
个人觉得字符串操作比较慢.
ffss239494 2004-11-05
  • 打赏
  • 举报
回复
上面的算法对于这样的问题:
比如:
26个数取不同的26个随机数列(1~26),15个数取15个不同的15个随机数(1~15)。
那么没有别的算法比这个高了,
因为它不重复取值。

但是如果像楼主的问题:
比如:
26个数中取5个不同随机数,或者100个数中取5个不同的随机数,
也就是基数大,取的数少~
那么这种算法就不一定效率最高。
比如:26取5
很可能分别取5个随机数,遇到重复的再取。
比这个效率高~
因为基数大,出现重复的几率就小。
这个算法的效率是变化的。(取决于基数和取数的比率)

以上为个人意见,仅供参考...
ffss239494 2004-11-05
  • 打赏
  • 举报
回复
楼主的算法和我用的原理是一样的~
主要是看delete()函数的效率。
在求字符随机位置的时候楼主不防改用数组求。
效率比字符串高~用数组求随机数的时候
可以用for()把数组从新赋值,或者用链表来实现
来代替delete()的功能~
链表删除原来位置快,找位置慢,
我觉得用数组找随机位置,再用结果找字符,
比用delete 效率高.....
别的算法不见得比这个效率高。

songyanbin 2004-11-01
  • 打赏
  • 举报
回复
数少了 产生随机数的方法不错,但是如过基数很大,选的数又很多的话,这样做就有点效率低了
我没有具体研究过这样的效率,比如对26个字母产生26个随机数,再对26个随机数排序效取前4个效率高还是只做4次取数操作(绝对没有重复的),再交换指定2个变量值效率高呢?
如果基数不是26而是10000呢?
yinweixian 2004-10-30
  • 打赏
  • 举报
回复
把取出来的数据遍历比较不就好了
ahuige 2004-10-30
  • 打赏
  • 举报
回复
主要是因为依然是操作了字符串,而且需要定位
ahuige 2004-10-30
  • 打赏
  • 举报
回复
楼上的兄弟程序想法不错,从简洁来讲是不错的,但是从效率上讲,和楼主的delete可能效果差不多,而且步骤好象还多一些。
songyanbin 2004-10-29
  • 打赏
  • 举报
回复
晕 上面写错了 是
for a:=1 to 4 do
begin
m:=random(n+1-a)+1
temp:=mystr[m];
mystr[m]:=mystr[n+1-a];
mystr[n+1-a]:=temp
end
songyanbin 2004-10-29
  • 打赏
  • 举报
回复
算知字符串mystr长度N,取4次
for a:=1 to 4 do
begin
temp:=mystr[random(n+1-a)+1];
mystr[random(n+1-a)+1]:=mystr[n+1-a];
mystr[n+1-a]:=temp
end

意思就是 你从N个字符中取4个
第一次,是N选1,并将选出的数和第N个交换
第二次 是N-1选1(不含最后一个),并将选出的数与第N-1个交换。
第三次 是N-2选1(不含最后两个), 并将选出的数与第N-2个交换。
第四次 是N-3选1 (不含最后三个),并将选出的数与第N-3个交换

这就选完了,输出时 从第N个倒着输出4个,就是你选中的字符,同时输出顺序

就是你选中的顺序。
xhai 2004-10-29
  • 打赏
  • 举报
回复
用COM的GUID不正是解决的好方案吗.只要不超过128个的数字,就可以用这个方法.
在DELPHI的Comobj程序单元中定义了一个方法CreateClassID程序.

例如需要前8位.GUID前8位是在COM产生新的GUI值时是最容易变化的.
加入单元文件:ComObj
procedure Tform.GetID(var sJID:olevariant);
begin
sJID:=CreateClassID;
sJID:=copy(sJID,2,8);
end;
alphax 2004-10-29
  • 打赏
  • 举报
回复
还有就是如果mystr是通过参数传递进来的话,应该在

ptemp := Pointer(temp);
之前调用一下UniqueString(temp);
alphax 2004-10-29
  • 打赏
  • 举报
回复
你主要避免重新分配内存以及避免调用一些隐含的string操作就可以了


var
k, l: integer;
mystr,temp:,num:string;
ptemp, pnum: PChar;
begin
mystr:='abcdefghijklmnopqrstuvwxyz';
temp:=mystr;
num:=stringofchar(' ',5);
randomize;

ptemp := Pointer(temp);
pnum := Pointer(num);

l := Length(mystr);

for k := 1 to 5 do
begin
n := random(l);
pnum^ := ptemp[n];

if n <> (l-1) then
ptemp[n] := ptemp[l-1];
dec(l);
inc(pnum);
end;
end;

上面这样写的前提是temp和num必须是临时变量,而且没有复制给别的字符串
ahuige 2004-10-29
  • 打赏
  • 举报
回复
老兄
你这就不对了生成重复的随机数是有可能的
但是根据随机数排序的次序是一定的.
而且我最后的说取值不是按随机数取,
是按随机数代表的n来取.
比如 'abcd' 生成 3,6,8,6;你的排序当然是看你用的什么法,但是反正结果一定是非二值的.
你排序后就成了8663,也就是cbda
ahuige 2004-10-29
  • 打赏
  • 举报
回复
算了,兄弟,我想了一下这种正规的方法效率也不高.
只有5位就干脆这样来
建立一个5位的数组,
自动生成随机数,
每生成一个就和数组里的数比较.
如果有相同的就再生成下一个数,
如果不相同就存入数组,直到找到5个不同的数
这样的效率从概率上讲应该还行.
因为不知道delete的效率如何所以我也不能说是否比你的好不过应该是可行的.

lgllps 2004-10-29
  • 打赏
  • 举报
回复
1.生成n个随机数,第n个随机数表示第n个字符
2.将n个随机数排序,我想一般你自己的工程里会有一个数组排序的过程.这样就不用写新的,不过排序时要记录原来的序号nth.
3.取排好序的前5位,或者5位
4.用这5个随机数代表的5个位的字符连接起来.

生成的n个随机数中,极可能出现重复的,排序后就可能出现 1123344555..这样取前5个还是不行呀?
ahuige 2004-10-29
  • 打赏
  • 举报
回复
看起来要用一个二维数组的排序来完成.
ahuige 2004-10-29
  • 打赏
  • 举报
回复
算了,学统计的大哥来帮你.
我这个方法,可能语句会更多.
但实际上不操作字符串可能会好一些.
1.生成n个随机数,第n个随机数表示第n个字符
2.将n个随机数排序,我想一般你自己的工程里会有一个数组排序的过程.这样就不用写新的,不过排序时要记录原来的序号nth.
3.取排好序的前5位,或者5位
4.用这5个随机数代表的5个位的字符连接起来.
lgllps 2004-10-29
  • 打赏
  • 举报
回复
random函数只能取一个值,如果能一次取若干个不同值就好了,比如 random(100,5)能一下子从0-99之间随机取5个值出来,这样就好喽,呵呵
lgllps 2004-10-29
  • 打赏
  • 举报
回复
是的,我通过对temp长度的变短排除,来得到5个不同的随机值。如果不这样,就有可能取的5个随机数中出现重复值。
加载更多回复(2)
中文编程系统化教程初级1学习编程捷径:(不论是正在学习编程的大学生,还是IT人士或者是编程爱好者,在学习编程的过程中用正确的学习方法可以达到事半功倍的效果。对于初学者,可以通过下面的方法学习编程,通过对成百上千个实例练习,则很快会成为编程高手。我们专业从事编程十几年,积累了丰富的编程经验,会陆续制作编程视频供大家学习,中级、高级编程我们会专门制作中高级的系列编程课程,难度逐步加深,想学编程的可以关注我们的系列课程。可以就相关编程问题提问。1、【编程工具分为 免费自由版、专业版、企业版。】首先通过免费自由版熟悉基本操作,通过我们提供的实例视频学习编程,先快速入门。2、基本入门后,再学习我们提供的中级编程课程,通过对若干实例的编程练习,基本可以掌握编程思路。3、想继续加深学习的,可以继续学习高级版编程课程,通过对连接数据库等的学习真正开发出实用的商业管理软件或定制开发程序。4、基本掌握了编程思路之后,再学习其他的编程语言或大学里的编程课程则会非常轻松,因为不论是哪个编程语言,最重要的是学习编程思路,而编程思路基本上是相通的。5、学习完PC电脑端编程后,还可以继续学习APP手机软件开发。APP手机软件开发需要有PC电脑上开发基础,操作基本类似。6、编程工具为 搭建之星,这个编程工具的特点:1、安装简单、迅速,纯中文界面,构件丰富,设计过程直观、自由;无需掌握电脑语言,所有编程构件化、命令化、可视化。2、交互式开发,只需要四种类型的“命令”,便可以建立各构件之间的联系;象搭积木一样简单,并可快速的搭建出具有专业水平的软件作品。3、微解释执行,命令解释量小,执行速度快。可以和编译后的可执行文件相媲美。4、提供打包工具,使您即刻将自制软件安装到其它机器上运行。5、自动对开发项目进行加密;使您的项目,在未经授权下,别人无法“浏览、修改”项目的构件关系与搭建方法。课程安排:初级11  初级概述2  熟悉构件取值赋值3 折叠式菜单滑动面板编程4 自定义图形窗口自定义标题栏编程5 多行文本分段显示编程6 调用外部exe文件关闭外部exe文件编程7 给自己编写的项目设置密码8 制作一个计算器编程9 图片浏览编程10 看图软件编程11 配置文件读写编程12密码验证登录编程13软件启动窗口编程14增加软件工具条菜单15调色板编程16随机算式编程17螳螂捕蝉多窗口显示编程18 删除指定的字符行编程19计算表达式编程20扩展系统菜单21时间计算秒级计算编程22数值范围判断编程23数值比较取中间值编程24随机抽取编程25锁定窗口编程26文件拷贝显示进度条编程27项目间传递参数公用数据编程28项目间传递参数执行文件编程29字符串截取编程30多媒体实例澳门介绍编程31电影播放软件编程32初级1总结【使用这个编程工具开发的部分实际案例】   

16,748

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 语言基础/算法/系统设计
社区管理员
  • 语言基础/算法/系统设计社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧