【数据结构与算法】1.1 栈

栈:是一个线性表,特殊的链表或者数组,遵循先进后出原则(FILO).

应用场景:浏览器的“前进”“后退”导航功能

栈和数组/链表的区别:数组和链表暴露很多接口,实现上更灵活;栈限制了操作的可能性,在某些场景下,是更适合的数据结构。(栈的基本方法:push, pop, size(), isEmpty())

栈的分类:

1. 基于数组的栈:以数组为底层数据结构,通常以数组头为栈底,数组头到尾为栈顶的生长方向

2. 基于单链表的栈:以链表为底层的数据结构,以链表头为栈顶,便于节点的插入与删除,压栈产生的新节点将一只出现在链表的头部

区别:扩容,链表天然支持冬天扩容,但也容易出现栈溢出。

//接口类:
public interface MyStack<Item>{
    MyStack<Item> push(Item item);    //入栈Item为泛型
    Item pop();                        //出栈
    int size();
    boolean isEmpty();
}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//实现一个栈:
public ArrayStack<Item> implements MyStack<Item>{
    private Item[] itemArray = (<Item>) new Object[1];    //初始化栈的容量 
    private int n=0;                                      //栈内元素个数
    
    //构造方法
    public ArrayStack(int cap){
    this.itemArray= (Item[]) new Object[cap];
    }

    public MyStack<Item> push(Item item){
        judgeSize();        //先判断是否需要扩容
        itemArray[n++] = item;    //在数组结尾处压入一个数据,并使n+1

        return null;
    }
    public Item pop(){
        if(isEmpty()){
            return null;
        }
        Item item = itemArray[--n];   //先有push操作,再有pop,因为push时n已经是+1状态了,因此需要先-1才能读取到最新压入栈的item
        itemArray[n] = null;                //且同时将pop出去的数据设为null,释放空间
        return item;
    }
    
    public int size(){
        return this.n;
    }
    
    public boolean isEmpty(){
        return n==0;
    }

    //判断栈是否需要扩容:当站内元素个数大于等于栈的容量,则进行扩容
    private void judgeSize()
    {
        if(itemArray.length <= n){
            resize(2* itemArray.length);
        }else if( n>0 && n<=itemArray.length/2){
        //扩容的优化:缩容,当栈内元素个数少于栈容积的1/2时,进行缩容
            resize(itemArray.length/2);
        }
    }

    //栈扩容
    private void resize(int size){
        //临时数组
        Item[] temp=(Item[]) new Object[size];
        for(int i=0;i<n;i++){
        temp[i]=itemArray[i];
        }
        itemArray=temp;
    }
}

Q1:

给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。

例如:

输入字符串:{}[]()  -->true

                      {[]()}  -->true

                      [()]{}  -->true

                      {(})[]  --> false

                      [[{{]}  --> false

A: 思考过程:括号依次匹配

public class BracketStatck{

    public static boolean isOk(String s){        //s表示待匹配的字符串
        MyStack<Character> brackets= new ArrayStack<Character>(20);    //利用之前实践过的栈类
        
        char[] c= s.toCharArray();
        Character top;
        for(char x:c){
            swtich(x){
                //如果是左括号,则压栈存储
                case '{':
                case '(':
                case '[':
                    brackets.push(x);    //压栈
                    break;
                //如果是右括号,则需进行匹配
                //如果括号匹配成功,则继续匹配,且需要将已匹配的括号弹出,因此用栈的pop;若匹配不成功,后面的字符也无须匹配了,直接返回false
                case '}':
                    top = brackets.pop();  //brackets可能是空的
                    if(top == null) return false;                    
                    if(top =='{'){ break;}           // 基础类型数据没有equals方法,只能使用==
                    else return false;
                case ']':
                    top = brackets.pop();
                    if(top == null) return false;                    
                    if(top =='['){ break;}
                    else return false;
                case ')':
                    top = brackets.pop();
                    if(top == null) return false;                    
                    if(top =='('){ break;}
                    else return false;
                default:
                    break;
            }            
        }
        return brackets.isEmpty();
    }

    //主方法进行测试
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        while(scanner.hasNext()){
            String s = scanner.next();
            System.out.println("s的匹配结果:"+isOk(s));
        }
    }

}

时间复杂度:

栈的push和pop的实践复杂度都是 O(1)

字符串s的遍历比较时间复杂度是O(n)

整个算法的时间复杂度是O(n)

应用场景:

1. 代码函数中的调用,代码运行过程中,函数的运行机制,即是栈

2. 数学表达式求值:3+11*2+8-15/5,用栈来实现这个算数表达式

        需要用到2个栈,一个用来存储数字,一个用来存储运算符;

        a)当前是数字,直接入栈到数字栈中;

        b)当前是符号,就把符号栈的栈顶数据pop出来进行比较,如果当前符号的优先级高于栈顶符号,则入栈;如果当前符号的优先级低于或者小于栈顶符号,则pop出栈顶符号进行计算(从数字栈中取栈顶的2个数字,并将计算完的结果压栈到数字栈中)

3. 浏览器前进后退的实现机制:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值