在 C 语言实现一个队列,最źǒng yǒu 直接的方式就是用数组做存,然后维护一个头尾指针。别想啥 fancy 的数据结构,就讲究最笨车最省事儿。 想象一下,你面前有一排长桌子,队列就是站在桌子排队的选手。队头就是第一个进场的人,队尾就是最终一个。每个人进的时候往后面挪,退的时候往前挪,中间不能乱撞。 比如你写个程序,栈容量是 10。你往栈顶压 5 个整数,分别是 1, 2, 3, 4, 5。

这时候栈顶指针指向 5,队头便指向 1。

要是要把 1 拿出来,你得先往后退指针,把 5 移走,再往前移,这样 1 自然就出来。 为了把代码写简易点,我常把栈顶和队头这两个概念混在一起搞,把数组看作一个容器。你只需求一个 tail 变量记录队头,一个 head 变量记录队尾。当你 push 的时候,把数据塞进 tail,然后 tail 往后挪一格。当你 pop 的时候,拿 tail 的数据出来,head 往后挪一格。 有时候你会发现,直接把数组当栈用也挺顺的。

比如你用一个整型数组存元素。

每次 push 时,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 时,直接拿走队头的数据,再把队头往后移一格。

不过这种写法有个缺点,就是操作多了会越界,得小心点。 比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把指针往后挪;每次 pop 的时候,直接拿数据,再把指针往后挪。 不过这种思路有个隐患,就是要是指针挪得忒了得,可能会把内存给搞跑。

故此一般我们会设一个长度,保证指针不越界。

比如数组大小是 6,你顶多能存 6 个元素。当你 push 第 7 个元素的时候,你得先把前 6 个元素往后挪一格,这样第 7 个元素才进得去。 在实际编程里,你会发现大量人喜爱用 queue 结构体来封装。定义一个队列结构体,里面存个数组、头指针和尾指针。

然后在函数里写具体的逻辑。

比如定义一个函数,输入数组、头、尾、长度,函数内部就会依次执行 push 和 pop 的操作。 比如你写个函数,接纳一个队列,让你往队尾压入一个整数 x。函数先判断队列满了没,满了就回黄了。

然后把 x 存到队列的尾位置,再让尾指针往后挪一格。

要是没满,就把 x 存进去,尾指针往后挪。 再比如你要从队头弹出元素。先判断队是不是空的,空的就回黄了。

然后从队列的头位置取出元素,再让头指针往后挪一格。 有时候你会发现,用数组存队列的时候,需求特别小心。

比如你定义了一个数组,然后启动存数据。存的时候,你要记得把数组里的元素往后挪,这样后面的位置才会被空出来。

要是顺序搞反了,后面存的数据就会挤到前面去,害得整个队列顺序都乱了。 比如你要存 1, 2, 3。你先把 1 放进数组,再存 2,再存 3。

这时候数组里是 [1, 2, 3]。

要是你目前要 pop 1,你得把 1 拿出来,然后数组里的 2 往后挪,3 也往后挪。

这时候数组变成 [2, 3, 1]。

要是你这时候再 push 4,你得先把 2 往后挪,3 也往后挪,把 4 放进数组的末尾。

这时候数组变成 [2, 3, 4, 1]。 实际上队列的底层原理和栈挺像,都是后进先出。栈里压得再靠后,队里排得再靠前。

故此推的时候先压的,排得越早;出的时候先排的,拿得越前。 比如你有个队列,容量是 10。你推了 5 个元素,1, 2, 3, 4, 5。你目前要 pop 一个,你得先把 1 拿出来,然后数组里的 2, 3, 4, 5 往后挪。

这时候队列为 2, 3, 4, 5。 要是队列满了如何办?比如你已经存了 10 个元素,这时候再 push 一个,就得先把前 10 个往后挪一格,然后才能把新的元素塞进去。

要是这时候再 pop 一个,就得把 10 个往后挪,再拿走 10 的队头。 在实际使用中,你可能会遇到队空的情况。

比如你让队头往后挪一格,但这时候队头实际上已经指向队尾了。

这时候你再让队头往后挪,就会把队尾的数据给删掉了,害得队列实际上变短了。 比如你有一个队列,当前队头指向 2,队尾指向 5。

这时候你再执行一次让队头往后挪的操作,队列就变成了 3, 4, 5。

这时候队头实际上是指向 3 了,但队尾还是 5。

要是你再 pop 一次,就拿走了 3,结局队列变成 4, 5。

这时候队头变成了 4,队尾还是 5。

看起来仿佛没难题,但要是你再 push 一个 6,你得先让队头往后挪,把 4 挪走,让 5 挪走,再让 6 进去。

这时候队头变成了 5,队尾是 6。 实际上这种操作挺好办出错。

比如你让队头往后挪的时候,要是当时队头已经等于队尾,你还会再往后挪一次,这样数据就没了。 比如你有一个队列,队头指向 1,队尾指向 1。

这时候你再让队头往后挪,队头会指向 2,队尾还是 1。

这时候队里只有一个元素 2。再让队头往后挪,队头变成 3,队尾还是 1。

这时候队里仿佛没了元素,但实际上队头指向 3,队尾指向 1。

要是你再 pop 一次,就拿走了 3,结局队里没了东西。 这时候就需求一个判断,让队头不能等于队尾。

要是队头等于队尾,说明队列满了。

这时候你再让队头往后挪,数据就没了。

故此得加个判断,防止这种情况形成。 比如写个函数,在让队头往后挪之前,先判断队头是否等于队尾。

要是是,就回操作黄了。否则,再执行让队头往后挪的操作。 比如你有一个队列,当前队头指向 1,队尾指向 5。

这时候你再执行一次让队头往后挪的操作。先判断队头是否等于队尾,不是。

然后把 1 拿出来,队头变成 2,队尾还是 5。目前队里是 2, 3, 4, 5。 再执行一次,判断队头等于队尾,是。

这时候直接 return,表示操作黄了。目前队里还是 1, 2, 3, 4, 5。 实际上要是队头等于队尾,说明队列满了。

这时候你再 push 一个元素,就得先把前 5 个元素往后挪,然后才能把新的元素塞进去。

要么先让队头往后挪,再 push。 比如你有一个队列,队头指向 1,队尾指向 5。目前再 push 一个 6。你先让队头往后挪,队头变成 2,队尾还是 5。

这时候队里是 2, 3, 4, 5。

然后把 6 塞进队尾,队尾变成 6。目前队头是 2,队尾是 6。 要是这时候再 pop 一次,就拿走了 2,队头变成 3,队尾还是 6。目前队里是 3, 4, 5, 6。 实际上这种写法挺复杂的,好办出错。

比如要是你让队头往后挪的时候,队头已经等于队尾了,你就再往后挪一次,数据就没了。 比如你有一个队列,队头指向 1,队尾指向 1。

这时候你再让队头往后挪,数据就没了。

故此得先判断队头是否等于队尾。 实际上队列实现有大量种,比如用数组模拟栈,用双向链表模拟队列,要么直接用数组模拟队列。每种写法都有优缺点,看你如何选。 比如用数组模拟队列,你需求维护头尾指针,每次 push 的时候,先把数据存进去,再把尾指针往后挪。

每次 pop 的时候,直接把队头的数据拿出来,再把头指针往后挪。 比如你有一个队列,数组大小是 10,头指针指向 0,尾指针指向 5。目前再 push 一个 6。你先把 6 存进去,尾指针变成 6,头指针还是 0。目前队里是 0, 1, 2, 3, 4, 5, 6。 再 pop 一次,就拿走了 0,头指针变成 1,尾指针还是 6。目前队里是 1, 2, 3, 4, 5, 6。 要是这时候再 push 一个 7,你得先把 1 往后挪,2 往后挪,3 往后挪,4 往后挪,5 往后挪,6 往后挪,然后把 7 装进去。目前队头是 2,队尾是 7。 要是这时候再 pop 一次,就拿走了 2,头指针变成 3,尾指针还是 7。目前队里是 3, 4, 5, 6, 7。 实际上这种写法挺难的,好办搞混头尾指针。

比如你让尾指针往后挪的时候,要是尾指针已经等于队尾了,你就再往后挪一次,头指针就变成队尾加 1。 比如你有一个队列,数组大小是 6,头指针指向 1,尾指针指向 5。目前再 push 一个 6。你先把 6 存进去,尾指针变成 6,头指针还是 1。

这时候尾指针等于队尾了,说明满了。

这时候你再 push 一个 7,你得先把 1, 2, 3, 4, 5 往后挪,然后 7 装进去。 实际上这种写法也挺乱的,好办出错。

比如你让头指针往后挪的时候,要是头指针已经等于队尾了,你就再往后挪一次,头指针就变成队尾加 1。 比如你有一个队列,数组大小是 6,头指针指向 1,尾指针指向 1。目前再让头指针往后挪,数据就没了。

故此得先判断头指针是否等于尾指针。 实际上队列的底层原理和栈挺像,都是后进先出。栈里压得再靠后,队里排得再靠前。

故此推的时候先压的,排得越早;出的时候先排的,拿得越前。 比如你有个队列,容量是 10。你推了 5 个元素,1, 2, 3, 4, 5。你目前要 pop 一个,你得先把 1 拿出来,然后数组里的 2, 3, 4, 5 往后挪。

这时候队列为 2, 3, 4, 5。 要是队列满了如何办?比如你已经存了 10 个元素,这时候再 push 一个,就得先把前 10 个往后挪一格,然后才能把新的元素塞进去。

要是这时候再 pop 一个,就得把 10 个往后挪,再拿走 10 的队头。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向 4。

要是你 push 了 5,你得把 1 往后挪,2 往后挪,3 往后挪,4 往后挪(实际上这一步是富余的,出于 4 本身已经在队尾了),然后 5 进队列,tail 指向 5,head 还是 1。

这时候队列为 1, 2, 3, 4, 5。 要是你 pop 一次,你得拿走 1,然后 head 指向 2,tail 还是 5,队列变成 2, 3, 4, 5。再 pop 一次,拿走 2,队列为 3, 4, 5。 实际上队列里数据移动是挺费事的,但为了代码简化,有些时候我们会直接用数组模拟成双向链表,要么干脆就把队列和栈搞混来。

比如你用一个 int 数组,每次 push 的时候,先把数据存进去,再把数组末尾的“空隙”位置(也就是队头)往后移动一遍。

每次 pop 的时候,直接拿走队头的数据,再把队头往后移一格。 不过这种写法有个缺点,就是操作多了会越界,得小心点。

比如你要存 10 个元素,你先把 1 到 10 存进去。

这时候队头在 1,队尾在 10。

要是你再 push 一个 11,你得先把 1 往后挪到 0,再把 11 塞进 0 的位置,这样队头就变成了 0。再 push 一个 12,你得先把 0 往后挪到 1,再把 12 塞进 1 的位置。 写个例子吧,假设你有个队列,容量是 5。你目前要把 1, 2, 3, 4 进队列

这时候 head 指向 1,tail 指向