Board logo

标题: [求助]数值排序(难并已解) [打印本页]

作者: bat-zw     时间: 2008-4-29 22:22    标题: [求助]数值排序(难并已解)

如有一列数值如:56 12 33 48 99 105 5 16
怎么通过批处理输出为:5 12 16 33 48 56 99 105
要求不生成任何临时文件。
----------------------------------------------------------------------------------------------------------
综合所有,本人的通用代码如下:
@echo off&setlocal enabledelayedexpansion
set "str=56 12 33 48 99 105 5 16"
for %%i in (%str%) do call,set var=!var! n%%in
for %%i in (%var%) do set a=%%i&call :lp
echo !var:n=!
pause>nul&goto :eof
:lp
for %%i in (%var%) do (
    set b=%%i&set b=!b:~1,-1!&set c=%a:~1,-1%
    if !b! lss !c! (
       set var=!var:%a% =!
       set var=!var:%%i=%%i %a%!
       ) else (
       set var=!var!
   )
)
再扩展:
@echo off&setlocal enabledelayedexpansion
set "str=%random% %random% -%random% %random% %random% %random% -%random%"
for %%i in (%str%) do call,set var=!var! n%%in
for %%i in (%var%) do set a=%%i&call :lp
echo !var:n=!
pause>nul&goto :eof
:lp
for %%i in (%var%) do (
    set b=%%i&set b=!b:~1,-1!&set c=%a:~1,-1%
    if !b! lss !c! (
       set var=!var:%a% =!
       set var=!var:%%i=%%i %a%!
       ) else (
       set var=!var!
   )   
)
[ Last edited by zw19750516 on 2008-5-4 at 09:20 PM ]
作者: qingfushuan     时间: 2008-4-29 22:40    标题: 先弄清问题,你写的是一行啊

按小>大的顺序排列吧
作者: HAT     时间: 2008-4-29 22:44
纯P的话,我一般是先比较长度,如果长度相同再比较大小。
作者: bjsh     时间: 2008-4-29 23:21
Linux

$ cat TEST
56
12
33
48
99
105
5
16

$ sort -n <TEST
5
12
16
33
48
56
99
105
作者: plp626     时间: 2008-4-29 23:34
版主也来凑热闹啦。。。

cmd就是没有shell强悍
作者: bat-zw     时间: 2008-4-29 23:37
到目前还没有完善的答案!
作者: terse     时间: 2008-4-29 23:56
@echo off&setlocal enabledelayedexpansion
set/p str=输入数字(用空格隔开)
for %%i in (%str%) do (
set str=0000000000%%i
set .!str:~-10! !random!=a
)
for /f "delims=.= " %%i in ('set .') do for /f "tokens=* delims=0" %%i in ("%%i") do if "%%i"=="" (set/p=0 <nul) else set/p=%%i <nul
pause>nul
作者: plp626     时间: 2008-4-29 23:59

@echo off&if not %1.==. goto%*
::plp@cn-dos.net|08-4-29
::数字排序。数字范围:(0-10^99)数字保存在dat.txt里,每行一个数字
if not exist dat.txt echo 缺少dat.txt&pause&exit
for /f "delims= " %%a in ('"%0" :sor^|sort')do echo %%a
pause
:sor
  setlocal enabledelayedexpansion
  for /f %%a in (dat.txt)do (set d=%%a
    call:byte&call:space
    echo\!sp!!d!
  )
exit/b
:byte
  for /l %%z in (1 1 100)do if "!d:~%%z,1!"=="" set/a byte=100-%%z&goto:eof
:space
  set "sp="
  for /l %%z in (1 1 %byte%)do set "sp=!sp! "
goto:eof
数字不是每行一个的,先用这个代码改为每行一个
@echo off
for /f "delims=" %%a in (test.txt)do call:dd %%a
exit
:dd
if %1.=. goto:eof
>>dat.txt echo %1
shift
goto:dd
[ Last edited by plp626 on 2008-4-30 at 01:41 PM ]
作者: HAT     时间: 2008-4-30 00:01
不知道 s11ss 兄的排序算法能否满足楼主的需求
''''''''      排序      ''''''''
''''''''s11ss 2007-10-18''''''''

option explicit
'接收输入:
dim s,r,n,i
s=inputbox(vbcrlf&vbcrlf&"以空格隔开:","请输入一组数:","2007 10 18 21 15")
if s="" then wscript.quit
r=split(s," ")
n=ubound(r)
        '把字符串转换为Double 子类型:
for i=0 to n
        r(i)=cdbl(r(i))
next

'快速排序方法调用:
quicksort r,0,n
'其它排序方法的调用:
'insertsort r
'shellsort r
'bubblesort r
'selectsort r
'heapsort r

'输出结果:
inputbox vbcrlf&vbcrlf&"按升序排列是:","结果",join(r," ")

'各种排序子过程自定义:
'直接插入排序:
sub insertsort(r)
        dim i,n,t,j
        n=ubound(r)
        for i=1 to n'依次插入r(1),r(2),...,r(n)
                t=r(i)
                j=i-1
                do while t<r(j)'查找r(i)的插入位置
                        r(j+1)=r(j)'将大于r(i)的数后移
                        j=j-1
                        if j=-1 then exit do
                loop
                r(j+1)=t'插入r(i)
        next
end sub

'希尔排序:
sub shellsort(r)
                '设置增量序列:
        dim i,d(),n,t,k,h,j
        n=ubound(r)
        i=0
        redim d(n)
        d(i)=fix(n/2)
        do until d(i)=1
                t=d(i)
                i=i+1
                d(i)=fix(t/2)
        loop
                '排序:
        k=0
        do
                h=d(k)'取本趟增量
                for i=h to n'r(h)到r(n)插入当前有序区
                        t=r(i)'保存待插入数
                        j=i-h
                        do while t<r(j)'查找正确的插入位置
                                r(j+h)=r(j)'后移
                                j=j-h'得到前一数的位置
                                if j<0 then exit do
                        loop
                        r(j+h)=t'插入r(i)
                next'本趟排序完成
                k=k+1
        loop while h<>1
end sub

'冒泡排序:
sub bubblesort(r)
        dim i,n,noswap,j,t
        n=ubound(r)
        for i=0 to n-1'做n趟排序
                noswap=True'置未交换标志
                for j=n-1 to i step -1'从下往上扫描
                        if r(j+1)<r(j) then'交换
                                t=r(j)
                                r(j)=r(j+1)
                                r(j+1)=t
                                noswap=False
                        end if
                next
                if noswap then exit for'本趟排序中未发生交换则终止算法
        next
end sub

'快速排序:
        '划分:
function partition(r,l,h)
        dim i,j,t
        i=l
        j=h
        t=r(i)'初始化,t为基准
        do
                while r(j)>=t and i<j
                        j=j-1'从右向左扫描,查找第1个小于t的数
                wend
                if i<j then
                        r(i)=r(j)'交换r(i)和r(j)
                        i=i+1
                end if
                while r(i)<=t and i<j
                        i=i+1'从左向右扫描,查找第1个大于t的数
                wend
                if i<j then
                        r(j)=r(i)'交换r(i)和r(j)
                        j=j-1
                end if               
        loop while i<>j
        r(i)=t'基准t已被最后定位
        partition=i
end function
        '排序:
sub quicksort(r,s1,t1)
        dim i
        if s1<t1 then'只有一个数或无数时无须排序
                i=partition(r,s1,t1)'对r(s1)到r(t1)做划分
                quicksort r,s1,i-1'递归处理左区间
                quicksort r,i+1,t1'递归处理右区间
        end if
end sub

'直接选择排序:
sub selectsort(r)
        dim i,n,k,j,t
        n=ubound(r)
        for i=0 to n-1'做n趟排序
                k=i
                for j=i+1 to n'在当前无序区选最小的数r(k)
                        if r(j)<r(k) then k=j
                next
                if k<>i then
                        t=r(i)
                        r(i)=r(k)
                        r(k)=t
                end if
        next
end sub

'堆排序:
        '筛选:
sub sift(r,i,m)'以r(i)为根的完全二叉树构成堆
        dim t,j
        t=r(i)
        j=2*i
        do while j<=m'j<=m,r(2*i)是r(i)的左孩子
                if j<m then
                        if r(j)<r(j+1) then j=j+1'j指向r(i)的右孩子
                end if
                if t<r(j) then'孩子节点的数较大
                        r(i)=r(j)'将r(j)换到双亲位置上
                        i=j'修改当前被调整节点
                        j=2*i
                else
                        exit do'调整完毕,退出循环
                end if
        loop
        r(i)=t'最初被调整节点放入正确位置
end sub
        '排序:
sub heapsort(r)
        dim i,n,t
        n=ubound(r)
        for i=fix(n/2) to 0 step -1'建初始堆
                sift r,i,n
        next
        for i=n to 0 step -1'进行n+1趟排序
                t=r(0)'当前堆顶数和最后一个数交换
                r(0)=r(i)
                r(i)=t
                sift r,0,i-1'r(0)到r(i-1)重建成堆
        next
end sub

作者: bat-zw     时间: 2008-4-30 00:04    标题: 我只想了个通用性不是很强的:

郁闷啊,个位数不能有重复的:
@echo off&setlocal enabledelayedexpansion
set "str=101 20 14 13 19 18 16 11 5"
for %%i in (%str%) do set a=%%i&call :lp
echo %str%
pause>nul&goto :eof
:lp
for %%i in (%str%) do (
    if %%i lss %a% (
       set str=!str:%a% =!
       set str=!str:%%i=%%i %a%!
    )
)

作者: terse     时间: 2008-4-30 00:11
我8楼的不合要求吗
set/p str=输入数字(用空格隔开)  改成   set "str=101 20 14 13 19 18 16 11 5"
应该可以的吧
作者: bat-zw     时间: 2008-4-30 00:18


  Quote:
Originally posted by terse at 2008-4-30 00:11:
我8楼的不合要求吗
set/p str=输入数字(用空格隔开)  改成   set "str=101 20 14 13 19 18 16 11 5"
应该可以的吧

terse八楼的代码太强了,说老实话,我现在还没看明白是怎么一回事,请terse兄弟能帮解释下啊!
作者: HAT     时间: 2008-4-30 00:32


  Quote:
Originally posted by plp626 at 2008-4-30 12:04 AM:
要不用cmd,哪有linux的shell来的方便,快捷,高效?
声明,我不懂linux.

这个不需要懂linux吧,只需要下载GNU的sort.exe然后在批处理中调用即可。
作者: pusofalse     时间: 2008-4-30 00:39


  Quote:
Originally posted by terse at 2008-4-29 11:56 PM:
@echo off&setlocal enabledelayedexpansion
set/p str=输入数字(用空格隔开)
for %%i in (%str%) do (
set str=0000000000%%i
set .!str:~-10! !random!=a
)
for /f "delims=.= "  ...

果真很强! 刚开始时没明白咋回事。。。

  Quote:
@echo off&setlocal enabledelayedexpansion
set/p str=输入数字(用空格隔开)
for %%i in (%str%) do (
set str=0000000000%%i
set .!str:~-10! !random!=a
)
set .
pause
for /f "delims=.= " %%a in ('set .') do for /f "tokens=* delims=0" %%i in ("%%a") do if "%%i"=="" (set/p=0 <nul) else set/p=%%i <nul
pause>nul

把代码改成这样之后 有点开窍了。。
作者: zh159     时间: 2008-4-30 01:51
以前用过的,忘了出自哪里了
@echo off
setlocal enabledelayedexpansion
    set numbers=%random% %random% %random% %random% %random% %random% %random% %random%
    echo 排序前数组为: %numbers%
    call :sort %numbers%
    echo 排序后数组为: %ret:~1%
pause
goto :eof

:sort
    set num=%1
    set str=%*
    for %%i in (%str%) do if !num! gtr %%i set num=%%i
    set ret=%ret% %num%
    if not "!str:%num%=!" == "" call :sort !str:%num%=!
goto :eof

作者: 26933062     时间: 2008-4-30 08:37
呵,没想数字排序居然在联盟掀起第二次风波。热闹。。
也贴一段以前的代码。助助兴
:
@echo off&goto start&rem 数字排序
a.txt 中为一行一个数字
可以对任何 200 位以内的整数进行排序。(包括负数、正数、0、及重复的数字)
缺点: 对于0开头的数字,结果会忽略首位的0
::by 26933062 2007-11-25
:start
setlocal EnableDelayedExpansion
for /l %%a in (1 1 200) do set lin=0!lin!
for /f %%a in (a.txt) do (
   set "str=%%a"
   if "!str:~0,1!"=="-" (set fus=a&set str=!str:~1!&set zf=_) else set zf=+
   set str=!lin!!str!
   set !zf!!str:~-200! !random!!random!!random!!random!!random!!random!!random!=a
)
if defined fus call :sort _ /r
call :sort +
pause&exit
:sort
for /f "tokens=1,2 delims=_+= " %%a in ('set %1^|sort %2') do (
   for /f "tokens=* delims=0" %%i in ("%%a") do (
      if "%1"=="_" (set fuhao=-) else set "fuhao="
      if "%%i"=="" (echo !fuhao!0) else echo !fuhao!%%i
   )
)
goto :eof

作者: zh159     时间: 2008-4-30 10:13
从负数到正数都可以,会去除重复的数字,对于开头为0得数字不能正确处理
@echo off
setlocal enabledelayedexpansion
set str= %random% %random% -%random% %random% %random% -%random% %random% -%random% %random% %random%
::对于 a.txt 中为一行一个数字采用下一行方式读取,上一行不要
::上一行set str= %random%...的数前面必需要有一个空格
::for /f %%i in (a.txt) do set str=!str! %%i
echo 排序前数组为: %str:~1%

:sort
    set num=m
    for %%i in (%str%) do if %%i lss !num! set num=%%i
    set ret=%ret% %num%
    set str=!str: %num%=!
    if not "%str%" == "" goto sort

echo 排序后数组为: %ret:~1%
pause
exit

作者: qzwqzw     时间: 2008-4-30 16:01
简化一下terse的方案,有不足再改吧
@echo off&setlocal enabledelayedexpansion
set/p str=输入数字(用空格隔开)
for %%i in (%str%) do (
    set str=0000000000%%i
    set .!str:~-10! !random!=%%i
)
for /f "tokens=2 delims==" %%i in ('set .') do set/p=%%i <nul
pause>nul

作者: lxmxn     时间: 2008-4-30 17:25
这么热闹,我也来一段了,缺点是效率有点低……
@echo off & Setlocal EnableDelayedExpansion

for /L %%i in (1,1,5) do (
        set skip=.!skip!
        findstr /rc:"^^!skip!$" file.txt|sort
)
for 里面的 5 根据数字的最大位数来指定,如果不知道也可以写个for语句计算出来,我这里免去了。
作者: huahua0919     时间: 2008-4-30 18:02


  Quote:
Originally posted by lxmxn at 2008-4-30 05:25 PM:
这么热闹,我也来一段了,缺点是效率有点低……
[code]@echo off & Setlocal EnableDelayedExpansion

for /L %%i in (1,1,5) do (
        set skip=.!skip!
        findstr /rc:"^^!ski ...

版主的代码没看懂,能否解释一下?
好象不支持负数排序
作者: lxmxn     时间: 2008-4-30 23:14


  Quote:
Originally posted by huahua0919 at 2008-4-30 18:02:

版主的代码没看懂,能否解释一下?
好象不支持负数排序

就是简单的根据数字位数,findstr 出从一位到五位的数,然后 sort 排序就可以了,不过前提是数字都是正整数,而且知道最大位数,严格说起来这个不算是排序~
作者: MLQX     时间: 2008-5-2 05:09    标题: 这种方法是什么原理?

为什么加一大串零在数字前,然后在环境变量里遍历时把零又截弃掉,它们便能自动排序?

请各位大侠提点一下.
作者: MLQX     时间: 2008-5-2 11:26    标题: 还有为什么要加一些随机数?

怎么没人理我?
作者: slore     时间: 2008-5-2 12:14
99
1
888

排序结果是
1
888
99

如果补0的话~结果为:

00001
00099
00888

……
作者: MLQX     时间: 2008-5-2 12:23    标题: 啊明白了,我真笨,没有想到这点

[quote]Originally posted by MLQX at 2008-5-2 11:26 AM:
谢谢了.quote]

[ Last edited by MLQX on 2008-5-2 at 12:34 PM ]
作者: MLQX     时间: 2008-5-2 12:45    标题: 妙,好精炼的代码



  Quote:
Originally posted by zh159 at 2008-4-30 01:51 AM:
以前用过的,忘了出自哪里了
[code]@echo off
setlocal enabledelayedexpansion
    set numbers=%random% %random% %random% %random% %random% %random% %random% %random%
    echo 排序前 ...

来此论坛学了3 天,今天总算能看懂这段代码了.
在俺这个菜鸟看来,这种思维方法很独特.
在别人看来,也许不是独特,而是经典.
作者: MLQX     时间: 2008-5-2 12:53    标题: 点号表示什么?



  Quote:
Originally posted by plp626 at 2008-4-29 11:59 PM:
[code]if not %1.==.

难首是文本文件里隐含的结束标志?抑或是表示行首或行尾的标志?

[ Last edited by MLQX on 2008-5-2 at 01:24 PM ]
作者: bat-zw     时间: 2008-5-3 22:19    标题: 再来个通用的:

&&想不到一石激起千重浪,几天未来论坛此贴已经变成了精华贴,而且如此之火,真是非我始之所料,今天将我原来的代码又研究了下,有了如下通用性极强的化码:
@echo off&setlocal enabledelayedexpansion
set "str=101 20 14 13 19 18 16 11 5 -7"
for %%i in (%str%) do call,set var=!var! n%%i
for %%i in (%var%) do set a=%%i&call :lp
echo !var:n=!
pause>nul&goto :eof
:lp
for %%i in (!var!) do (
    set b=%%i
    if !b:~1! lss %a:~1% (
       set var=!var:%a% =!
       set var=!var:%%i=%%i %a%!
    )
)

作者: MLQX     时间: 2008-5-4 00:41    标题: 我觉得有一个人的代码最精炼:

@echo off&for /f "delims=" %%i in ('sort /+n c.txt') do echo %%i


如果比较三位数,那么把n值改为3即可.
作者: terse     时间: 2008-5-4 12:02


  Quote:
Originally posted by zw19750516 at 2008-5-3 22:19:
&&想不到一石激起千重浪,几天未来论坛此贴已经变成了精华贴,而且如此之火,真是非我始之所料,今天将我原来的代码又研究了下,有了如下 ...

不通用  你这样试 set "str=1111 111 20 14 13 19 18 16 11 5 -7"
作者: bat-zw     时间: 2008-5-4 19:09    标题: 再优化:

我31楼的代码还是没有考虑到数值前面有n位相同的情况,再次修改如下:
@echo off&setlocal enabledelayedexpansion
set "str=%random% %random% -%random% %random% %random% %random% -%random% "
for %%i in (%str%) do call,set var=!var! n%%in
for %%i in (%var%) do set a=%%i&call :lp
echo !var:n=!
pause>nul&goto :eof
:lp
for %%i in (%var%) do (
    set b=%%i&set b=!b:~1,-1!&set c=%a:~1,-1%
    if !b! lss !c! (
       set var=!var:%a% =!
       set var=!var:%%i=%%i %a%!
    )
)

作者: 26933062     时间: 2008-5-4 19:58
标签后的代码好像逻辑上有问题,请测试以下数字。
set "str=111 2 555 111 2 -8 0 -9 9 5 0"