beta 的第三篇心得:深入研究 case 语句 (50分)

  • 主题发起人 主题发起人 beta
  • 开始时间 开始时间
有点意思!收!
 
你的几篇心得我想替你推荐发表了,不知道是否可以?
如果可以请抽空整理一下 :)
 
to 老猫:
谢谢了,我也想过发表,就是怕人家不要啊:(
QQ 上联系吧,告诉我一点具体的事情。
 
如果是这样的例子呢?
i := 7;
if i = 1 then
showmessage('i')
else
if i = 100000000 then
showmessage('10000000')
else
showmessage('other');
case语句又如何才有效率呢?
 
哈哈哈哈
i:=7;// i Longint
case i of
1:ShowMessage('i');
1000000:showmessage('1000000');
else
showmessage('other')
end;
和楼上的 if 有不同?
当然还可以:
i:=7;
case i of
1:ShowMessage('i');
2..1000:showmessage('2-1000');
// case 子界
1000000:showmessage('1000000');
else
showmessage('other')
end;
不过这和讨论的主题不符。写一则,兼收藏。
 
to zhukewen:
我知道您的意思,但是我前面已经说过了,当最小项的值和最大项的值之间的差距很大
的时候,Delphi 会用不同的方法进行处理。
我看了一下,当出现您这种极端情况的时候,Delphi 不会建表,而是直接用一种和 if
then
else
if 类似的方法进行处理。也就是说,效率和 if then
else
if 相当。
因此“case语句又如何才有效率呢?”这个问题就清楚了。
to 小雨哥:
你这两种情况的处理和上面一样:)
呵呵,不过要是出现这种情况,最好的办法就是改进设计,进而避免咯:)
 
各位老大,请做个测试,虽然这个不说明什么问题,但不妨作为业余游戏啊:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, TypInfo;
type
TMyStrSel = (Beijing, Tianjing, Shanghai, Chongqing);
TForm1 = class(TForm)
Button1: TButton;
ComboBox1: TComboBox;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
t1, t2: Cardinal;
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
begin
ComboBox1.Text := 'Chongqing';
with ComboBox1.Itemsdo
begin
Add('Beijing');
Add('Tianjing');
Add('Shanghai');
Add('Chongqing');
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
str: string;
strSel: TMyStrSel;
i: Cardinal;
begin
str := ComboBox1.Text;
i := 429496;//7295;
{MAX:4294967295}
t2 := 0;
t1 := GetTickCount;
strSel := TMyStrSel(GetEnumValue(TypeInfo(TMyStrSel), str));
while i > 0do
begin
case strSel of
Beijing: t2 := GetTickCount;
Tianjing: t2 := GetTickCount;
Shanghai: t2 := GetTickCount;
Chongqing: t2 := GetTickCount;
else
t2 := GetTickCount;
end;
dec(i);
end;
Caption := Format('选择 %s ,计算时间 %u ms', [str, t2 - t1]);
end;
procedure TForm1.Button2Click(Sender: TObject);
var
str: string;
i: Cardinal;
begin
str := ComboBox1.Text;
i := 429496;//7295;
{MAX:4294967295}
t2 := 0;
t1 := GetTickCount;
while i > 0do
begin
if str = 'Beijing' then
t2 := GetTickCount
else
if str = 'Tianjing' then
t2 := GetTickCount
else
if str = 'Shanghai' then
t2 := GetTickCount
else
if str = 'Chongqing' then
t2 := GetTickCount
else
t2 := GetTickCount;
Dec(i);
end;
Caption := Format('选择 %s ,计算时间 %u ms', [str, t2 - t1])
end;
end.
结果是什么?测试后看一看啊,也不知道我的代码有没有写错。
 
呵呵,小雨哥,你这个例子很说明问题啊,下面是我的测试结果:
(以下时间取 10 次的平均值,单位毫秒)
选择 case 方法 if 方法
Beijing 0.8 30
Tianjing 0.8 47
Shanghai 0.9 65
Chongqing 0.8 85
效率问题很明显的摆在眼前,我就不用多说了[:D]
 
TO小雨哥:
你这个比较有些不公平,
strSel := TMyStrSel(GetEnumValue(TypeInfo(TMyStrSel), str));
while i > 0do
begin
case strSel of
...
end;
dec(i);
end;
其中strSel := TMyStrSel(GetEnumValue(TypeInfo(TMyStrSel), str));只做了一次,
而if中的字符串的比较可是做了无数次哦,所以不能说明什么问题。
这个算法的关键是在于把字符转换为有序整数,效率的关键在于转换函数效率。如果
if的时间复杂度是O(n/2),而 case 的时间复杂度是 O(1)。假设转换函数的时间复杂
度也是O(1),记为O'(1)吧。那么整个算法的时间复杂度是O'(1)+O(1),让我们来看小
雨哥的比较,假设他做了X次,那么整时间复杂度应该是是X*(O'(1)+O(1)),然而小雨
哥把程序写成了O'(1)+X*(O(1)),很明显这是个投机取巧的做法,因为实际上O'(1)的
时间要大于O(1)。对于程序设计来说,这种取巧是一种技巧,值得学习,然而对于测试
来说,违背了公平原则。建议修改一下程序:
while i > 0do
begin
strSel := TMyStrSel(GetEnumValue(TypeInfo(TMyStrSel), str));
case strSel of
...
end;
dec(i);
end;
把strSel := TMyStrSel(GetEnumValue(TypeInfo(TMyStrSel), str));
这一句移到循环内,再做测试,这样才是公平的结果[:D]
 
DoubleWood: 这样才是不公平,我们讨论的是 case 和 if then
else
if 之间的效率
不应该涉及到其他的东西。
如果你想不通,可以直接全部用 整型 来进行比较,一样可以看出效率差异的:)
 
毋庸置疑,case的效率无论从哪个方面来说都优于if then
else
if
之所以存在if then
else
if 这样的代码如果排除编程人员的水平因素,完全是因为
if then
else
if 的适用范围远远多于case. 事实上,两者从逻辑上完全等效,采用
那种方式完全取决于编码的代价,尽管case 效率高,但考虑编写代码,对于特定的人
综合工作量来说可能if then
else
if更少一些。另外,对于某些情况下,如果用case
的可读性反而不如if then
else
if。所以,采用那种形式还要具体问题具体分析。
 
case ordinal_type of
.
.
end;
确实比if then
else
效率要高,
但是GetEnumValue(TypeInfo(TMyStrSel), str));
又是在做什么呢,无需进行字符串比较?
 
CASE 与 IF 的比较就好比 WHILE 和 FOR 的比较。
 
我想,既然用得上case那么所有的情况都是已经预知的,其实,如果需要判断的情况稍微
多一点,用首字母hash
case aStr[1] of
'A':
if (aStr = 'ABC') then
begin
end
else
if (aStr = 'ABCD') then
begin
end;
还是比较有效率的,如果需要判断的情况太多,性能要求又太高,就需要寻求更高性能的
算法
 
TO beta:
也许是我没有看清楚你的题目,也许是我看了你的第二篇还没回过神来。我以为说的是
字符变成有序类型然后用CASE这种办法和直接用if...then
...的比较,所以得
出不公平的结论。
不过在我看来,就算是比较CASE和if...then
...的效率,小雨哥的程序仍然有失公平。
原因很简单,那就是如果要进行这样的比较,那么在if 比较的时候,不应该使用象字符
串比较这样化时间的操作,因为if...then
...本身花费的时间并不多,相对来说,绝大多
数时间化在了字符比较上,这难道叫公平吗?
 
case 循环更改为:
~~~~~~~~~~~~~~~~
while i > 0do
begin
strSel := TMyStrSel(GetEnumValue(TypeInfo(TMyStrSel), str));
case strSel of
...
end;
dec(i);
end;

字符串增加为:
~~~~~~~~~~~~~~~~
with ComboBox1.Itemsdo
begin
Add('Beijing');
Add('Tianjing');
Add('Shanghai');
Add('Chongqing');
Add('Zhongguo');
Add('Hangzhou');
Add('Suibian');
end;

测试结果
~~~~~~~~~~~~~~~~~
选择 case 方法 if 方法
15 40
Beijing 40 25
Tianjing 45 45
Shanghai 60 60
Chongqing 50 70
Zhongguo 35 70
Hangzhou 35 70
Suibian 30 70
 
我觉得大家的讨论有点偏了
如果一段程序的执行时间很长,需要优化,那他的瓶颈
有多少可能是if..then
..else
和case语句造成的?
如果程序运行需要10秒钟,你把if..thne..else
换成
case,或者把case换成if..thne..else
节约几十毫秒
有什么意义?,而且各位的测试不知是如何测试的?
如果一个case语句需要几十毫秒,或者一个10来行
的if..then
..else
需要几十毫秒,那不知各位用的
是什么机器?是386还是286,或者更差是8086,即使
是那些机器,大概也用不了那么多的时间。顺便说一
句,如果用Now函数来计算运行时间,如果运行时间
是秒以上的,还是可用的,如果运行时间是毫秒级的
用这个函数得出的结果是不可靠的,就像100米跑,用
秒表可以分辨两个人的速度,可是如果这一百米是
飞机飞过,一个是800公里/小时,一个是900公里/小时
你的秒表能分得出来吗?
所以通常case或if..then
..else
本身并不是效率的优化对象,
我编程序还基本没有遇到需要优化case或if..then
..else

身的时候,因为case或if..then
..else
本身永远不会成为
瓶颈,因为我们编的是应用程序,除非你的程序就是要处理
case或if..then
..else
本身这种情况,呵呵
 
本人倾向于:
if ... then
begin
......
end else

if ... then
begin
......
end else

if ... then
begin
......
end else

if ... then
begin
......
end else

......
 
同意SS2000的观点, 如果为了研究一下, 深入讨论有点意义..如果仅仅是为了
对于编码时采用if 还是 case的一个佐证,就没有什么大的意义了。尽管说程序
的细微之处见功夫,但是如果不能够从大处着眼,从全面去衡量一个系统不同
方案的利弊得失,懂得再多的技巧也只能停留在低层次的水平上。。。。
 
后退
顶部