原副标题:小厂必不可少专业技能:计算机程序之堆栈
那时咱这首诗主要传授一类跟栈同列的计算机程序,那就是堆栈。堆栈和栈那样是一类特定的algorithms,但它的核心理念思想刚好恰好相反。二者的亲密关系就像字符串和二叉树那样,在相同的情景下要将它的促进作用充分发挥到恰到好处。在这首诗中,他们将详尽的传授呵呵堆栈此种计算机程序。
堆栈的核心理念特征刚好和栈恰好相反,堆栈的核心理念为Kosaraju,像咱每晚的多肽排队等候,先排队等候的人的确先略过多肽,先返回堆栈,后排队等候的的后做,后返回堆栈。
再比如说咱微服务网络中的NSSMQ,对应用程序的数个允诺须要依照次序消费需求时,这个这时候堆栈此种计算机程序毫无疑问不是一类最合适的同时实现形式。
接下去了,他们特别针对堆栈,展开三个详尽的传授。
什么是队列?
堆栈是和栈恰好相反的一类计算机程序,也是一类特定的algorithms,它和栈那样反之亦然由三个操作符形成,三个叫队头,除此之外三个操作符叫做郑谦。和栈相同的是,他们追加操作形式是在郑谦展开操作形式的,删掉操作形式是在队头顺利完成的。堆栈的追加叫做入团,删掉操作形式叫做罗足庆。下列是堆栈此种计算机程序的缓存储存图:
入团:堆栈追加原素的操作形式,叫做入团,为的是同时实现Kosaraju的此种效用,咱堆栈填入原素的操作过程是在郑谦顺利完成的,就像你做多肽排队等候或是饭堂打中餐,你根本无法排在堆栈的最终,而无法间接插在堆栈的最终方。上面是入团的左图:
罗足庆:堆栈删掉原素的操作形式,叫做罗足庆,为的是同时实现Kosaraju的此种效用,咱堆栈删掉原素的操作过程是在队头顺利完成的,就像你做多肽排队等候或是饭堂打中餐,先顺利完成的从后面依序选择退出。上面是罗足庆的左图:
堆栈的同时实现
接下去他们使用字符串和二叉树两种形式来同时实现堆栈此种计算机程序。
2.1字符串同时实现堆栈
2.1.1 堆栈的抽象父类
package com.ignoarance.stack;
/**
* @ClassName Queue
* @Description 堆栈抽象父类
* @Author ignorance
* @Version 1.0
**/
public abstract class Queue<T> {
private int size;//堆栈的实际有效原素个数
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
/**
* 判断当前堆栈是否满
* 是返回true,否返回false
* @return
*/
public abstract boolean isFull();
/**
* 判断当前堆栈是否空
* 是返回true,否返回false
* @return
*/
public abstract boolean isEmpty();
/**
* 入团核心理念方法
*/
public abstract void enQueue(T element);
/**
* 出堆栈方法
* 并返回罗足庆原素
* @return
*/
public abstract T deQueue();
/**
* 遍历方法
*/
public abstract void show();
}
2.1.2 字符串同时实现堆栈核心理念类ArrayQueue
ArrayQueue主要为字符串同时实现堆栈的核心理念类,在该类中,他们定义了三个变量名叫做elementData的字符串来存放原素,maxSize表示底层字符串的初始化长度,也就是堆栈能够存放原素的数量,front和rear分别表示队头和郑谦。在构造器中,他们初始化底层字符串长度,以及front和rear的初始值都为0。
package com.ignoarance.stack;
/**
* @ClassName ArrayQueue
* @Description TODO
* @Author ignorance
* @Version 1.0
**/
public class ArrayQueue<T> extends Queue<T> {
private T[] elementData;//存放原素的字符串
private int front;//队头操作符
private int rear;//郑谦操作符
private int maxSize;//堆栈最大个数
public ArrayQueue(T[] elementData) {
this.elementData = elementData;
this.maxSize = elementData.length;
this.front = this.rear = 0;
}
/**
* 判断当前堆栈是否满
* 是返回true,否返回false
* @return
*/
@Override
public boolean isFull() {
return false;
}
/**
* 判断当前堆栈是否空
* 是返回true,否返回false
*
* @return
*/
@Override
public boolean isEmpty() {
return false;
}
/**
* 入团核心理念方法
*
* @param element
*/
@Override
public void enQueue(T element) {
}
/**
* 出堆栈方法
* 并返回罗足庆原素
*
* @return
*/
@Override
public T deQueue() {
return null;
}
/**
* 遍历方法
*/
@Override
public void show() {
}
}
2.1.3 判断空队和满队
堆栈的空队和满队判断相比栈来说,稍微有点抽象,他们本次的堆栈为三个循环堆栈,他们通过上面的图来分析。
可以看出咱的堆栈,在满足front==rear的这时候,咱的堆栈不存在任何原素,故咱的堆栈为空。
@Override
public boolean isEmpty() {
return front == rear;
}
这个这时候咱的堆栈什么这时候满呢?可不是rear==maxSize-1啊,因为咱此时的堆栈是个循环堆栈,当rear=maxSize-1后,下次入堆栈的原素就应该放在咱堆栈的第三个位置。
为的是同时实现循环堆栈,这个这时候他们须要将front指向队头的第三个位置,也就是elementData[0]的位置,rear呢?他们指向堆栈最终三个原素的下三个位置,在此操作过程他们将字符串预留三个空间,目的是更方便咱进一步顺利完成构建循环堆栈这个操作过程,让缓存得以充分利用。
本来字符串的长度为maxSize,因为咱底层是字符串结构,这个这时候咱的堆栈储存的最大原素个数为maxSize-1。此时咱构建的循环堆栈满队的判断条件为(real+1)%maxSize==front才对。举个例子,咱刚开始满队,咱字符串的最大长度为5,front为0,rear为4时,咱的堆栈刚好满。此时代入公式结果为这样的:(4+1)%5==0==front。如果此时咱的堆栈罗足庆三个,这个这时候咱的队头front=2,rear仍然为4。但是这个这时候咱们的有效个数为3,还有三个位置可以继续添加,此时堆栈最终三个原素的索引为3,此时呢,下三个入团的索引就为4,继续入栈的索引为0。最终的rear为1。此时咱堆栈有效个数又变成了4,此时堆栈又满了。
这个这时候咱的公式代入表达式为(1+1)%5==front==2,刚好满队。如果有问题,咱看下图。
核心理念代码如下:
@Override
public boolean isFull() {
return (rear + 1) % maxSize == front;
}
2.1.4 堆栈的有效个数
@Override
public int getSize() {
return (rear + maxSize – front) % maxSize;
}
2.1.5 enQueue()方法
@Override
public void enQueue(T element) {
if (isFull()){
throw new RuntimeException(“【堆栈已满,无法入团…】”);
}
elementData[rear] = element;
//重置rear,循环使用字符串,防止字符串越界
rear = (rear + 1) % maxSize;
}
2.1.6 deQueue()方法
@Override
public T deQueue() {
if (isEmpty()){
throw new RuntimeException(“【堆栈为空,无法罗足庆…】”);
}
T curData = elementData[front];
//重置front,循环使用字符串,防止字符串越界
front = (front + 1) % maxSize;
return curData;
}
2.1.7 遍历
@Override
public void show() {
for (int i = front;i < front + getSize();i++){
System.out.println(“当前索引:” + (i % maxSize) + “—-” + elementData[i % maxSize]);
}
}
2.1.8 测试
package com.ignoarance.stack.test;
import com.ignoarance.stack.ArrayQueue;
import com.ignoarance.stack.Queue;
import org.junit.Test;
/**
* @ClassName QueueTest
* @Description 堆栈测试
* @Author ignorance
* @Version 1.0
**/
public class QueueTest {
@Test
public void test01(){
Queue<String> queue = new ArrayQueue<>(new String[5]);
queue.enQueue(“周芷若”);
queue.enQueue(“夏诗涵”);
queue.enQueue(“黄蓉”);
queue.enQueue(“郭靖”);
queue.show();
System.out.println(“【有效原素个数】:” + queue.getSize());
queue.deQueue();
System.out.println(“【有效原素个数】:” + queue.getSize());
queue.enQueue(“张无忌”);
queue.deQueue();
queue.enQueue(“楚雅柔”);
System.out.println(“【有效原素个数】:” + queue.getSize());
queue.show();
}
}
2.2二叉树同时实现堆栈
相比字符串同时实现堆栈,二叉树实在是再简单不过了,他们间接创建三个单二叉树即可:
2.2.1 同时实现代码
package com.ignoarance.stack;
import com.ignoarance.stack.node.Node;
/**
* @ClassName LinkedListQueue
* @Description TODO
* @Author ignorance
* @Version 1.0
**/
public class LinkedListQueue<T> extends Queue<T> {
private Node<T> front;//队头
private Node<T> rear;//郑谦
private Node<T> last;//尾结点
public LinkedListQueue() {
this.front = new Node<>(null);
this.rear = null;
}
/**
* 判断当前堆栈是否满
* 是返回true,否返回false
*
* @return
*/
@Override
public boolean isFull() {
throw new RuntimeException(“【不支持的操作形式…】”);
}
/**
* 判断当前堆栈是否空
* 是返回true,否返回false
*
* @return
*/
@Override
public boolean isEmpty() {
return front == null || front.next == null;
}
/**
* 入团核心理念方法
*
* @param element
*/
@Override
public void enQueue(T element) {
Node<T> insertNode = new Node<>(element);
if (isEmpty()){
front.next = insertNode;
rear = insertNode;
last = insertNode;
setSize(getSize() + 1);
return;
}
last.next = insertNode;
last = insertNode;
setSize(getSize() + 1);
}
/**
* 出堆栈方法
* 并返回罗足庆原素
*
* @return
*/
@Override
public T deQueue() {
if (isEmpty()){
throw new RuntimeException(“【堆栈为空,无法出栈…】”);
}
Node<T> curNode = rear;
front.next = curNode.next;
rear = curNode.next;
setSize(getSize() – 1);
return curNode.getItem();
}
/**
* 遍历方法
*/
@Override
public void show() {
if (isEmpty()){
throw new RuntimeException(“【堆栈为空,无法遍历…]”);
}
for (Node<T> cur = front.next;cur != null;cur = cur.next){
System.out.println(cur);
}
}
}
2.2.2 测试
@Test
public void test02(){
Queue<String> queue = new LinkedListQueue<>();
queue.enQueue(“周芷若”);
queue.enQueue(“夏诗涵”);
queue.enQueue(“黄蓉”);
queue.enQueue(“郭靖”);
queue.show();
System.out.println(“【罗足庆结点:】” + queue.deQueue());
System.out.println(“【罗足庆后】” + queue.getSize());
queue.show();
}
综合代码
下列是本首诗的相关代码,给大家做个借鉴和参考。
3.1结点类Node
package com.ignoarance.stack.node;
/**
* @ClassName Node
* @Description 结点类
* @Author ignorance
* @Version 1.0
**/
public class Node<T> {
private T item;
public Node<T> next;
public Node(T item) {
this.item = item;
}
public T getItem() {
return item;
}
public void setItem(T item) {
this.item = item;
}
@Override
public String toString() {
return “Node{” +
“item=” + item +
};
}
}
3.2堆栈抽象父类Queue
package com.ignoarance.stack;
/**
* @ClassName Queue
* @Description 堆栈抽象父类
* @Author ignorance
* @Version 1.0
**/
public abstract class Queue<T> {
private int size;//堆栈的实际有效原素个数
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
/**
* 判断当前堆栈是否满
* 是返回true,否返回false
* @return
*/
public abstract boolean isFull();
/**
* 判断当前堆栈是否空
* 是返回true,否返回false
* @return
*/
public abstract boolean isEmpty();
/**
* 入队核心理念方法
*/
public abstract void enQueue(T element);
/**
* 出堆栈方法
* 并返回罗足庆原素
* @return
*/
public abstract T deQueue();
/**
* 遍历方法
*/
public abstract void show();
}
3.3ArrayQueue
package com.ignoarance.stack;
/**
* @ClassName ArrayQueue
* @Description TODO
* @Author ignorance
* @Version 1.0
**/
public class ArrayQueue<T> extends Queue<T> {
private T[] elementData;//存放原素的字符串
private int front;//队头操作符
private int rear;//郑谦操作符
private int maxSize;//堆栈最大个数
public ArrayQueue(T[] elementData) {
this.elementData = elementData;
this.maxSize = elementData.length;
this.front = this.rear = 0;
}
@Override
public int getSize() {
return (rear + maxSize – front) % maxSize;
}
/**
* 判断当前堆栈是否满
* 是返回true,否返回false
* @return
*/
@Override
public boolean isFull() {
return (rear + 1) % maxSize == front;
}
/**
* 判断当前堆栈是否空
* 是返回true,否返回false
*
* @return
*/
@Override
public boolean isEmpty() {
return front == rear;
}
/**
* 入团核心理念方法
*
* @param element
*/
@Override
public void enQueue(T element) {
if (isFull()){
throw new RuntimeException(“【堆栈已满,无法入团…】”);
}
elementData[rear] = element;
//重置rear,循环使用字符串,防止字符串越界
rear = (rear + 1) % maxSize;
}
/**
* 出堆栈方法
* 并返回罗足庆原素
*
* @return
*/
@Override
public T deQueue() {
if (isEmpty()){
throw new RuntimeException(“【堆栈为空,无法罗足庆…】”);
}
T curData = elementData[front];
//重置front,循环使用字符串,防止字符串越界
front = (front + 1) % maxSize;
return curData;
}
/**
* 遍历方法
*/
@Override
public void show() {
for (int i = front;i < front + getSize();i++){
System.out.println(“当前索引:” + (i % maxSize) + “—-” + elementData[i % maxSize]);
}
}
}
3.4LinkedListQueue
package com.ignoarance.stack;
import com.ignoarance.stack.node.Node;
/**
* @ClassName LinkedListQueue
* @Description TODO
* @Author ignorance
* @Date 2022/9/26 2:00
* @Version 1.0
**/
public class LinkedListQueue<T> extends Queue<T> {
private Node<T> front;//队头
private Node<T> rear;//郑谦
private Node<T> last;//尾结点
public LinkedListQueue() {
this.front = new Node<>(null);
this.rear = null;
}
/**
* 判断当前堆栈是否满
* 是返回true,否返回false
*
* @return
*/
@Override
public boolean isFull() {
throw new RuntimeException(“【不支持的操作形式…】”);
}
/**
* 判断当前堆栈是否空
* 是返回true,否返回false
*
* @return
*/
@Override
public boolean isEmpty() {
return front == null || front.next == null;
}
/**
* 入团核心理念方法
*
* @param element
*/
@Override
public void enQueue(T element) {
Node<T> insertNode = new Node<>(element);
if (isEmpty()){
front.next = insertNode;
rear = insertNode;
last = insertNode;
setSize(getSize() + 1);
return;
}
last.next = insertNode;
last = insertNode;
setSize(getSize() + 1);
}
/**
* 出堆栈方法
* 并返回罗足庆原素
*
* @return
*/
@Override
public T deQueue() {
if (isEmpty()){
throw new RuntimeException(“【堆栈为空,无法出栈…】”);
}
Node<T> curNode = rear;
front.next = curNode.next;
rear = curNode.next;
setSize(getSize() – 1);
return curNode.getItem();
}
/**
* 遍历方法
*/
@Override
public void show() {
if (isEmpty()){
throw new RuntimeException(“【堆栈为空,无法遍历…]”);
}
for (Node<T> cur = front.next;cur != null;cur = cur.next){
System.out.println(cur);
}
}
}
3.5Queue测试类
package com.ignoarance.stack.test;
import com.ignoarance.stack.ArrayQueue;
import com.ignoarance.stack.LinkedListQueue;
import com.ignoarance.stack.Queue;
import org.junit.Test;
/**
* @ClassName QueueTest
* @Description 堆栈测试
* @Author ignorance
* @Version 1.0
**/
public class QueueTest {
@Test
public void test01(){
Queue<String> queue = new ArrayQueue<>(new String[5]);
queue.enQueue(“周芷若”);
queue.enQueue(“夏诗涵”);
queue.enQueue(“黄蓉”);
queue.enQueue(“郭靖”);
queue.show();
System.out.println(“【有效原素个数】:” + queue.getSize());
queue.deQueue();
System.out.println(“【有效原素个数】:” + queue.getSize());
queue.enQueue(“张无忌”);
queue.deQueue();
queue.enQueue(“楚雅柔”);
System.out.println(“【有效原素个数】:” + queue.getSize());
queue.show();
}
@Test
public void test02(){
Queue<String> queue = new LinkedListQueue<>();
queue.enQueue(“周芷若”);
queue.enQueue(“夏诗涵”);
queue.enQueue(“黄蓉”);
queue.enQueue(“郭靖”);
queue.show();
System.out.println(“【罗足庆结点:】” + queue.deQueue());
System.out.println(“【罗足庆后】” + queue.getSize());
queue.show();
}
}
总结
在本首诗中,咱主要讲了堆栈此种计算机程序,堆栈作为一类特别重要且常见特别重要的。
在学习的操作过程中,是三个很枯燥且乏味的操作过程,尤其是对一些抽象的知识百思不得其解的这时候,是最想放弃的这时候,但是学习的操作过程也是三个不断进步不断充实自己的操作过程,在三个困惑已久的问题突然心生灵感,豁然开朗时,对咱来说反之亦然又是一直无以言表的激动和快乐。
所以啊,加油吧!你的努力只有自己能看到,它将会为你博取三个更美好的明天,让你成为三个自己最想成为的那个人!