类似的。程序可以采用单链表来保存栈中的所有元素,这种链式的栈也被称为链栈。对于链栈而言,栈顶的元素不断改变,程序只要用一个top引用来记录当前的栈顶元素即可。top引用变量永远引用栈顶元素,在使用一个size变量记录当前栈中包含多少个元素即可。下面是链栈示意图:
1、进栈
对于链栈的进栈操作,程序需要做如下两件事情:
(1)让top引用指向新添加的元素,新元素的next引用指向原来的栈顶元素。
(2)让记录栈内元素的个数size+1.
下面是进栈示意图:
2、出栈
对于链栈的出栈操作,程序需要将栈顶的元素弹出栈,需要做两件事情:
(1)让top引用指向原栈顶元素的下一个元素并释放原栈顶元素。
(2)让记录栈内元素的个数size-1.。
下面是出栈的示意图:
下面是代码实现:
public class LinkStack<T> {
private class Node{
private Node next;
private T data;
@SuppressWarnings("unused")
public Node(){
}
public Node(T element){
this.data = element;
this.next = null;
}
public Node(T element, Node next){
this.data = element;
this.next = next;
}
}
//链栈的长度
private int size;
//永远指向栈顶的引用
private Node top;
public LinkStack(){
top = null;
size = 0;
}
public LinkStack(T element){
top = new Node(element);
size ++;
}
public int length(){
return size;
}
public boolean isEmpty(){
return size == 0;
}
//入栈(push)
public void push(T element){
top = new Node(element, top);
size ++;
}
//出栈(pop)并返回栈顶元素
public T pop(){
Node oldTop = top;
top = top.next;
oldTop.next = null;
size --;
return oldTop.data;
}
//peek
public T peek(){
return top.data;
}
//清空链栈‘
public void clear(){
top = null;
size = 0;
}
//toString方法
public String toString(){
if(isEmpty()){
return "[]";
}
else{
StringBuffer sb = new StringBuffer("[");
for(Node current = top; current != null; current = current.next){
sb.append(current.data.toString() + ",");
}
return sb.toString().substring(0, sb.length() - 1) + "]";
}
}
}
测试类如下:
import com.yc.list.LinkStack;
public class LinkStackTest {
public static void main(String[] args) {
LinkStack<Student> stack = new LinkStack<Student>();
stack.push(new Student("wb", "湖工", 22));
stack.push(new Student("lp", "湖工", 22));
stack.push(new Student("ls", "湖工", 22));
System.out.println( "从栈顶向栈底依次输出链栈: " + stack);
System.out.println();
Student s1 = stack.peek();
System.out.println( "peek的数据元素为: " + s1);
System.out.println( "从栈顶向栈底依次输出链栈: " + stack);
System.out.println();
Student s2 = stack.pop();
System.out.println( "pop的数据元素为: " + s2);
System.out.println( "从栈顶向栈底依次输出链栈: " + stack);
System.out.println();
System.out.println( stack.isEmpty());
stack.clear();
System.out.println( stack.isEmpty());
}
}
测试结果为:
运行上面的程序,LinkStack通常可以正常工作。经过上面的介绍可以看出,为了实现栈这种数据结构,程序有两种实现选择:顺序栈和链栈。
由于栈不需要实现随机存、取的功能,他只需要从栈顶插入、删除元素,因此顺序结构所提供的高效存、取就没有太大的意义,即采用链式结构的实现,
程序同样可以高效的出栈、入栈。对于链栈而言,栈内包含几个元素,底层链式结构就只需保存几个节点,每个节点需要额外添加一个next引用,
这会引起部分空间的浪费。但对于顺序栈来说,程序开始就要在底层开辟一块连续的内存(数组),这种空间浪费其实更大。从空间利用率来看,链栈的
空间利用率要比顺序栈的空间利用率高一些。
Java集合中的栈:
栈也是一种常用的数据结构,因此Java集合框架也提供了栈来工开发者使用。对于Java集合而言,它并未专门提供一个Stack接口,再为
该接口提供了顺序栈、链栈两种实现。
但JAVA集合实际上提供了一下两种栈供开发者使用:
(1)java.util.Stack:它是一个最普通的顺序栈,底层基于数组实现。这个Stack类是线程安全的,在多线程环境下也可以方心使用。
(2)java.util.LinkedList:首先LinkedList是一个双向链表;除此之外,LinkedList还可以作为栈来使用,查看该类的API将会发现,它同样提供了
push(),pop(),peek()这种栈的标志性方法。这表明linkedList是可以当成栈来使用的。但它是线程不安全的,如果需要在多线程的环境下使用它的话,
则应该使用Collections类的工具方法将其“改造”成线程安全的。