浅谈栈(Stack)数据结构

本文介绍了栈(Stack)的基本概念、特征,如后进先出(LIFO)的性质,以及栈在撤销操作、程序调用和括号匹配等场景中的应用。还探讨了如何通过Java的`java.util.Stack`以及自定义`ArrayList`和`LinkedList`实现栈数据结构。

一、概述:

栈(stack):栈是一种线性的结构,这种数据结构仅限在线程表的一段进行插入和删除操作。其中线性表插入的和删除的一段称为栈顶(top),不循序插入和删除的一段称为栈底(bottom)。所以栈数据结构是遵循“后入先出”,也就是“LIFO”。

二、栈的特征

(1)栈也是一种线性的机构。

(2)相比较数组,占对应的操作是数组的子集。

(3)只能从一端添加元素,也只能从一端取出元素,这一端称为栈顶。

(4)栈是一种后进先出的数据结构。称为:Liast In First Out(LIFO)

三、栈的应用:

(1)无处不在的Undo操作(撤销)。

(2)程序调用的系统栈。

(3)括号匹配-编译器

通过java.util.Stack来实现一个括号匹配器:

public class Solution {

    public boolean isValid(String s) {
        Stack<Character> stack = new Stack<>();
        for(int i=0; i< s.length();i++){
            char c = s.charAt(i);
            if(c == '(' || c == '[' || c == '{')
                stack.push(c);
            else{
                if(stack.isEmpty())
                    return false;

                char topChar = stack.pop();
                if(c == ')' && topChar != '(')
                    return false;
                if(c == ']' && topChar != '[')
                    return false;
                if(c == '}' && topChar != '{')
                    return false;
            }
        }
        return stack.isEmpty();
    }

    public static void main(String[] args) {
        System.out.println((new Solution()).isValid("()[]{}"));
        System.out.println((new Solution()).isValid("()[]{]}"));
    }

}

java.util.Stack这个栈数据结构得底层是通过java.util.Vector实现的,Stack继承了Vector,而Vector和ArrayList一样实现了List接口,Vector和ArrayList是实现原理上是非常相似的,它们都是通过数组实现的,不过与ArrayList不同的是,Vector支持线程的同步,即某一个时刻只有一个线程能够操作Vector,避免了多线程同时引起的不一致性,它的同步是通过synchronized实现的,同步需要很高的花费,访问它要比访问ArrayList要慢;Vector属于线程安全级别的,但是大多数情况下不使用Vector,因为线程安全需要更大的系统开销。

四、栈的实现:

(一) 通过自定义ArrayList封装一个栈数据结构:

1、定义Stack接口:

public interface Stack<E> {

    //查看栈元素的数量
    int getSize();

    //查看栈元素是否为空;
    boolean isEmpty();

    //压栈
    void push(E e);

    //弹出
    E pop();

    //查看栈顶元素
    E peek();
}

2、创建自定义ArrayList

public class CustomArray<E> {

    //private int[] data;
    private E[] data;

    private int size;

    //构造函数,出入数组的容量capocity构造CustomArray
    public CustomArray(int capacity){
        //data = new int[capacity];
        /**
         * java语言中不支持泛型语法,因为泛型是java在1.5之后引入的,这是一个历史
         * 遗留问题。所以我们在声明泛型类数组的时候,要有用一个折中的方案现用Object
         * 声明一个数组,再强转为泛型类型(E[])
         * */
        data = (E[])new Object[capacity];
        size = 0;
    }

    public CustomArray(){
        this(10);
    }

    // 获取数组中的元素个数
    public int getSize(){
        return size;
    }

    // 获取数组的容量
    public int getCapacity(){
        return data.length;
    }
    //返回数组是否为空
    public boolean isEmpty(){
        return size == 0;
    }

    // 想所有的元素后添加一个新的元素
    public void addLast(E e){
        if(size == data.length){
            //throw new IllegalArgumentException("AddLast failed.CustomArray is full.");
            resize(2 * data.length);
        }
        data[size] = e;
        size ++;
    }
    public void addLastPuls(E e){
        add(size,e);
    }

    public void addFirst(E e){
        add(0,e);
    }

    // 在第index个位置插入一个新的元素e
    public void add(int index,E e){
        if(size == data.length)
            //throw new IllegalArgumentException("Add failed.Array is full.");
            resize(2 * data.length);

        if(index < 0 || index > size){
            throw new IllegalArgumentException("Add failed.Require index >= 0 and index <= size");
        }
        for(int i = size - 1;i >= index; i--){
            data[i+1] = data[i];
        }
        data[index] = e;
        size ++;
    }

    // 获取index索引位置的元素
    public E get(int index){
        if(index<0 || index>=size)
            throw new IllegalArgumentException("Get failed.Index is illegal.");
        return data[index];
    }
    // 修改index索引位置的元素为e
    public void set(int index, E e){
        if(index<0 || index>=size)
            throw new IllegalArgumentException("Get failed.Index is illegal.");
        data[index] = e;
    }
    // 查看数组中是否有元素e
    public boolean contains(E e) {
        for (int i = 0; i < size; i++){
            if (data[i].equals(e))
                return true;
        }
         return false;
    }
    // 查询数组中元素e所在的索引,如果不存在元素e,则返回-1
    public int find(E e){
        for (int i = 0; i < size; i++){
            if (data[i].equals(e))
                return i;
        }
        return -1;
    }

    public E remove(int index){
        if(index<0 || index>=size)
            throw new IllegalArgumentException("Remove failed.Index is illegal.");

        E ret = data[index];
        for(int i=index+1; i < size;i++)
            data[i - 1] = data[i];
        size--;
        data[size] = null;//loitering object

        if(size == data.length/4 && data.length / 2 != 0)
            resize(data.length / 2);
        return ret;
    }
    // 从数组中删除第一个元素,返回参数的元素
    public E removeFirst(){
        return remove(0);
    }
    // 从数组中删除最后一个袁术,返回删除的元素
    public E removeLast(){
        return remove(size - 1);
    }

    public void removeElement(E e){
        int index = find(e);
        if(index != -1){
            remove(index);
        }
    }

    @Override
    public String toString(){
        StringBuilder res = new StringBuilder();
        res.append(String.format("Array:size = %d , capadity = %d\n",size,data.length));
        res.append('[');
        for(int i = 0;i < size; i++){
            res.append(data[i]);
            if(i != size - 1){
                res.append(", ");
            }
        }
        res.append(']');
        return res.toString();
    }

    private void resize(int newCapacity){
        E[] newData = (E[])new Object[newCapacity];
        for(int i=0;i<size;i++){
            newData[i] = data[i];
        }
        data = newData;
    }

    public E getLast(){
        return get(size-1);
    }
    public E getFirst(){
        return get(0);
    }
}

3、自定义Stack实现类:

public class ArrayStack<E> implements Stack<E> {

    CustomArray<E> array;

    public ArrayStack(int capacity){
        array = new CustomArray<>(capacity);
    }

    public ArrayStack(){
        array = new CustomArray<>();
    }

    @Override
    public int getSize(){
        return array.getSize();
    }

    @Override
    public boolean isEmpty(){
        return array.isEmpty();
    }

    public int getCapacity(){
        return array.getCapacity();
    }

    @Override
    public void push(E e){
        array.addLast(e);
    }

    @Override
    public E pop(){
        return array.removeLast();
    }

    @Override
    public E peek(){
        return array.getLast();
    }

    @Override
    public String toString(){
        StringBuilder res = new StringBuilder();
        res.append("Stack:");
        res.append('[');
        for(int i = 0; i<array.getSize(); i++){
            res.append(array.get(i));
            if(i != array.getSize() - 1){
                res.append(", ");
            }
        }
        res.append("] top");
        return res.toString();
    }
}

4、自定义测试类

public class StackTest {

    public static void main(String [] args){
        ArrayStack<Integer> stack = new ArrayStack<>();

        for(int i=0; i<5; i++){
            stack.push(i);
            System.out.println(stack);
        }
        stack.pop();
        System.out.println(stack);
    }

}

(二) 通过自定义LinkedList封装一个栈数据结构:

1、定义Stack接口:

public interface Stack<E> {

    //查看栈元素的数量
    int getSize();

    //查看栈元素是否为空;
    boolean isEmpty();

    //压栈
    void push(E e);

    //弹出
    E pop();

    //查看栈顶元素
    E peek();
}

2、实现一个自定义的LinkedList类:

public class CustomLinkedList<E> {

    /**
     *  将节点的设置成私有的内部类,也就是只有在链表这个数据结构内
     *  可以被访问到。在链表这个结构外用户是无法访问到这个节点类(Node.class)的。
     *  针对外部的用户屏蔽底层的实现细节;
     * */
    private class Node{
        public E e;
        public Node next;

        public Node(E e, Node next){
            this.e = e;
            this.next = next;
        }

        public Node(E e){
            this(e,null);
        }
        public Node(){
            this(null,null);
        }

        @Override
        public String toString(){
            return e.toString();
        }
    }

    //private Node head;
    private Node dummyHead;
    int size;

    public CustomLinkedList(){

        //head = null;
        //设置唯一的虚拟头节点
        dummyHead = new Node(null,null);
        size = 0;
    }

    // 获取链表中的元素个数;
    public int getSize(){
        return size;
    }

    // 返回链表是否为空
    public boolean isEmpty(){
        return size == 0;
    }

    // 在链表头添加新的元素e
    public void addFirst(E e){
        /*
        Node node = new Node(e);
        node.next = head;
        head = node;
        */
        //head = new Node(e,head);
        add(0,e);//设置虚拟节点版本
        //size ++;
    }

    /**
     *  在链表的index(0-based)位置添加新的元素e
     *  在链表中不是一个常用操作
     * */
    public void add(int index,E e){
        if(index < 0 || index > size)
            throw new IllegalArgumentException("Add failed. Illegal index.");
        /*
        if(index == 0)
            addFirst(e);
        else{
            Node prev = head;
            for(int i = 0; i < index -1; i++)
                prev = prev.next;

            // Node node = new Node(e);
            // node.next = prev.next;
            // prev.next = node;

            prev.next = new Node(e,prev.next);
            size ++;
        }
        */
        //设置虚拟节点头
        Node prev = dummyHead;
        for(int i = 0; i < index; i++)
            prev = prev.next;

        prev.next = new Node(e,prev.next);
        size ++;
    }

    // 在链表末尾添加新的元素e
    public void addList(E e){
        add(size,e);
    }

    //获得链表的第index(0-based)个位置的元素
    //在链表中不是一个常用的操作
    public E get(int index){
        if(index < 0 || index >= size){
            throw new IllegalArgumentException("Get Failed.Illegal index.");
        }
        Node cur = dummyHead.next;
        for(int i=0; i<index;i++)
            cur = cur.next;
        return cur.e;
    }

    //获取链表的第一个元素
    public E getFirst(){
        return get(0);
    }

    // 获得链表的最后一个元素
    public E getLast(){
        return get(size-1);
    }

    //修改链表的第index(0-based)哥位置的元素为e
    //在链表中不是一个常用的操作
    public void set(int index,E e){
        if(index < 0 || index >= size){
            throw new IllegalArgumentException("Update Failed.Illegal index.");
        }
        Node cur = dummyHead.next;
        for(int i=0; i<index; i++)
            cur = cur.next;
        cur.e = e;
    }
    //查找链表中是否有元素e
    public boolean contains(E e){
        Node cur = dummyHead.next;
        while(cur != null){
            if(cur.e.equals(e)){
                return true;
            }
            cur = cur.next;
        }
        return false;
    }

    @Override
    public String toString(){
        StringBuilder res = new StringBuilder();
        /*
        Node cur = dummyHead.next;
        while(cur != null){
            res.append(cur + "->");
            cur = cur.next;
        }*/
        for(Node cur =dummyHead.next; cur != null; cur =cur.next){
            res.append(cur + "->");
        }
        res.append("NULL");
        return res.toString();
    }

    //从链表中删除index(0-based)位置的元素,返回参数的元素
    //在链表中不是一个常用的操作
    public E remove(int index){
        if(index<0 || index >= size)
            throw new IllegalArgumentException("Remove failed.Index is illegal");

        Node prev = dummyHead;
        for(int i=0;i<index;i++)
            prev = prev.next;

        Node retNode = prev.next;
        prev.next = retNode.next;
        size --;
        return retNode.e;
    }

    // 从链表中删除第一个元素,返回删除的元素
    public E removeFirst(){
        return remove(0);
    }

    // 从链表中删除最后一个元素,返回删除的元素
    public E removeLast(){
        return remove(size-1);
    }

}

3、自定义Stack实现类:

public class LinkedListStack<E> implements Stack<E> {


    private CustomLinkedList<E> list;

    public LinkedListStack(){
        list = new CustomLinkedList<>();
    }


    @Override
    public int getSize(){
        return list.getSize();
    }

    @Override
    public boolean isEmpty(){
        return list.isEmpty();
    }

    @Override
    public void push(E e){
        list.addFirst(e);
    }

    @Override
    public E pop(){
        return list.removeFirst();
    }

    @Override
    public E peek(){
        return list.getFirst();
    }

    @Override
    public String toString(){
        StringBuilder res = new StringBuilder();
        res.append("Stack:top");
        res.append(list);
        return res.toString();
    }
}

4、自定义测试类:

public class StackTest {

    public static void main(String [] args){
        LinkedListStack<Integer> stack = new LinkedListStack<>();

        for(int i=0; i<5; i++){
            stack.push(i);
            System.out.println(stack);
        }
        stack.pop();
        System.out.println(stack);
    }

}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值