一、什么是栈
栈(stack
),是一种常见的数据结构;大部分的微处理器运用了栈的基本体系结构,当调用一个方法时,把它的返回地址和参数压入栈,当方法结束返回时,那些数据就出栈。这里涉及到的栈的特性,即先进后出
的特性。
相关词解读:
压栈(push)
:压栈即进栈,对于栈来说,元素只能从栈顶进栈。弹栈(pop)
:弹栈即出栈,对于栈来说,元素只能从栈顶弹栈。先进后出
:这是前面两者的总结,即对于栈来说,先入栈的元素会被压到栈尾,而每次弹栈的只能是栈顶的元素,所以就是先进后出。
二、用Java实现栈结构
2.1、基于数组
public class Stack {
private int size;//栈的大小
private int pointer;//栈顶的索引
private int[] theStack;//用数组构造栈结构
public Stack(int size) {
//初始化数组
this.size = size;
theStack = new int[size];
//初始化索引,-1表示空栈
pointer = -1;
}
//判断是否空栈
public boolean isEmpty() {
if (this.pointer == -1) {
System.out.println("空栈");
return true;
} else {
return false;
}
}
//判断是否满栈
public boolean isFull() {
if (this.pointer == this.size - 1) {
//满栈
return true;
} else {
return false;
}
}
//压栈
public void push(int value) {
if (!isFull()) {
//不是满栈
//索引+1并添加元素
theStack[++pointer] = value;
}
}
//弹栈
public int pop() {
if (!isEmpty()) {
//不是空栈
//弹出栈顶元素、索引-1
return theStack[pointer--];
}else{
System.out.println("空栈");
return 0;
}
}
//查看栈顶元素
public int peek(){
return theStack[pointer];
}
}
2.2、基于链表
public class LinkedListStack<T>{
//栈深度
private int stackDepth = 0;
//栈头数据
private Node first;
//链表节点
private class Node {
//指向下一节点
Node next;
//节点携带的数据
T value;
private Node(T value) {
this.value = value;
}
}
public boolean isEmpty() {
return stackDepth == 0;
}
public int depth() {
return stackDepth;
}
public int push(T value) {
Node node = new Node(value);
//两种情况,一是为空栈时,二是不为空栈,从链头插入节点
if (isEmpty()) {
first = node;
stackDepth++;
return 1;
} else {
Node oldNode = first;
first = node;
first.next = oldNode;
stackDepth++;
return 1;
}
}
public T pop() {
if (!isEmpty()) {
T value = first.value;
first = first.next;
stackDepth--;
return value;
} else {
return null;
}
}
public T peek() {
if (isEmpty()) {
return null;
} else {
return first.value;
}
}
}
三、栈结构相关操作的Big O分析
由于弹栈和压栈都只能在栈顶进行,不需要其他操作,所以对与栈结构来说,弹栈和压栈以及查看栈顶元素的时间复杂度都是常数,即O(1)。
四、Java的原始栈结构
讲完了栈结构的基本java实现,接下来看看java中的Stack< T >
类;
package java.util.Stack< T >:
/**
* The <code>Stack</code> class represents a last-in-first-out
* (LIFO) stack of objects. It extends class <tt>Vector</tt> with five
* operations that allow a vector to be treated as a stack. The usual
* <tt>push</tt> and <tt>pop</tt> operations are provided, as well as a
* method to <tt>peek</tt> at the top item on the stack, a method to test
* for whether the stack is <tt>empty</tt>, and a method to <tt>search</tt>
* the stack for an item and discover how far it is from the top.
* <p>
* When a stack is first created, it contains no items.
*
* <p>A more complete and consistent set of LIFO stack operations is
* provided by the {@link Deque} interface and its implementations, which
* should be used in preference to this class. For example:
* <pre> {@code
* Deque<Integer> stack = new ArrayDeque<Integer>();}</pre>
*
* @author Jonathan Payne
* @since JDK1.0
*/
public
class Stack<E> extends Vector<E> {
/**
* Creates an empty Stack.
*/
public Stack() {
}
/**
* Pushes an item onto the top of this stack. This has exactly
* the same effect as:
* <blockquote><pre>
* addElement(item)</pre></blockquote>
*
* @param item the item to be pushed onto this stack.
* @return the <code>item</code> argument.
* @see java.util.Vector#addElement
*/
public E push(E item) {
addElement(item);
return item;
}
/**
* Removes the object at the top of this stack and returns that
* object as the value of this function.
*
* @return The object at the top of this stack (the last item
* of the <tt>Vector</tt> object).
* @throws EmptyStackException if this stack is empty.
*/
public synchronized E pop() {
E obj;
int len = size();
obj = peek();
removeElementAt(len - 1);
return obj;
}
/**
* Looks at the object at the top of this stack without removing it
* from the stack.
*
* @return the object at the top of this stack (the last item
* of the <tt>Vector</tt> object).
* @throws EmptyStackException if this stack is empty.
*/
public synchronized E peek() {
int len = size();
if (len == 0)
throw new EmptyStackException();
return elementAt(len - 1);
}
/**
* Tests if this stack is empty.
*
* @return <code>true</code> if and only if this stack contains
* no items; <code>false</code> otherwise.
*/
public boolean empty() {
return size() == 0;
}
/**
* Returns the 1-based position where an object is on this stack.
* If the object <tt>o</tt> occurs as an item in this stack, this
* method returns the distance from the top of the stack of the
* occurrence nearest the top of the stack; the topmost item on the
* stack is considered to be at distance <tt>1</tt>. The <tt>equals</tt>
* method is used to compare <tt>o</tt> to the
* items in this stack.
*
* @param o the desired object.
* @return the 1-based position from the top of the stack where
* the object is located; the return value <code>-1</code>
* indicates that the object is not on the stack.
*/
public synchronized int search(Object o) {
int i = lastIndexOf(o);
if (i >= 0) {
return size() - i;
}
return -1;
}
/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = 1224463164541339165L;
}
这个Stack< T >
类和上文用java实现的基本栈结构原理一样,不过是将数组用泛型替换掉,得一让Stack< T >
类能够存储不同的对象和数据类型,其中的弹栈pop()
、压栈push()
、查看栈头peek()
方法的实现都是一样的;还有一点值得一提的是,该类继承了向量类Vector
,Vector
类是数组的扩展,它是可扩容的,这解决的数组的定长问题。