欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

通过一个小算法,谈谈学习如何编写程序

程序员文章站 2022-04-08 19:20:05
给定一个数字列表,返回其所有可能的排列 输入:[1,2,3]输出:[ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1]] 假定各个数字不相同 给出核心代码 private void dfs(int[] nums, boolean[] visit ......

给定一个数字列表,返回其所有可能的排列

输入:[1,2,3]
输出:
[
  [1,2,3],
  [1,3,2],
  [2,1,3],
  [2,3,1],
  [3,1,2],
  [3,2,1]
]

假定各个数字不相同

给出核心代码

   private void dfs(int[] nums,

                     boolean[] visited,
                     list<integer> permutation,
                     list<list<integer>> results) {
        if (nums.length == permutation.size()) {
            results.add(new arraylist<integer>(permutation));
            return;
        }
       
        for (int i = 0; i < nums.length; i++) {
            if (visited[i]) {
                continue;
            }
           
            permutation.add(nums[i]);
            visited[i] = true;
            dfs(nums, visited, permutation, results);
            visited[i] = false;
            permutation.remove(permutation.size() - 1);
        }
    }

考虑int[] nums={1,2,3,4}情况

——————————————————————————————————————————————

可以看下面各个量的变化情况,当看不懂算法的时候,可以用这种方法,自己一步一步模拟程序做了什么,就能明白代码的含义了

在这个小例子中,visted【】数组存放的是,1234是否在permutation中的状态,

对于1234这四个数,visited【0】=false,就代表1没在permutation中

1234会不断添加到permutation中,并且当4个数字都进入p中时,会得到一个结果;

——————————————————————————————————————————————

在模拟的过程中,我们明白各个变量发生了什么,所代表的意义

然后对于比较有代表性的几个位置,看看程序发生了什么

——————————————————————————————————————————————

1     观察程序回到dfs(tttf,1230)时

v2 变成f

p   变成1200

循环进入f3

而此时4不在p中

4进入p中

然后重新调用

dfs(ttft,1240)

可以预见,下一个进入result的就是1243

————————————————————————————————

2    继续观察程序运行到dfs(tttt,1432)

首先会将1432add进入result

然后回到dfs的位置

dfs(tttf,1430)的f1循环中,

继续运行

v1变成f  p变成143 此时v是 tftt然后

f2 t

f3 t

此时 dfs(tttf,1430)运行结束 a8位置

给出a8之前的三行

f2 f

p143

v2 t tftt

然后我们继续模拟程序

v2 f tfft

p14

f3 t

说明某个dfs已经完成了全部循环,这个dfs的位置应该是最近的一个没有被标号的dfs

因为有标号的,说明都被执行完了

goto a9

我们回到了 dfs(tfft,1400)a9

f3 f

p14

v3 t tfft

继续模拟程序

v3 f

p1

此时 dfs(tfft,1400)所在的循环也结束了

goto a10

说明dfs(tfff,1000) a10也执行结束了

观察dfs(tfff,1000) a10上面的三行代码

f0 f

p1

v0 f

继续进行

v0 f ffff

p0000

f1 f

p2

v1 t

dfs(ftff,2000)

——————————————————————————————————————————————————————————————

通过这两处 我们完全可以明白这些代码的意义了

对于任何一位上的某个数字a,在它进入p之后,对于这一位来讲,没进入p而比a更靠后的数字,会添加进p

而对于当添加一个元素进入后,它的下一位会从重新又从头去寻找v[i] t,也就是没有进入p的数字

而对于填入某个位置数字后的dfs执行完成了,如果后一位的数字都比前一位的数字在原数组更靠前,那么就会出现

每退掉一位,回到前一个dfs,而将要退掉这个位置的数字,而之前的数字,在原数组的位置都比这个数字靠前,所以之后的循环不会再有数字进入

如果是1432,那么会变成2000

如果是4321,那么会变成dfs(fttt,4000)结束,整个程序结束

——————————————————————————————————————————————————————————————

 

而学习其他代码的过程也类似

看懂了代码以后,尝试用自然程序做了什么说出来,如果能说明白发生了什么事,也就说明看懂了

然后再把自己想要完成的事梳理一下,拆解成一步一步要做的事,再用代码使其重新实现

学习代码的过程:

  模拟程序代码逐条运行 ——》尽量提炼出代码块的作用 ——》用自然语言 说明算法做了什么

而编写代码的过程:

  分析问题——》提出完成算法的各个步骤 ——》逐条编写代码完成各个步骤 ——》调试,带入测试数据

 

下面给出模拟程序运行时,各个变量的变化情况

dfs(ffff,0000)  //dfs(nums,ffff,,)为了方便 只写最频繁变化的两个参数

f0 f       //f(0) 为了方便写成 f0 v[0]是f

p1        //permutation={1} 为了方便写成 p1

v0 t     tfff      //v[0]改成0 visited变成 tfff

dfs(tfff,1000) a10

f0 t   

f1 f

p12

v1 t 

dfs(ttff,1200) a3

f0 t

f1 t

f2 f

p123

v2 t

dfs(tttf,1230) a1

f0 t

f1 t

f2 t

f3 f

p1234

v3 t

dfs(tttt,1234)

result 1234 //这里的dfs直接结束了 能找到

v3 f tttf

p123

goto a1 这里其实是方法a的 for循环结束了 返回a所在位置,继续下一行

v2 f ttff

p12

f3 f

p124

v3 t

dfs(ttft,1240) a2

f0 t

f1 t

f2 f

p1243

v2 t

dfs(tttt,1243)

result  1243

v2 f ttft

p124

f3 t

goto a2

v3 f ttff

p12

goto a3

v1 f tfff

p1 

f2 f

p13

v2 t tftf

dfs(tftf,1300) a6

f0 t

f1 f

p132

v1 t

dfs(tttf,1320) a4

f0 t

f1 t

f2 t

f3 f

p1324

v3 t tttt

dfs(tttt,1324)

result 1324

v3 f tttf

p132 

goto a4

v1 f tftf

p13

f2 t

f3 f

p134

v3 t tftt

dfs(tftt,1340) a5

f0 t

f1 f

p1342

v1 t tttt

dfs(tttt,1342)

result 1342

v1 f tftt

p134

f2 t

f3 t

goto a5

v3 f tftf

p13

goto a6

v2 f tfff

p1

f3 f

p14

v3 t tfft

dfs(tfft,1400)a9

f0 t

f1 f

p142

v1 t ttft

dfs(ttft,1420) a7

f0 t

f1 t

f2 f

p1423

v2 t tttt

dfs(tttt,1423)

result 1423

v2 f ttft

p142 

f3 t

goto a7

v1 f tfft

p14

f2 f

p143

v2 t tftt

dfs(tftt,1430) a8

f0 t

f1 f

p1432

v1 t

dfs(tttt,1432)

return 1432

v1 f tftt

p143

f2 t

f3 t

goto a8

v2 f tfft

p14

f3 t

goto a9

v3 f tfff

p1

goto a10

v0 f ffff

p000

f1 f

p2

v1 ftff

dfs(ftff,2000)

我们可以预见 下一个就是2134

我们已经完全可以预见程序将要完成什么了

也就是此时此刻,我们看懂了这段代码的含义