栈 介绍及简单实现

来源:互联网 发布:淘宝返现卡片 编辑:程序博客网 时间:2024/06/07 02:24
一、栈介绍
1.1 简单介绍
    栈(stack) 是一个有序线性表,只能在表的一端(称为栈顶(top))执行插入和删除操作。最后插入的元素最后一个被删除,所以,栈也称为后进先出(LIFO)或先进后出(FILO)线性表。
    入栈(push):表示在栈顶插入一个元素。
    出栈(pop):表示从栈顶删除一个元素。
    试图对一个空栈执行出栈操作称为下溢(underflow)
     对一个满栈进行入栈操作称为溢出(overflow)。
    通常情况下下溢和溢出均认为异常。
1.2 操作
    简单起见,我们使用int类型。
    void push(int data)  将data插入栈
    int pop() 删除并返回最后一个插入的元素。
    int top() 返回一个最后插入的元素。
    int size() 返回存储在栈中的元素的个数。
    boolean isEmpty() 判断栈中是否有元素
    boolean isStackFull() 判断栈中是否存满元素。
1.3 栈的常见应用
  • 符号匹配
  • 中辍表达式转为后辍表达式
  • 计算后辍表达式
  • 实现函数调用(包括递归)
  • 文本编辑器的撤销操作。
  • 浏览器后退按钮的实现。
  在后面的介绍中,会对栈的常见应用给出对应案例。

二、栈的实现
   2.1   抽象栈
    我们使用三种方式实现栈,一种是简单数组,一种是动态数组,最后是单向链表
2.2 简单数组实现栈
    
1
import java.util.Arrays;
2
3
/**
4
 * Created by Administrator on 2017/6/24 0024.
5
 */
6
public class SimpleDynamicArrayStack extends  Stack {
7
    private int top;
8
    private int capacity;
9
    private int[] array;
10
11
    public SimpleDynamicArrayStack(int capacity) {
12
        this.capacity = capacity;
13
        array = new int[capacity];
14
    }
15
16
    public void push(int data) {
17
        if(isStackFull()){
18
            expansion();
19
        }
20
        array[top] = data;
21
        top++;
22
    }
23
24
    public int pop() {
25
        if(isEmpty()){
26
            throw new IllegalMonitorStateException("该栈为空栈,无法探出元素");
27
        }
28
        top--;
29
        return array[top-1];
30
    }
31
32
    public int top() {
33
        if(isEmpty()){
34
            throw new IllegalMonitorStateException("该栈为空栈,没有元素");
35
        }
36
        top--;
37
        int temp = array[top-1];
38
        //如果栈中存储的不是基本数据类型,这里注意将array[top-1]置为null,否则可能出现内存泄漏
39
        return temp;
40
    }
41
42
    public int size() {
43
        return 0;
44
    }
45
46
    public boolean isEmpty() {
47
        return top == 0;
48
    }
49
50
    public boolean isStackFull() {
51
        return top == capacity;
52
    }
53
54
    /**
55
     * 数组扩容操作
56
     */
57
    private void expansion(){
58
        capacity = 2*capacity;
59
        array = Arrays.copyOf(array,capacity);
60
    }
61
}
62
    性能和局限性
    性能:假设n为栈中元素个数,在基于简单数组的栈的实现中,各种栈操作的算法复杂度如下:    
    
空间复杂度(用于n次push操作)O(n)size()的时间复杂度O(1)push()的时间复杂度O(1)isEmpty()的时间复杂度O(1)pop()的事件复杂度O(1)isStackFull()的时间复杂度O(1)
    局限性:栈的最大容量在初始化的时候指定不能改变。

2.2 基于动态数组的实现
    我们采取的方式是当栈满了,就能让栈的容量扩充为原来的两倍
    性能:假设n为栈中元素个数。算法复杂度如下  
  
空间复杂度(用于n次push操作)O(n)size()的时间复杂度O(1)push()的时间复杂度O(1)(平均)isEmpty()的时间复杂度O(1)pop()的事件复杂度O(1)isStackFull()的时间复杂度O(1)

2.2 使用链表实现
1
/**
2
链表节点
3
*/
4
public class Node {
5
    private int data;
6
    private Node next;
7
8
    public Node(int data) {
9
        this.data = data;
10
11
    }
12
13
    public int getData() {
14
        return data;
15
    }
16
17
    public void setData(int data) {
18
        this.data = data;
19
    }
20
21
    public Node getNext() {
22
        return next;
23
    }
24
25
    public void setNext(Node next) {
26
        this.next = next;
27
    }
28
}
29
30
31
32
import cn.lx.node.Node;
33
34
/**
35
 * Created by Administrator on 2017/6/24 0024.
36
 */
37
public class SimpleNodeStack extends Stack{
38
    private Node headNode;
39
    private int size;
40
    @Override
41
    public void push(int data) {
42
        Node node = new Node(data);
43
        if(isEmpty()){
44
            headNode = node;
45
            return;
46
        }
47
        size++;
48
        node.setNext(headNode);
49
        headNode = node;
50
    }
51
52
    @Override
53
    public int pop() {
54
        if(isEmpty()){
55
            throw new IllegalMonitorStateException("该栈为空栈,无法探出元素");
56
        }
57
        int temp = headNode.getData();
58
        headNode = headNode.getNext();
59
        size--;
60
        return temp;
61
    }
62
63
    @Override
64
    public int top() {
65
        if(isEmpty()){
66
            throw new IllegalMonitorStateException("该栈为空栈,无法探出元素");
67
        }
68
69
        int temp = headNode.getData();
70
        return temp;
71
    }
72
73
    @Override
74
    public int size() {
75
        return 0;
76
    }
77
78
    @Override
79
    public boolean isEmpty() {
80
        return    headNode == null;
81
    }
82
83
    @Override
84
    public boolean isStackFull() {
85
        return false;
86
    }
87
}
88
    性能:假设栈中元素个数为n,算法复杂度如下:
空间复杂度(用于n次push操作)O(n)size()的时间复杂度O(1)push()的时间复杂度O(1)(平均)isEmpty()的时间复杂a度O(1)pop()的事件复杂度O(1)isStackFull()的时间复杂度O(1)
2.4 栈的实现方式比较
基于数组与基于链表的比较:
       基于数组实现:
    各个操作都是常数时间开销
    每隔一端时间倍增操作的开销较大
        基于链表实现
    栈规模大的增加和减少都很简洁
    每个操作都是常数时间开销
    每个操作都都要使用额外的空间和时间来处理指针。