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

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;
...全文
719 22 打赏 收藏 转发到动态 举报
AI 作业
写回复
用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)

16,747

社区成员

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

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