一、简介

众所周知,线性表是数据结构的基础,通常有两种实现方式:数组和链表。栈和队列是最常用的数据结构,它们基于线性表实现。

 

二、栈

定义:栈是限定仅在表尾进行插入和删除操作的线性表,即FILO。

栈被经常类比于弹夹,即先被压如弹夹的子弹最后被打出。根据线性表的实现方式得知,栈的实现方式有两种:数组实现和链表实现。

 

栈的数组实现:

package basic.data_structure.cha01;

/**
 * 栈:先进后出(FILO),只允许在栈顶操作元素
 * 栈的基本操作:
 *  初始化栈、弹栈、压栈、获取栈顶元素、判断是否为空
 *  
 *  
 * 用数组实现栈。
 * */
public class ArrayStack<T> {

    private T[] data;     //数据容器
    private int maxSize;  //栈容量
    private int top = -1; //栈顶指针
    
    
    public ArrayStack(){ this(10); }
    //初始化栈
    public ArrayStack(int capacity){
        if(capacity > 0){
            data = (T[])new Object[capacity];
            maxSize = capacity;
            top = -1;
        }else{
            throw new RuntimeException("栈的初始化大小不能小于或等于0");
        }
    }
    
    public boolean isEmpty(){
        return top == -1;
    }
    
    //压栈
    public boolean push(T elem){
        if(top == maxSize - 1){
            throw new RuntimeException("栈满");
        }
        
        data[++top] = elem;
        return true;
    }
    
    //获取栈顶元素(不移除)
    public T peek(){
        if(this.isEmpty()){
            throw new RuntimeException("空栈");
        }
        return data[top];
    }
    
    
    //弹栈
    public T pop(){
        if(this.isEmpty()){
            throw new RuntimeException("空栈");
        }
        return data[--top];
    }
}

很容易理解,都是实际上都是线性表的基本操作。

 

栈的链表实现:

package basic.data_structure.cha01;


/**
 * 栈:先进后出 FILO,只允许在栈顶操作元素
 * 栈的基本操作:
 *      初始化栈、压栈、弹栈、获取栈顶元素、当前栈大小
 * 
 * 栈的链表实现
 * */
public class LinkedStack<T> {

    private int currentSize;//当前栈大小(链表栈没有大小限制)
    private Node<T> top;    //头节点
    
    
    //初始化栈
    public LinkedStack(){
        top = null;  //头指针为空
    }
    
    public boolean isEmpty(){
        return top == null;
    }
    
    public int length(){
        return currentSize;
    }
    
    //压栈
    public boolean push(T elem){
        Node<T> node = new Node<T>(elem, top);
        top = node;
        currentSize ++;
        
        return true;
    }
    
    //获取栈顶元素
    public T peek(){
        if(this.isEmpty()){
            throw new RuntimeException("空栈");
        }
        
        return top.data;
    }
    
    //弹栈
    public T pop(){
        if(this.isEmpty()) {
            throw new RuntimeException("空栈");
        }
        Node<T> node = top;
        top = top.next;
        node.next = null;
        currentSize --;
        
        return node.data;
    }
    
    //节点(内部类)
    private static class Node<T>{
        T data;           //数据域
        Node<T> next;     //链域
        public Node(){}
        public Node(T data, Node<T> next){
            this.data = data;
            this.next = next;
        }
    }
    
}

 

 

总结:

  由于线性表的实现方式有“数组”和“链表”两种,所以 栈 的实现方式也分两种,这两种实现方式都实现的栈的主要功能点:压栈、弹栈、获取栈顶元素,但也有所区别。基于数组实现的栈在初始化时需要指定具体的大小,基于链表的实现没有大小限制。

  两种实现的本质区别在于:基于数组的实现用操作数组下标,基于链表的实现操作链表节点的指针。

 

  需要注意的是,在基于链表的实现中,弹栈时,要对引用做清理工作,否则会导致无用对象无法被GC回收。

posted on 2017-04-11 22:33  D.Zhang  阅读(299)  评论(0编辑  收藏  举报