[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖

一个有限制的排序算法题

昨天群里看到的,
【吐槽】Tiger<haotian.fan@qq.com> 下午 2:09:55
网上看见一道题目,问下大家,
如果一个List只能移动第一项,请问如何排序?
【中华】zhonghua(1138520994) 下午 3:02:33
@Tiger Tiger 只能移动第一项是啥意思,栈之类的结构么
【吐槽】Tiger<haotian.fan@qq.com> 下午 3:02:56
就比如说 5 1 3 2 4只能移动5,不能移动其他元素
【吐槽】Tiger<haotian.fan@qq.com> 下午 3:03:11
stack overflow看到的,有点解不开
【中华】zhonghua(1138520994) 下午 3:04:28
这个移动是啥意思
pop(0)?
【吐槽】Tiger<haotian.fan@qq.com> 下午 3:04:54
比如说移到3后面就编程1 3 5 2 4

我的解法(伪插入排序,效率底下,各位大佬见笑):
  1. @echo off
  2. Setlocal enabledelayedexpansion
  3. ::CODER BY 老刘 POWERD BY iBAT
  4. Set /p List=
  5. Call :GetList !List!
  6. Set /A Count=1
  7. :Loop 首项逆向比较
  8. Set /A Flag1=0
  9. For /l %%a in (!prt! -1 1) Do (
  10. If !.1! Gtr !.%%a! (
  11. Call :MoveTo %%a
  12. Set /A Flag1=1
  13. Goto :JmpOut
  14. )
  15. )
  16. :JmpOut
  17. If !Flag1! Equ 1 Goto Loop
  18. Set /A Count+=1
  19. If !Count! Leq !prt! (
  20. Call :MoveTo !Count!
  21. Goto :Loop
  22. )
  23. For /l %%a in (1 1 !prt!) Do Set .%%a
  24. pause&"%~0"
  25. :GetList
  26. Set /A Prt=0
  27. Set list=%*
  28. For %%a In (%*) Do (
  29. Set /A Prt+=1
  30. Set .!Prt!=%%a
  31. )
  32. Goto :Eof
  33. :MoveTo 移动到原先第%1项的后面
  34. Set /A #=.1
  35. For /l %%a in (1 1 %1) Do (
  36. Set /A PlusOne=%%a+1
  37. Set /A .%%a=.!PlusOne!
  38. )
  39. Set /A .%1=#
  40. Goto :Eof
复制代码

本帖最后由 老刘1号 于 2019-1-24 13:06 编辑

回复 2# 523066680


    刚去拷问了一波问主,原话
每次移动完以后,只能移动第一个,插入以后,列表开头就是新的可移动元素

TOP

回复 4# 523066680


    总觉得不需要纠结结构……
我觉得问主的意思就是,第一个随意移动,其余的被动移动,顺便改变位置

TOP

补一个优化版
  1. @echo off
  2. Setlocal enabledelayedexpansion
  3. ::CODER BY 老刘 POWERD BY iBAT
  4. Set /p List=
  5. Call :GetList !List!
  6. Set /A Count=1
  7. :Loop
  8. Rem 首项逆向比较
  9. Set /A Flag1=0
  10. For /l %%a in (!prt! -1 1) Do (
  11. If !.1! Gtr !.%%a! (
  12. Call :MoveTo %%a
  13. set/p=移动到%%a后:<nul
  14. For /l %%a in (1 1 !prt!) Do Set/p=!.%%a!-<nul
  15. Echo.
  16. Set /A Flag1=1
  17. Goto :JmpOut
  18. )
  19. )
  20. :JmpOut
  21. If !Flag1! Equ 1 Goto Loop
  22. Rem 判断是否排序完成。
  23. Set /A Flag2=0
  24. For /l %%a in (1 1 !prt!) Do (
  25. Set /A PlusOne=%%a+1
  26. Set /A "#=.!PlusOne!"
  27. If !#! Lss !.%%a! (
  28. Set Flag2=1
  29. If %%a equ !prt! Set Flag2=0
  30. Goto :JmpOut2
  31. )
  32. )
  33. :JmpOut2
  34. If !Flag2! Equ 0 Goto End
  35. Rem 继续排序
  36. Set /A Count+=1
  37. If !Count! Leq !prt! (
  38. Call :MoveTo !Count!
  39. Set/p=移动到!Count!后:<nul
  40. For /l %%a in (1 1 !prt!) Do Set/p=!.%%a!-<nul
  41. Echo.
  42. Goto :Loop
  43. )
  44. :End
  45. For /l %%a in (1 1 !prt!) Do Set/p=!.%%a!-<nul
  46. Echo.&pause&"%~0"
  47. :GetList
  48. Set /A Prt=0
  49. Set list=%*
  50. For %%a In (%*) Do (
  51. Set /A Prt+=1
  52. Set .!Prt!=%%a
  53. )
  54. Goto :Eof
  55. :MoveTo 移动到原先第%1项的后面
  56. Set /A #=.1
  57. For /l %%a in (1 1 %1) Do (
  58. Set /A PlusOne=%%a+1
  59. Set /A .%%a=.!PlusOne!
  60. )
  61. Set /A .%1=#
  62. Goto :Eof
复制代码
  1. 5 1 3 2 4
  2. 移动到5后:1-3-2-4-5-
  3. 移动到2后:3-1-2-4-5-
  4. 移动到3后:1-2-3-4-5-
  5. 1-2-3-4-5-
  6. 请按任意键继续. . .
  7. 3 2 1
  8. 移动到3后:2-1-3-
  9. 移动到2后:1-2-3-
  10. 1-2-3-
  11. 请按任意键继续. . .
  12. 7 3 4 1 10 9 8 11 24
  13. 移动到4后:3-4-1-7-10-9-8-11-24-
  14. 移动到3后:4-1-3-7-10-9-8-11-24-
  15. 移动到3后:1-3-4-7-10-9-8-11-24-
  16. 移动到2后:3-1-4-7-10-9-8-11-24-
  17. 移动到2后:1-3-4-7-10-9-8-11-24-
  18. 移动到3后:3-4-1-7-10-9-8-11-24-
  19. 移动到3后:4-1-3-7-10-9-8-11-24-
  20. 移动到3后:1-3-4-7-10-9-8-11-24-
  21. 移动到4后:3-4-7-1-10-9-8-11-24-
  22. 移动到4后:4-7-1-3-10-9-8-11-24-
  23. 移动到4后:7-1-3-4-10-9-8-11-24-
  24. 移动到4后:1-3-4-7-10-9-8-11-24-
  25. 移动到5后:3-4-7-10-1-9-8-11-24-
  26. 移动到5后:4-7-10-1-3-9-8-11-24-
  27. 移动到5后:7-10-1-3-4-9-8-11-24-
  28. 移动到5后:10-1-3-4-7-9-8-11-24-
  29. 移动到7后:1-3-4-7-9-8-10-11-24-
  30. 移动到6后:3-4-7-9-8-1-10-11-24-
  31. 移动到6后:4-7-9-8-1-3-10-11-24-
  32. 移动到6后:7-9-8-1-3-4-10-11-24-
  33. 移动到6后:9-8-1-3-4-7-10-11-24-
  34. 移动到6后:8-1-3-4-7-9-10-11-24-
  35. 移动到5后:1-3-4-7-8-9-10-11-24-
  36. 1-3-4-7-8-9-10-11-24-
  37. 请按任意键继续. . .
  38. 1 2 3 5 4
  39. 移动到2后:2-1-3-5-4-
  40. 移动到2后:1-2-3-5-4-
  41. 移动到3后:2-3-1-5-4-
  42. 移动到3后:3-1-2-5-4-
  43. 移动到3后:1-2-3-5-4-
  44. 移动到4后:2-3-5-1-4-
  45. 移动到4后:3-5-1-2-4-
  46. 移动到4后:5-1-2-3-4-
  47. 移动到5后:1-2-3-4-5-
  48. 1-2-3-4-5-
  49. 请按任意键继续. . .
复制代码

TOP

本帖最后由 老刘1号 于 2019-1-22 14:28 编辑

回复 7# 523066680


    好思路,若完成效率应该比我那个高
250技术不忍破坏
1

评分人数

    • 523066680: 是的判断未写完,不知道会不会推倒重来PB + 1

TOP

本帖最后由 老刘1号 于 2019-1-22 16:55 编辑

回复 9# 523066680


    若不考虑效率的话,感觉可以把只移动首个元素这个限制用一个算法去除掉,直接完成任意两元素交换。
a b c d e f
b <-- --> e
b c d e f a
c d e b f a
d e b f a c
e b f a c d
b f a e c d
f a e c d b
a e c d b f

a b c d e f
a <-- --> c
b c a d e f
c a d e f b
a d e f c b
d e f c b a
e f c b a d
f c b a d e
c b a d e f

a b c
a <-- --> c
b c a
c a b
a c b
c b a

脑补算法中

TOP

回复 12# 523066680


    哈哈哈,人是那个人,群不是那个群

TOP

本帖最后由 老刘1号 于 2019-1-22 19:11 编辑

回复 12# 523066680


    伪元素交换的算法摸清了……
找个位置真费脑……杀了一大片脑细胞
  1. @echo off
  2. Setlocal enabledelayedexpansion
  3. ::CODER BY 老刘 POWERD BY iBAT
  4. ::Set /p List=
  5. Call :GetList 1 2 3 4 5
  6. Call :Xchg 1 4
  7. Call :Echo
  8. Call :Xchg 2 3
  9. Call :Echo
  10. Call :Xchg 2 5
  11. Call :Echo
  12. Call :Xchg 3 4
  13. Call :Echo
  14. Pause
  15. Exit
  16. :GetList
  17. Set /A Prt=0
  18. Set list=%*
  19. For %%a In (%*) Do (
  20. Set /A Prt+=1
  21. Set .!Prt!=%%a
  22. )
  23. Goto :Eof
  24. :XChg 两元素互换
  25. Rem 将需要互换的第一个元素换到第一位
  26. Set /A SubOne=%1-1
  27. For /l %%a in (1 1 !SubOne!) Do Call :MoveTo !Prt!
  28. Set /a Steps+=SubOne
  29. Rem 将需要互换的第一个元素塞到第二个元素后面
  30. Rem 计算新list中第二个元素的位置
  31. Set /A Arg2Index=%2-SubOne
  32. Rem 挪
  33. Call :MoveTo !Arg2Index!
  34. Set /a Steps+=1
  35. Rem 将需要互换的第二个元素换到第一位
  36. Set /a Arg2SubArg1SubOne=%2-%1-1
  37. For /l %%a in (1 1 !Arg2SubArg1SubOne!) Do Call :MoveTo !Prt!
  38. Set /a Steps+=Arg2SubArg1SubOne
  39. Rem 将第二个元素塞到原先第一个元素的位置
  40. Rem 计算新list中第一个元素之前元素的位置
  41. Set /a 第一个元素之前元素的位置=(%1+1)-(SubOne+1+Arg2SubArg1SubOne)+prt-1
  42. Rem 挪
  43. Call :MoveTo !第一个元素之前元素的位置!
  44. Set /a Steps+=1
  45. Rem 还原其余各元素位置
  46. Set /A Reserve=prt-((SubOne+1+Arg2SubArg1SubOne)-1)-1
  47. For /l %%a in (1 1 !Reserve!) Do Call :MoveTo !Prt!
  48. Set /a Steps+=Reserve
  49. Goto :Eof
  50. :MoveTo 移动到原先第%1个元素的后面
  51. Set /A #=.1
  52. For /l %%a in (1 1 %1) Do (
  53. Set /A PlusOne=%%a+1
  54. Set /A .%%a=.!PlusOne!
  55. )
  56. Set /A .%1=#
  57. Goto :Eof
  58. :Echo
  59. For /l %%a in (1 1 !prt!) Do Set/p=!.%%a!-<nul
  60. Echo.
  61. Goto :Eof
复制代码
4-2-3-1-5-
4-3-2-1-5-
4-5-2-1-3-
4-5-1-2-3-
请按任意键继续. . .
1

评分人数

TOP

回复 15# 523066680


    哈哈,这和批处理倒是关系不大, 主要是用“只移动第一个元素”来模拟“交换任意两个元素”比较蛋疼

TOP

本帖最后由 老刘1号 于 2019-1-22 19:23 编辑

补一个冒泡排序
  1. @echo off
  2. Setlocal enabledelayedexpansion
  3. ::CODER BY 老刘 POWERD BY iBAT
  4. Set /p List=
  5. Set /A Steps=0
  6. Call :冒泡排序算法 !List!
  7. Call :Echo
  8. Echo 第一个元素被移动的次数:!Steps!
  9. Pause
  10. :冒泡排序算法
  11. Call :GetList %*
  12. :Loop
  13. Set Flag=0
  14. For /l %%a in (2 1 !prt!) Do (
  15. Set /A SubOne=%%a-1
  16. Set /A #=.!SubOne!
  17. If !#! Gtr !.%%a! (
  18. Call :XChg !SubOne! %%a
  19. Set /A Flag=1
  20. )
  21. )
  22. If !Flag! Equ 1 Goto :Loop
  23. Goto :Eof
  24. :GetList
  25. Set /A Prt=0
  26. Set list=%*
  27. For %%a In (%*) Do (
  28. Set /A Prt+=1
  29. Set .!Prt!=%%a
  30. )
  31. Goto :Eof
  32. :XChg 两元素互换
  33. Rem 将需要互换的第一个元素换到第一位
  34. Set /A SubOne=%1-1
  35. For /l %%a in (1 1 !SubOne!) Do Call :MoveTo !Prt!
  36. Set /a Steps+=SubOne
  37. Rem 将需要互换的第一个元素塞到第二个元素后面
  38. Rem 计算新list中第二个元素的位置
  39. Set /A Arg2Index=%2-SubOne
  40. Rem 挪
  41. Call :MoveTo !Arg2Index!
  42. Set /a Steps+=1
  43. Rem 将需要互换的第二个元素换到第一位
  44. Set /a Arg2SubArg1SubOne=%2-%1-1
  45. For /l %%a in (1 1 !Arg2SubArg1SubOne!) Do Call :MoveTo !Prt!
  46. Set /a Steps+=Arg2SubArg1SubOne
  47. Rem 将第二个元素塞到原先第一个元素的位置
  48. Rem 计算新list中第一个元素之前元素的位置
  49. Set /a 第一个元素之前元素的位置=(%1+1)-(SubOne+1+Arg2SubArg1SubOne)+prt-1
  50. Rem 挪
  51. Call :MoveTo !第一个元素之前元素的位置!
  52. Set /a Steps+=1
  53. Rem 还原其余各元素位置
  54. Set /A Reserve=prt-((SubOne+1+Arg2SubArg1SubOne)-1)-1
  55. For /l %%a in (1 1 !Reserve!) Do Call :MoveTo !Prt!
  56. Set /a Steps+=Reserve
  57. Goto :Eof
  58. :MoveTo 移动到原先第%1个元素的后面
  59. Set /A #=.1
  60. For /l %%a in (1 1 %1) Do (
  61. Set /A PlusOne=%%a+1
  62. Set /A .%%a=.!PlusOne!
  63. )
  64. Set /A .%1=#
  65. Goto :Eof
  66. :Echo
  67. For /l %%a in (1 1 !prt!) Do Set/p=!.%%a!-<nul
  68. Echo.
  69. Goto :Eof
复制代码
7 3 4 1 10 9 8 11 24
1-3-4-7-8-9-10-11-24-
第一个元素被移动的次数:80
请按任意键继续. . .
1

评分人数

TOP

本帖最后由 老刘1号 于 2019-1-22 23:51 编辑

选择排序
  1. @echo off
  2. Setlocal enabledelayedexpansion
  3. ::CODER BY 老刘 POWERD BY iBAT
  4. Set /p List=
  5. Set /A Steps=0
  6. Call :选择排序算法 !List!
  7. Call :Echo
  8. Echo 第一个元素被移动的次数:!Steps!
  9. Pause
  10. :选择排序算法
  11. Call :GetList %*
  12. Set /A Count=0
  13. :Loop
  14. Set /A Count+=1
  15. Set /A #=.!Count!
  16. For /l %%a in (!Count! 1 !prt!) Do (
  17. If !.%%a! Leq !#! (
  18. Set /A #=.%%a
  19. Set /A Index=%%a
  20. )
  21. )
  22. If !Count! Neq !Index! Call :XChg !Count! !Index!
  23. If !Count! Lss !prt! Goto :Loop
  24. Goto :Eof
  25. :GetList
  26. Set /A Prt=0
  27. Set list=%*
  28. For %%a In (%*) Do (
  29. Set /A Prt+=1
  30. Set .!Prt!=%%a
  31. )
  32. Goto :Eof
  33. :XChg 两元素互换
  34. Rem 将需要互换的第一个元素换到第一位
  35. Set /A SubOne=%1-1
  36. For /l %%a in (1 1 !SubOne!) Do Call :MoveTo !Prt!
  37. Set /a Steps+=SubOne
  38. Rem 将需要互换的第一个元素塞到第二个元素后面
  39. Rem 计算新list中第二个元素的位置
  40. Set /A Arg2Index=%2-SubOne
  41. Rem 挪
  42. Call :MoveTo !Arg2Index!
  43. Set /a Steps+=1
  44. Rem 将需要互换的第二个元素换到第一位
  45. Set /a Arg2SubArg1SubOne=%2-%1-1
  46. For /l %%a in (1 1 !Arg2SubArg1SubOne!) Do Call :MoveTo !Prt!
  47. Set /a Steps+=Arg2SubArg1SubOne
  48. Rem 将第二个元素塞到原先第一个元素的位置
  49. Rem 计算新list中第一个元素之前元素的位置
  50. Set /a 第一个元素之前元素的位置=(%1+1)-(SubOne+1+Arg2SubArg1SubOne)+prt-1
  51. Rem 挪
  52. Call :MoveTo !第一个元素之前元素的位置!
  53. Set /a Steps+=1
  54. Rem 还原其余各元素位置
  55. Set /A Reserve=prt-((SubOne+1+Arg2SubArg1SubOne)-1)-1
  56. For /l %%a in (1 1 !Reserve!) Do Call :MoveTo !Prt!
  57. Set /a Steps+=Reserve
  58. Goto :Eof
  59. :MoveTo 移动到原先第%1个元素的后面
  60. Set /A #=.1
  61. For /l %%a in (1 1 %1) Do (
  62. Set /A PlusOne=%%a+1
  63. Set /A .%%a=.!PlusOne!
  64. )
  65. Set /A .%1=#
  66. Goto :Eof
  67. :Echo
  68. For /l %%a in (1 1 !prt!) Do Set/p=!.%%a!-<nul
  69. Echo.
  70. Goto :Eof
复制代码
7 3 4 1 10 9 8 11 24
1-3-4-7-8-9-10-11-24-
第一个元素被移动的次数:20
请按任意键继续. . .

TOP

回复 17# 523066680


    学习了,又秒杀我那个无脑挪法……(固定挪表长+1次)
不知有没有最佳方案,明天再想想
论坛真是藏龙卧虎,不发点题都不肯出来

TOP

回复 22# search_Sudoku


    看懂了,谢大佬

TOP

本帖最后由 老刘1号 于 2019-1-23 12:09 编辑

回复 25# 523066680


    简单明了、高效,学习了。
我的思路(调换3与7)
12345678 - 不想太多,操作3与7就等到能操作的时候再操作,其他按顺序塞到后面
1234567812 - 此时所用步数记作step1
  345673812 - 3与7互换,∴先将3放到7后面
   45673812#456 - 继续无脑挪到7可操作,步数记为step2
      738127456 - 将7放到原先3的位置(4之前)
       3812745638 - 恢复原顺序,步数记为step3

由于一波操作下来除了3其它数字都移动一次,而3移动2次,∴总步数为表长+1
下面默认数组下标从1开始,
step1=%第一个数下标(3)%-1
step2=(%第二个数下标(7)%-%第一个数下标(3)%)-1
#一直固定在最开始第一个数(3)后面一个数(4)的前面
∴要计算第二个数(7)需要移动到的位置,就计算"最开始第一个数后面的一个数(4)“的位置。
由于前面每次移动都必然会移动到4的后面,∴4的新下标=4的原下标-步数+表长=(3的原下标+1)-(step1+1+step2)+表长
∴第二个数(7)需要移动到”4的新下标-1“这个下标代表的数的后面,即"(3的原下标+1)-(step1+1+step2)+表长-1"
step3=总步数-已走步数=(表长+1)-(step1+1+step2+1)

真蛋疼

TOP

本帖最后由 老刘1号 于 2019-1-23 19:26 编辑

回复 22# search_Sudoku


    用批实现一个,带二分的之后补上,
在表尾构建有序数列(非二分检索,倒序检索).BAT
  1. @echo off
  2. Setlocal enabledelayedexpansion
  3. ::CODER BY 老刘 POWERD BY iBAT
  4. Set /p List=
  5. Call :GetList !List!
  6. Set /A 判断次数=0,挪移次数=0
  7. Rem 确定末尾有序数组的起始位置
  8. Set /A point=prt-1
  9. For /l %%a in (!prt! -1 2) Do (
  10. Set /A SubOne=%%a-1
  11. Set /A #=.!SubOne!
  12. Set /A 判断次数+=1
  13. If !#! Gtr !.%%a! (
  14. Set /A Point=SubOne
  15. Goto :JmpOut1
  16. )
  17. )
  18. :JmpOut1
  19. Rem 挪
  20. For /l %%a in (!Point! -1 1) Do Call :挪 %%a
  21. Goto :Next
  22. :挪
  23. For /l %%b in (!prt! -1 %1) Do (
  24. Set /A 判断次数+=1
  25. If !.1! Gtr !.%%b! (
  26. Call :MoveTo %%b
  27. Set /a 挪移次数+=1
  28. Set/p=移到%%b后:<nul
  29. Call :Echo
  30. Goto :JmpOut2
  31. )
  32. )
  33. :JmpOut2
  34. Rem 处理首个元素比末尾有序数组全小的情况
  35. Set /A 判断次数+=1
  36. If !.1! Lss !.%1! (
  37. Call :MoveTo %1
  38. Set /a 挪移次数+=1
  39. Set/p=移到%1后:<nul
  40. Call :Echo
  41. )
  42. Goto :Eof
  43. :Next
  44. Set 判断次数
  45. Set 挪移次数
  46. pause&"%~0"
  47. :GetList
  48. Set /A Prt=0
  49. Set list=%*
  50. For %%a In (%*) Do (
  51. Set /A Prt+=1
  52. Set .!Prt!=%%a
  53. )
  54. Goto :Eof
  55. :MoveTo 移动到原先第%1项的后面
  56. Set /A #=.1
  57. For /l %%a in (1 1 %1) Do (
  58. Set /A PlusOne=%%a+1
  59. Set /A .%%a=.!PlusOne!
  60. )
  61. Set /A .%1=#
  62. Goto :Eof
  63. :Echo
  64. For /l %%a in (1 1 !prt!) Do Set/p=!.%%a!-<nul
  65. Echo.
  66. Goto :Eof
复制代码
1 3 5 2 4
移到3后:3-5-1-2-4-
移到4后:5-1-2-3-4-
移到5后:1-2-3-4-5-
判断次数=11
挪移次数=3
请按任意键继续. . .
7 3 4 1 10 9 8 11 24
移到6后:3-4-1-10-9-7-8-11-24-
移到5后:4-1-10-9-3-7-8-11-24-
移到5后:1-10-9-3-4-7-8-11-24-
移到4后:10-9-3-1-4-7-8-11-24-
移到7后:9-3-1-4-7-8-10-11-24-
移到6后:3-1-4-7-8-9-10-11-24-
移到2后:1-3-4-7-8-9-10-11-24-
判断次数=38
挪移次数=7
请按任意键继续. . .
25 23 4 9 8 2 1 12 15
移到9后:23-4-9-8-2-1-12-15-25-
移到8后:4-9-8-2-1-12-15-23-25-
移到5后:9-8-2-1-4-12-15-23-25-
移到5后:8-2-1-4-9-12-15-23-25-
移到4后:2-1-4-8-9-12-15-23-25-
移到2后:1-2-4-8-9-12-15-23-25-
判断次数=36
挪移次数=6
请按任意键继续. . .

TOP

返回列表