具体内容:
该文章的源代码仓库为:
- java:https://github.com/MeteorCh/DataStructure/tree/master/Java/DataStructure/src/StackAndQueue
- C++:https://github.com/MeteorCh/DataStructure/tree/master/C%2B%2B/DataStructure/DataStructure/StackAndQueue
一、栈
1.栈的定义
栈是限定仅在表尾进行插入和删除操作的线性表。把允许插入的一端称为栈顶,另一端称为栈底,不含任何元素的栈称为空栈。栈是后进先出的线性表。
2.栈的实现
栈的实现有数组和链表两种方式。其中,数组方式很简单,就是定义一个数组,然后用一个int类型的变量用来标识栈顶,每次入栈的时候将新元素插入到数组尾处,这里就不实现了。因为在链表一节中已经实现了单链表,以及在其尾部插入(相当于入栈操作)的算法,我们这里直接就继承我们实现的单链表,增加栈的弹栈、是否为空的判断两个方法。实现代码如下:
- Java
public class LinkStack<T> extends LinkList<T> {
public boolean isEmpty(){
return length==0;
}
/**
* 弹栈
* @return
*/
public T pop(){
if (this.head!=null){
return remove(this.length-1);
}
return null;
}
}
上述代码中,LinkList的实现见链表一节。使用示例如下:
LinkStack<String> stack=new LinkStack<>();
stack.pushBack("0");
stack.pushBack("1");
stack.pushBack("2");
System.out.println(stack);
System.out.println(stack.pop());
System.out.println(stack.pop());
System.out.println(stack.pop());
此处的链表是使用的尾插法,但是这样其实在弹栈以及入栈的时候性能并不好,因为每次入栈和弹栈都需要遍历链表,所以应该使用头插法,此处就需要重写单链表中的pushBack方法。重写后的链式存储栈的代码如下:
public class LinkStack<T> extends LinkList<T> {
public boolean isEmpty(){
return length==0;
}
/**
* 弹栈
* @return
*/
public T pop(){
if (this.head!=null){
return remove(0);
}
return null;
}
/**
* 获取栈尾元素,但并不弹出
* @return
*/
public T peek(){
if (this.head!=null){
return get(0);
}
return null;
}
/**
* 重写pushback方法,使用头插法,每次将节点插入到链表的头部
* @param data
*/
@Override
public void pushBack(T data) {
insert(0,data);
}
/**
* 重写toString方法,从后往前输出
* @return
*/
@Override
public String toString() {
String result="";
Node node=head;
while (node!=null){
result=node.getData()+","+result;
node=node.getNext();
}
return result;
}
}
在重写pushBack和pop方法的同时,还要重写toString,让输出是从后往前输出。使用头插法以后,这个链式栈的性能就好多了。同理,我们用C++来实现头插法的链式栈。其中父类LinkList的实现仍见链表一节。
- C++
#include "../LinkList/LinkedList.h"
template<class T>
class LinkStack:LinkList<T>
{
public:
/*
* 重写插入方法,使用头插法
*/