为什么要取余?

来源: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 是多少?做什么操作以后,循环队列的各种相关变量变成了什么?为什么这么变换?)


如果还有不理解的地方,你可以再结合具体的例子做提问(在这个例子中,我觉得在什么操作以后,结果应该是怎样的?但是实际或者根据课程的讲解,却是怎样的?不一致,所以我不理解。)结合一个具体的例子去学习,是最有效的学习方式。我们学习应该从具体到抽象,而非反过来。


==========


如果是面试的时候,也要现场推导出这个公式吗?


如果面试有类似的问题,是的,你需要现场搞定这步计算。实际上,这种求余运算,在很多面试场合中,根本不属于数学问题。所以你也不需要把他想得太“数学”,理解了,会用这个方式,就好了。这个课程的内容,基本上不存在必须专门学习某个数学领域(比如高数或者线数)才能学习的情况。


继续加油!:)

1

算法与数据结构

波波老师5年集大成之作,算法与数据结构系统学习,考试、面试、竞赛通用

2603 学习 · 1086 问题

查看课程

相似问题

回答 4

回答 1

回答 1

回答 2