数据结构之路 - 栈

栈:栈(英语:stack)又称为堆栈或堆叠,属于线性数据结构,其满足后进先出原则,进行数据的存储。
特点,只在一端进行插入,删除操作,其表现为:从栈顶放入(入栈),栈顶取出(出栈)
后进先出 Last In First Out LIFO   类似羽毛球筒
栈图
经典应用:
1. 文本撤销
2. 程序调用系统栈
 执行方法时,调用子方法,入栈,执行完,出栈; 可找到上一次中断的位置)
3. 递归

一般操作系统中,入栈的操作使得栈顶的地址减小,出栈的操作使得栈顶的地址增大。

栈在程序的运行中有着举足轻重的作用。最重要的是栈保存了一个函数调用时所需要的维护信息,这常常称之为堆栈帧或者活动记录。堆栈帧一般包含如下几方面的信息:
1.函数的返回地址和参数
2.临时变量:包括函数的非静态局部变量以及编译器自动生成的其他临时变量。

栈的实现

根据栈的后进先出特性,以及查看Stack.java 源码时,发现只需要实现如下接口:

class Stack<E> extends Vector<E>
public class Vector<E>
    extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.SerializableVector 中,具体实现使用的是数组

isEmpty - 栈是否为空
push - 入栈
pop - 出栈
peek - 查看栈顶元素
search - 搜索某元素

数组

在实现时,多加了2个方法,一个用于数组的动态大小变化,一个是栈内容打印。

/**
 * @author stormxz
 *
 * @param <E>    泛型
 */
public class ArrStack<E> {
    //定义默认数据长度
    private int DATA_LENGTH = 10;

    //int 数据类型的数据
    private E[] data;

    //描述数据中的实际个数
    private int size;

    /**
     * 初始化无参构造函数,此时为默认长度
     */
    public ArrStack() {
        data = (E[]) new Object[DATA_LENGTH];
    }

    /**
     * @return  判断数组是否为空
     */
    public boolean isEmpty() {
        return size == 0;
    }

    /**
     * @param value  添加的值
     * 
     * 在末尾添加数据
     */
    public void push(E value) {
        if (size == data.length) {
            upDateArrayLength(2 * data.length);
        }

        data[size] = value;
        size++;
    }

    /**
     * @param length  新数组的长度
     * 
     * 更新数组容量 长度大小   复杂度O(n)
     */
    public void upDateArrayLength(int length) {
        E[] newData = (E[]) new Object[length];
        for (int i = 0; i < size; i++) {
            newData[i] = data[i];
        }
        data = newData;
    }

    /**
     *  删除栈顶元素,并返回
     */
    public E pop() {
        if (size <= 0) {
            throw new IllegalArgumentException("栈已空");
        }
        E value = data[size - 1];
        data[size - 1] = null;
        size--;

        if (size == data.length / 2 && data.length > 1) {
            upDateArrayLength(data.length / 2);
        }
        return value;
    }

    /**
     * @param index  查看栈顶元素
     * 
     * 查看栈顶元素,并返回数据  
     */
    public E peek() {
        if (size <= 0) {
            throw new IllegalArgumentException("栈已空");
        }
        return data[size - 1];
    }

    /**
     * @param value   查找的值
     * @return        对应值的索引
     * 
     * 查找值的位置 
     */
    public int search(E value) {
        for (int i = 0; i < size; i++) {
            if (data[i] == value) {
                return i;
            }
        }
        return -1;
    }

    /** (non-Javadoc)
     * @see java.lang.Object#toString()
     * 
     * 打印输出
     */
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("[");
        for (int i = 0; i < size; i++) {
            sb.append(data[i]);
            if (i != size -1) {
                sb.append(", ");
            } else {
                sb.append("]");
            }
        }
        System.out.println("Array size = " + size + "   
                                          length = " + data.length);
        return sb.toString();
    }
}

链表

使用链表的好处是,长度没有定死,与数组相比减少了数据copy的过程
链表实现栈功能

栈的小应用

括号匹配

括号匹配Leetcode - 20

将字符串逆序输出

    public void useStack() {
        Stack mStack = new Stack();
        String str = "hello, world";
        char[] c = str.toCharArray();
        for (char mStr : c) {
            mStack.push(mStr);
        }

        while(!mStack.isEmpty()) {
            System.out.print(mStack.pop());
        }
    }

运行结果:
dlrow ,olleh

总结

  1. 从栈的实现可以看出,在进行入栈和出栈的时间复杂度都为O(1),也就是说栈操作所耗的时间不依赖栈中数据项的个数,因此操作时间很短。
  2. 搜索操作时间复杂度为O(n)。
  3. 栈后进先出的特性,能够解决一些常见问题。

~看到新问题会继续补充

猜你喜欢

转载自blog.csdn.net/weixin_39158738/article/details/80770789
今日推荐