65.9K
CodeProject 正在变化。 阅读更多。
Home

高级批处理文件技术第一部分 - 冒泡排序

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.95/5 (22投票s)

2007年9月2日

7分钟阅读

viewsIcon

136640

一个 Windows 批处理文件,用于对项目列表进行冒泡排序

Batch File Bubble Sort

引言

这是一个只使用Windows批处理文件实现的冒泡排序。它可以用于对命令行中指定的项目列表进行排序。

摘要

命令行项目排序的问题最初由Rama在一个题为周五编程测验休息室帖子中提出。他实际上正在寻找使用LINQ的解决方案,但我决定尝试只使用Windows批处理编程来完成它。

在本文中,我将介绍一种编写批处理文件以对任意数量的参数执行冒泡排序的技术。例如,给定以下输入

67 89 12 1 8 1 3 5 7

程序应该产生下面所示的输出

1
1
3
5
7
8
12
67
89

使用代码

批处理文件可能很难阅读和理解,特别是如果您不熟悉一些完成工作所需的更深奥的Windows命令和标志。我将详细解释每个部分,然后在文章末尾提供完整的列表。

另请注意,我已对代码片段使用了C++风格的双斜杠注释。这是因为批处理文件注释由REM语句或行首的双冒号组成。批处理文件不支持后面带有注释的行,但我希望注释每一行。我使用这种语法只是为了说明重点。请不要尝试运行任何带有//注释的代码!

初始化

首先要做的就是初始化一个计数器并关闭命令的回显。保持echo on是一个有用的调试工具,但它也会产生满屏的输出,这不是我们想要的。计数器将用于在加载项目时唯一命名它们。

@echo off
 set count=1

加载变量

现在我们需要将参数加载到变量中,以便我们可以对它们进行排序。不幸的是,我们没有数组或列表等数据结构的便利。此外,虽然我们可以根据需要创建变量,但由于变量展开的执行方式,我们无法读取其值。换句话说,以下代码将无法工作,因为变量var将无法正确展开。这使得“创建”环境变量成为可能,但我们无法读取其值,因为我们并不知道其名称。

 set count=1
 set var%count%=%1               // create a variable called 'var1'
 set var                         // We can see the variable...
 echo %var%count%%               // ...but we can't access the value!

我们真正想在这里创建的是一个伪数组,其中变量本身包含索引。例如:var1=67, var2=89等等。这意味着我们可以通过连接和展开来即时创建变量名:var%count%=%1。然而,为了使其工作,我们需要用%符号包围“整个”变量以指示变量应该被展开,(%var%count%%)而这就是它失败的地方,因为我们无法展开内部变量。

相反,我们使用文件系统来存储我们的变量。它有点复杂,也慢得多,但它工作得很好。下面的代码片段展示了每个命令行参数如何存储在一个小的、顺序编号的文本文件中。

:loadLoop                        // Start of our loop
 echo %1 > _%count%.var          // Copy the arguments into a file
                                 // called _1.var, _2.var etc.
 set /a count=count+1            // Increase the counter
 shift                           // shift the arguments
 if "%1" == "" goto :startSort   // If we are out of arguments,
                                 // continue to the next phase
 goto loadLoop                   // Back to the top, and process
                                 // the next argument

set命令中指定的/a标志表示等号右侧的字符串是一个数值表达式,应该进行求值。这允许我们执行算术运算——在本例中是增加变量的值。shift命令将所有命令行参数向左旋转一位,这样%2变成%1%1滑出末尾并永远消失。通过以这种方式使用shift,我们可以通过始终引用%1在循环中处理任意数量的参数。

最后,if语句只是检查是否还有更多参数需要处理。如果%1的值是一个空字符串,我们已经将所有参数加载到已知的“变量”中,然后我们可以goto排序例程的开头。

排序输入

现在我们已经加载了参数,并且它们位于我们可以轻松访问的已知变量名中,是时候对它们进行排序了。在这个版本的冒泡排序算法中,每当检测到交换时,排序就会重新开始,而不是在单次遍历中扫描和交换多个项目。这将妨碍性能,但比完整的扫描冒泡排序更容易实现。此外,由于我们使用批处理文件来完成此任务,性能并不是我们所需功能列表中的首要考虑因素...

以下代码只是循环遍历我们已知元素的“数组”,从0开始,直到%total%。通过调用子例程:swap(将在下一节中解释),将每个项目与以下数组元素进行比较。%next%变量通过简单地将存储在%count%中的当前项目索引加一来计算,再次使用set命令的/a标志。

如果变量%swapped%true,那么我们知道元素已交换,我们跳转到:RestartSort从头开始重新扫描数组。如果当前项目的索引 (%count%) 等于元素总数,并且我们在此次遍历中没有交换任何内容,我们知道所有元素都已排序,因此我们可以goto :output显示它们。

:startSort                            // Set our upper "array bound"
 set /a total=count-1

:RestartSort                          // Restart the sort from the beginning
 set /a count=1

:sortLoop
 set /a next=%count%+1                // Swap n and n+1
 call :swap %count% %next%
 set /a count=count+1
 if "%swapped%" == "true" goto :RestartSort // If the variables were swapped,
                                            // start again
 if "%count%" == "%total%" goto :output     // If we're done,
                                            // output the results
 goto :sortLoop                             // Back to the start to
                                            // swap the next two

交换元素

冒泡排序通过交换无序的元素来工作。在我们的实现中,我们可以通过简单地重命名存储元素的文件的名称来轻松交换两个元素的顺序!下面的代码显示了:swap子例程,它测试小于或等于并相应地交换元素。

但第一个问题是如何将我们的元素值从存储它们的文件中读出,并放入一个我们可以用于比较的环境变量中。诀窍是使用带有/P标志和一些基本文件重定向的set命令。set /P将变量设置为用户输入的一行。我们可以利用此功能,将包含元素的f文件重定向到set命令,从而将变量设置为文件的内容。

:swap
 set /P var1="" < _%1.var                   // Get the first element
 set /P var2="" < _%2.var                   // Get the second element
 if /I %var1% LEQ %var2% goto noSwap        // Compare and swap if necessary
 ren _%1.var _temp.var                      // Simply rename the files to swap
                                            // the positions
 ren _%2.var _%1.var
 ren _temp.var _%2.var
 set swapped=true                           // Let the caller know that
                                            // we swapped the elements
 goto :eof                                  // return

:noSwap
 set swapped=                               // No swap occurred, so clear the
                                            // "swapped" flag
 goto :eof                                  // and return

一旦我们将两个元素加载到一些变量中,我们就可以使用if命令的扩展,即/I标志,它会导致对两个值进行不区分大小写的字符串比较。有趣的是,如果值是数字,则执行数字比较而不是字符串比较,这意味着此批处理脚本可以像字符串一样轻松地对数字列表进行排序,无需任何修改。

字符串比较可用的比较运算符如下所示,但对于我们的排序,我们只需要LEQ(小于或等于)。我们也可以使用GEQ(大于或等于),我们的排序将按相反方向排序。实现一个批处理排序,该排序可以接受一个指示应该执行升序还是降序排序的标志,这留给读者作为练习。

EQU 等于
NEQ 不等于
LSS less than
LEQ 小于或等于
GTR greater than
GEQ 大于或等于

显示已排序的项目

一旦我们的列表排序完成,我们需要能够输出结果。对于此任务,我们使用带有/L标志的for循环,这会使命令生成一组具有特定起始、增量和结束点的数字。这些数字实际上是我们现在已排序数组的索引。对于集合中的每个元素,我们调用:showval例程以显示具有给定索引号的文件的内容。

循环完成后,我们清理所有剩余文件,并通过将环境变量设置为空来释放它们。

:output
 for /L %%i in (0,1,%total%) do call :showval %%i

:cleanup
 erase *.var
 set next=
 set offset=
 set total=
 set count=
 set var=
 set var1=
 set var2=
 goto :eof

:showval     // %1 is the first parameter in the subroutine, NOT the batch file
 type _%1.var  // type the file to the screen
 goto :eof

完成的程序 - BatchSort.bat

完成的程序如下所示。要使用它,只需将代码复制并粘贴到一个新的文本文件中,并将其扩展名为.bat,例如BatchSort.bat,然后运行它。Windows记事本是创建批处理文件的出色编辑器。

@echo off
 set /a count=0

:loop
 echo %1 > _%count%.var
 set /a count=count+1
 shift
 if "%1" == "" goto :startSort
 goto loop

:startSort
 set /a total=%count%-1

:RestartSort
 set /a count=0

:sortLoop
 set /a next=%count%+1
 call :swap %count% %next%
 set /a count=count+1
 if "%swapped%" == "true" goto :RestartSort
 if "%count%" == "%total%" goto :output
 goto :sortLoop

:swap
 set /P var1="" < _%1.var
 set /P var2="" < _%2.var
 if /I %var1% LEQ %var2% goto noSwap
 ren _%1.var _temp.var
 ren _%2.var _%1.var
 ren _temp.var _%2.var
 set swapped=true
 goto :eof

:noSwap
 set swapped=
 goto :eof

:output
 for /L %%i in (0,1,%total%) do call :showval %%i

:cleanup
 erase *.var
 set next=
 set offset=
 set total=
 set count=
 set var=
 set var1=
 set var2=
 goto :eof

:showval
 type _%1.var
 goto :eof

摘要

希望本文能为您提供一些关于批处理文件编程强大功能的见解。并非总是需要启动复杂的IDE来创建软件。有时我们需要的工具就在我们指尖。

有关Windows批处理命令的更多信息,请参阅Microsoft网站上的文档。您也可以使用Google找到大量资源。

高级批处理文件技术第1部分 - 冒泡排序 - CodeProject - 代码之家
© . All rights reserved.