找回密码
 加入
搜索
楼主: pusofalse

[效率算法] 练习003 - 顺序排列文本中的无序内容

 火... [复制链接]
发表于 2010-1-17 00:14:53 | 显示全部楼层
$begin=TimerInit()
$fc=FileRead("a.txt")
$array=StringRegExp($fc,"\r\n\r\n\:([\s\S]+?)(?=\r\n\r\n\:)",3)
Dim $thestr[UBound($array)]
for $i = 0 to UBound($array) - 1
        $thestr[$i]=$array[$i]                
Next
$array=StringRegExp($fc,"\A\:([\s\S]+?)\r\n\r\n\:[\s\S]*\z",1)
If Not @error Then
        Local $an=UBound($thestr)
        ReDim $thestr[$an+1]
        $thestr[$an]=$array[0]
EndIf
$array=StringRegExp($fc,"(?:[\s\S]+?\r\n\r\n\:)*([\s\S]*)\z",1)
If Not @error Then
        Local $an=UBound($thestr)
        ReDim $thestr[$an+1]
        $thestr[$an]=$array[0]
EndIf
For $i=0 To UBound($thestr)-1
        For $j=$i To 0        Step -1                
                If $j>0 And StringLeft($thestr[$j],1)<StringLeft($thestr[$j-1],1) Then 
                        $tmpval=$thestr[$j]
                        $thestr[$j]=$thestr[$j-1]
                        $thestr[$j-1]=$tmpval
                EndIf
        Next
Next
$thelast=":"&$thestr[0]
For $i=1 To UBound($thestr)-1
        $thelast=$thelast&@CRLF&@CRLF&":"&$thestr[$i]
Next
;ConsoleWrite($thelast&@CRLF)
FileDelete("a.txt")
FileWrite("a.txt",$thelast)
$diff=TimerDiff($begin)

MsgBox(0,"",$diff&"毫秒")
如果保证文件格式规范,可以不用UBOUND,再精简一点,但代码还是感觉冗余啊,。。唉,还是学习学习前面几位耗了。。

评分

参与人数 1金钱 +25 收起 理由
pusofalse + 25 学习了。

查看全部评分

发表于 2010-1-17 00:23:12 | 显示全部楼层
看到Afan的代码了,真是精炼啊,呵呵,为了重排序,我可想了半天,原来可以这么简单。。呵呵

不过要求中:2、每个段落中有m条内容(m>0),每行内容的第一个字符总是不为冒号:。
并不保证:冒号不出现在非第一字符,譬如出现在内容之中呢?我测试了一下,显示失败了,Afan可以再改进一下,呵呵

评分

参与人数 1金钱 +15 收起 理由
pusofalse + 15 还是你考虑周到~

查看全部评分

 楼主| 发表于 2010-1-17 00:23:14 | 显示全部楼层
本帖最后由 pusofalse 于 2010-1-17 00:25 编辑

FileDelete、FileWrite这两句降低了不少效率,其实也不必重写文件,直接Msgbox输出即可。输出的结果有点问题,:true在:test之前,用以下样本测试的:
:true
true??
assign!

:false
false??

:loop
L$***,G$***

:M$
M$###,M-obj

:test
^^~!!%%^^
false??
发表于 2010-1-17 00:31:59 | 显示全部楼层
本帖最后由 llztt 于 2010-1-17 01:08 编辑

恩,是有着问题,我自以为是只排第一字符就够了呢,理解失误了,呵呵

貌似直接字符串之间用大于小于比较就可以了,AFAN的好像也是这样做了

因为分隔符比较规律,所以,感觉用stringsplit更简洁些如下:
$begin=TimerInit()
$fc=FileRead("a.txt")
Dim $strNew
$thestr=StringSplit(StringRight($fc,StringLen($fc)-1),Chr(13)&Chr(10)&":",1)
For $i=1 To $thestr[0]
        For $j=$i To 1        Step -1                
                If $j>1 And $thestr[$j]<$thestr[$j-1] Then 
                        $tmpval=$thestr[$j]
                        $thestr[$j]=$thestr[$j-1]
                        $thestr[$j-1]=$tmpval
                EndIf
        Next
Next
$thelast=":"&$thestr[1]
For $i=2 To $thestr[0]
        $thelast=$thelast&@CRLF&@CRLF&":"&$thestr[$i]
Next
$diff=TimerDiff($begin)
MsgBox(0, '完成耗时(s):' & TimerDiff($begin) / 1000, $thelast)
数组临界判断没加。。。呵呵,菜偷差不多了,得睡觉去啦,pusofalse大大,还不睡哈

评分

参与人数 1金钱 +75 收起 理由
pusofalse + 75 果真强大,如果能够去掉函数调用就完美至极 ...

查看全部评分

发表于 2010-1-17 01:08:29 | 显示全部楼层
看到Afan的代码了,真是精炼啊,呵呵,为了重排序,我可想了半天,原来可以这么简单。。呵呵

不过要求中 ...
llztt 发表于 2010-1-17 00:23



    谢谢提醒,一会我修改下~
 楼主| 发表于 2010-1-17 01:56:15 | 显示全部楼层
回复 19# llztt


    果真强大,如果能够去掉函数调用就完美至极了。
不调用任何函数,这样做带来的后果是代码臃肿,或者还有可能是效率低下(?)。
测试以下代码就能体会到“合理使用语句、运算符”和“调用函数”之间的效率差别了:
Dim $dTimer1 = TimerInit(), $iCount1

For $i = 1 To 1000000
        $iCount1 += 1
Next
Msgbox(0, '', TimerDiff($dTimer1))

Dim $dTimer2 = TimerInit(), $iCount2
For $i = 1 To 1000000
        $iCount2 = $iCount2 + 1
Next
Msgbox(0, '', TimerDiff($dTimer2))

Dim $dTimer3 = TimerInit(), $iCount3
For $i = 1 To 1000000
        $iCount3 += _Test()
Next
Msgbox(0, '', TimerDiff($dTimer3))

Func _Test()
        Return 1 ; 什么也不做,立即返回。
EndFunc
当然上面的3段代码是没有任何意义的,只是能够非常清楚地表明其间的效率差别。
结论:
1、程序效率至上(这个与个人性格有关 - -|||)。
2、合理调用函数,能够合理地使用语句完成的指令,尽量不调用函数。当然这也要看个人喜好。
3、用最合适的代码,做最合适的事情。

评分

参与人数 2威望 +20 贡献 +5 收起 理由
gapkiller + 5 原来 += 操作符的效率还高些.. 学习了
afan + 20 学习了,经典的测试方法

查看全部评分

发表于 2010-1-17 08:36:54 | 显示全部楼层
#19
试问:如果用":a~:z"判断顺序 是否可行!!
#21
1、程序效率至上(这个与个人性格有关 - -|||)。
2、合理调用函数,能够合理地使用语句完成的指令,尽量不调用函数。当然这也要看个人喜好。
3、用最合适的代码,做最合适的事情。
不同意:
1、多半跟个人的AU3水平有关(其实出题的那一分钟,偶就有了思路,因水平有限,无法编辑出)
2  3  出题有条件是最好的,因为有限制,才能展出个人的水平!
发表于 2010-1-17 09:25:05 | 显示全部楼层
本帖最后由 llztt 于 2010-1-17 20:43 编辑

那个重排顺序上,还不能省事呢,目前我只有重排数组的办法了
发表于 2010-1-17 12:33:45 | 显示全部楼层
学习下。.....
发表于 2010-1-17 12:38:55 | 显示全部楼层
学习下。.....
发表于 2010-1-17 14:40:17 | 显示全部楼层
本帖最后由 C.L 于 2010-1-17 14:45 编辑

有空了重做一次,11楼的代码太臃肿了,优化了一下代码,去掉了二维数组,循环减少了两个,还是只用运算符和语句
$timestart = TimerInit ()
Dim $atemp [5],$temp,$lines
$i=1
$m=4
While 1
        $sLine = FileReadLine ("a.txt",$i)        
        $atemp[$m] = $lines&@CRLF
        If @error = -1 Then 
                For $i = 0 To 4
                        If $temp < $atemp[$i] Then
                                $temp&= $atemp[$i]
                        Else
                                $temp = $atemp[$i] & $temp
                        EndIf
                Next
                ExitLoop
        EndIf
        If $sLine <> "" Then 
                $lines &= $sLine&@CRLF
        Else
                $atemp[$m] = $lines&@CRLF
                $lines = ""
                $m -= 1
        EndIf
        $i += 1
WEnd
MsgBox (0,"运行时间:"&TimerDiff ($timestart)&"毫秒",$temp)

评分

参与人数 1金钱 +70 收起 理由
pusofalse + 70 学习了。

查看全部评分

发表于 2010-1-17 15:48:30 | 显示全部楼层
抽空再向各位前辈学习~~
 楼主| 发表于 2010-1-17 17:16:35 | 显示全部楼层
本帖最后由 pusofalse 于 2010-1-17 17:19 编辑

感谢诸位参与。以下是我的解,效率不怎样,问题出在了FileReadLine("a.txt", ...)这一句,测试打开文件句柄之后再读取,速度会快很多。I/O操作果真费时。一次读取全部,再用StringRegExp切割,速度会增加数倍,但不知在不使用Ubound函数的情况下,如何得到数组的元素数量。
Local $dTimer = TimerInit(), $iIndex, $hFile
Local $sLine, $aVar[1][2], $aVar1, $sResult, $iLineIndex = 0, $iFlags = 1

;$hFile = FileOpen("a.txt", 0)
While 1
        $iLineIndex += 1
        $sLine = FileReadLine("a.txt", $iLineIndex)
        If @error Then ExitLoop
        If $sLine = "" Then
                $iFlags = 1
                ContinueLoop
        EndIf
        If $iFlags Then
                $aVar[0][0] += 1
                Redim $aVar[$aVar[0][0] + 1][2]
                $aVar[$aVar[0][0]][0] = $sLine
                $iFlags = 0
        Else
                $aVar[$aVar[0][0]][1] &= $sLine & @CRLF
        EndIf
WEnd
;FileClose($hFile)

$aVar1 = $aVar
For $i = 1 To $aVar1[0][0]
        $iIndex = 1
        For $j = 1 To $aVar1[0][0]
                If $aVar1[$i][0] > $aVar1[$j][0] Then $iIndex += 1
        Next
        $aVar[$iIndex][0] = $aVar1[$i][0]
        $aVar[$iIndex][1] = $aVar1[$i][1]
Next

For $i = 1 To $aVar[0][0]
        $sResult &= $aVar[$i][0] & @CRLF & $aVar[$i][1] & @CRLF
Next
Msgbox(0, TimerDiff($dTimer) / 1000, $sResult)
发表于 2010-1-17 17:31:39 | 显示全部楼层
哈哈,一直等楼主的解,终于看到了,呵呵

不过可能我太钻牛角尖了,对条件的理解有些多了“4、段落与段落之间,总是有一空行连接。”,这并不约束段落中出现空行吧,感觉描述的最终理解为:空行+冒号开头的次行,这是区分该文件段落的分界符。。
如果以上理解通过的话,大大的解就得再改改了。。

评分

参与人数 1金钱 +10 收起 理由
pusofalse + 10 感谢指出错误。

查看全部评分

 楼主| 发表于 2010-1-17 17:52:01 | 显示全部楼层
回复 29# llztt


    的确如此。其实这道题目是我前几天确实遇到过的实际情况,实际样本中,空行只是在段落与段落之间,而在段落中并没有空行。我在出题目时,也就没有考虑到段落中也出现空行的情况。感谢你的建议,的确应该兼顾这种情况,那么我上面的解就完全错了,明天我改一下。今天晚上还要出去,不能上网了。
您需要登录后才可以回帖 登录 | 加入

本版积分规则

QQ|手机版|小黑屋|AUTOIT CN ( 鲁ICP备19019924号-1 )谷歌 百度

GMT+8, 2024-12-22 22:38 , Processed in 0.088594 second(s), 15 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表