![e70a2f2eac55ab11e41a4f5e394909c6.png](https://i-blog.csdnimg.cn/blog_migrate/78506a97fe5ef119033cd82d82965b32.jpeg)
- 栈:
后进先出(Last In First Out,LIFO)的线性序列,称为“栈”。栈也是一种线性表,只不过它是操作受限的线性表,只能在一端进出操作。进出的一端称为栈顶(top),另一端称为栈底(base)。栈可以用顺序存储,也可以用链式存储,分别称为顺序栈和链栈。
![44041063715cc261813871ad2b4066ab.png](https://i-blog.csdnimg.cn/blog_migrate/b32a46f2e8c85a4a415cb596f5fa0ca3.png)
顺序栈:
顺序栈需要两个指针,base表示栈底指针(指向首地址或基地址),top表示栈顶指针。(top指针永远指向空,即指向栈顶元素的下一位置)
![9e8567ac4499242aa06a1813aae1b9fc.png](https://i-blog.csdnimg.cn/blog_migrate/8d86f5b9942d7c5a034733429ed6ee5c.png)
typedef
顺序栈的动态分配:
![e71c6cb0fb817c8af1c35b4edf81ddb3.png](https://i-blog.csdnimg.cn/blog_migrate/82b5aed7504ce6a2ed3056d524303ebf.png)
顺序栈的静态分配:
![e4f80d112954d5efa7982b9cec68e438.png](https://i-blog.csdnimg.cn/blog_migrate/666bb9df769a11c95b922de178416123.png)
顺序栈初始化:
![01892dfa3d6aaebfd15402c9cb96117d.png](https://i-blog.csdnimg.cn/blog_migrate/15c8a4812a082855ee42f135e02c1982.png)
bool
顺序栈入栈:
注意:每次入栈前,都需要判断栈是否已满。
![fc2b01933b5553b08c6f627a0696fe6b.png](https://i-blog.csdnimg.cn/blog_migrate/89f0357f0f3cd43ed5d131291b0570ef.png)
bool
顺序栈出栈:
注意:每次出栈前都需要判断栈是否为空。
![e48a8ec3d22bb8cf06bb559e40973e22.png](https://i-blog.csdnimg.cn/blog_migrate/3bcf4cae32e6e7083b4b3c9cdc766249.png)
bool
顺序栈取栈顶:
![3f8688c48ef276da3386acae65d63d07.png](https://i-blog.csdnimg.cn/blog_migrate/40df4852d1f0c251786469a7ea2d2f09.png)
int
- 链栈:
链栈只需要一个指针S指向栈顶元素即可。
![fdbb7da4d9e1e9412739db239413262f.png](https://i-blog.csdnimg.cn/blog_migrate/9f24237ace6dc218d9dcc30018171d0d.png)
链栈入栈:
链栈入栈操作:入栈前:指针S指向栈顶结点;入栈后:新生成的结点,指针p指向它;然后把入栈前的栈顶结点的地址赋值给新生成结点的next域,最后更新S指针指向新生成的结点(指向栈顶结点)。
![046bf6bd13ce0d4e29e3b14fd372f5fc.png](https://i-blog.csdnimg.cn/blog_migrate/153b62232649bed013995dd0608bf54a.png)
链栈出栈:
链栈出栈:需要一个指针p标记栈顶元素,用于最后释放空间。出栈:首先:指针p指向栈顶结点,然后更新栈顶指针s指向下一个结点;最后释放指针p指向的结点即可。
![260cdd5166da0e3cb7f1a409e990be2f.png](https://i-blog.csdnimg.cn/blog_migrate/e17e065da8720af3ff70b53a03a5d38b.png)
链栈取栈顶:
链栈取栈顶只需要s->data,一步操作即可。
![b17441ff7b0aa6f2e34558f3ad4e31d3.png](https://i-blog.csdnimg.cn/blog_migrate/8d7a4458fa925430e6d7a807036843fb.png)
队列:
先进先出(First In First Out,FIFO)的线性序列,称为“队列”。队列也是一种线性表,只不过它是操作受限的线性表,只能在两端操作:一端进,一端出。进的一端称为队尾(rear),出的一端称为队头(front)。队列可以用顺序存储,也可以用链式存储。
![aebabdb60f1ba4ad8dc3a6cb7b994f01.png](https://i-blog.csdnimg.cn/blog_migrate/e275e0153bcec864ecb2004c35bd086a.png)
顺序队列
队列的顺序存储形式,可以用一段连续的空间存储数据元素,用两个整数变量记录队头和队尾元素的下标。
![3c587bd7f8f04fd4c47c1b5c09df44fb.png](https://i-blog.csdnimg.cn/blog_migrate/e94eb40fb96882bab89ee89c947d88f7.png)
顺序队列动态分配
typedef
![44c0c97c8bb08c002cad541c0f75d5e6.png](https://i-blog.csdnimg.cn/blog_migrate/ce824448e93cf1cadcec5ff3f0764411.png)
顺序队列静态分配:
![862b5b2ef2d630701e0be3b0be081d6a.png](https://i-blog.csdnimg.cn/blog_migrate/e0fd0f4ec07f4f81a12ded683d90823c.png)
顺序队列初始化
![62da75193de40e6433455354545b7cea.png](https://i-blog.csdnimg.cn/blog_migrate/4122ea019703f0a0582842a70f3b3d21.png)
//队列的初始化
顺序队列入队:
![02dcf486e33c7251a6eafaa4c0dbed16.png](https://i-blog.csdnimg.cn/blog_migrate/87eab7029523a358df6c20ff6413fc3e.png)
将新入队的元素,插在队尾,然后更新下表Q.rear。Q.rear和Q.front都是数组的下标,Q.base是数组。每次入队前要先判断对是否已满。
Q
![cbe201727526f4fe779aa685c246af25.png](https://i-blog.csdnimg.cn/blog_migrate/a708e657f88af83afc921e1815f8da84.png)
也可以一边入队,一遍出队。出队Q.front向后移动。
e
![c08abf009dfe60f2d3c16dafcc03558d.png](https://i-blog.csdnimg.cn/blog_migrate/31e2042b95c3819549613b21db284d20.png)
当尾指针指向了空,但是队列前面还存在未占用的空间,这种情况叫做假溢出。此时,将新来的元素插入到队首,这种队列叫做循环队列。代码如下处理,每次移动指针后对Maxsize取余处理临界状态。
(
![7b6de411ca844a3d706085f692dcfc60.png](https://i-blog.csdnimg.cn/blog_migrate/e2fec43a850264ac40e52d2f826e4875.png)
循环队列队空:
- 循环队列队空条件:
Q
![8037aeff5425eb6fd9c75cdf09f17b10.png](https://i-blog.csdnimg.cn/blog_migrate/2a19c7471f4eda9858cfc79be97bc0eb.png)
- 循环队列队满:
队满条件:浪费一个空间,当Q.rear的下一个元素为Q.front是表示队满。
(
![5e4df7d2472270d8473b430c0579d1f5.png](https://i-blog.csdnimg.cn/blog_migrate/8d992225a59bedd34b450ef3ecbab4d4.png)
循环队列入队
入队:
Q
![e39b030da681b638b8cb345c5c98756e.png](https://i-blog.csdnimg.cn/blog_migrate/c81010737d9a406d481d6267f1f09730.png)
//循环队列的入队
循环队列出队
- 循环队列出队:
e
![0435fbfb6cc68a85688c29c974c148fa.png](https://i-blog.csdnimg.cn/blog_migrate/a3f0d2986af88d3fa7ad6fcd770df032.png)
- 队列中元素个数:
(
![6f754c96b6f0ac66e257d5c0b39a394c.png](https://i-blog.csdnimg.cn/blog_migrate/12f28d8be0632fc12df67d34415004a7.png)
//循环队列的出队
链队:
需要头指针,出队跳过第一个结点,入队将新结点插入到尾部即可。
![4394207b2610a56a6300b83db69a7e58.png](https://i-blog.csdnimg.cn/blog_migrate/8999b55d1a604e521aa8aeab30f0a610.png)
链队出队:指针q指向要跳过的结点,如下图:
q
![17c87530e4227c699e2a74c109d56aec.png](https://i-blog.csdnimg.cn/blog_migrate/59fa038123715fe3a4a8fae0d53b1730.png)
链队入队:将新生成的结点,next域置空,原链队的next保存新生成的结点地址,更新Q.rear指向新入队的结点即可。
Q
![9e2a3e9a4d3193bbeee1d1a797170a23.png](https://i-blog.csdnimg.cn/blog_migrate/b453739c24d23f094ca5392276aa853b.png)
栈完整代码:
https://github.com/xinhai2017/Data-Structures-and-Algorithms/blob/master/3.1.SqStack.cppgithub.com队列完整代码:
https://github.com/xinhai2017/Data-Structures-and-Algorithms/blob/master/3.2.SqQueue.cppgithub.com