为什么要取余?
来源:2-7 循环队列的实现
404_
2023-05-25 10:21:34
老师,您好!
我的数学不好。请问,判断循环队列满的时候为什么是**(tail + 1)%数组的长度 == front**?
这是怎么推导出来的?
还有扩容的时候 为什么是 data[(i+front)%数组的长度]
这些公式都是怎么推导出来的? 如果是面试的时候,也要现场推导出这个公式吗?
1回答
liuyubobobo
2023-05-26
假设数组有 n 个元素,这 n 个元素的索引是 0, 1, 2, 3, ... n - 1
0 的下一个元素是 1
1 的下一个元素是 2
2 的下一个元素是 3
...
这些应该都没问题,这些和普通的数组一样。
但关键是“循环队列”里,“循环”的意思多了一条 n - 1 的下一个元素是 0。
怎么做到让 n - 1 的下一个元素是 0?答案是 + 1 以后对 n 取模。即 (n - 1 + 1) % n = 0;
而对于索引小于 n - 1 的情况,这个取模不影响。因为 + 1 后的结果是 < n 的,所以对 n 取模以后还是它本身。比如 (0 + 1) % n = 1(假设 n > 1)。
如果对此还不理解,你就想钟表就好了。9 点钟再过 4 个小时,是几点钟(12 小时制),答案是 1 点钟。
1 是怎么算出来的?
如果你掰着手指头数,就是 9 -> 10 -> 11 -> 0 -> 1(4个箭头,走过了 4 个小时,最后停在了 1)。
如果一步继续算,就是 (9 + 4) % 12 = 1。9 + 4 本来等于 13,但是钟表一共只有 12 个位置,所以11 以后要循环为 0,我们使用求余运算。
这不求余不影响“不循环的情况”,比如 4 点钟再过 4 个小时,是几点钟?答案是 8 点钟。当然, 4 + 4 = 8,但是 (4 + 4) % 12 也等于 8。关键在于 8 还没有超出界,所以这步求余不影响这种情况的结果。
==========
如果理解了上面我解释的“为什么要用求余运算”,你可以再回顾一下课程中介绍的和循环队列相关的各种操作,看看是不是理解了?
如果还没有理解,你可以使用一个具体的例子去看一下(而不要对这“公式”发呆。)。事实上,课程的 PPT 中,都给出了一个具体的例子(假设 n 是多少?front 是多少?做什么操作以后,循环队列的各种相关变量变成了什么?为什么这么变换?)
如果还有不理解的地方,你可以再结合具体的例子做提问(在这个例子中,我觉得在什么操作以后,结果应该是怎样的?但是实际或者根据课程的讲解,却是怎样的?不一致,所以我不理解。)结合一个具体的例子去学习,是最有效的学习方式。我们学习应该从具体到抽象,而非反过来。
==========
如果是面试的时候,也要现场推导出这个公式吗?
如果面试有类似的问题,是的,你需要现场搞定这步计算。实际上,这种求余运算,在很多面试场合中,根本不属于数学问题。所以你也不需要把他想得太“数学”,理解了,会用这个方式,就好了。这个课程的内容,基本上不存在必须专门学习某个数学领域(比如高数或者线数)才能学习的情况。
继续加油!:)
相似问题