Chp3栈和队列
栈 Stack
概念:
栈是一种线性结构;
相比数组,栈对应操作的是数组的子集;
只能从一端添加元素,也只能从一段取出元素;
这一段称作栈顶。
性质:
栈是一种先进后出的数据结构;Last In First Out;在计算机的世界里栈有着不可思议的作用。
栈的应用:
Undo操作(撤销)
栈的实现
Stack
构造方法:根据参数规定的容量创建一个新栈,栈的域包括表示最大容量的变量(即数组的大小)。
push()方法:将top(栈顶)的值增加一,使它指向原顶端数据项上面的一个位置,并在这个位置上存储一个数据项。
pop()方法: 从栈中移除数据项。返回index为top(栈顶)的数据项值,然后top减一。
peek()方法:返回栈顶(top)元素所指的数据项的值,不对栈做任何变动。
LeetCode例题
给定一个只包括
思路
1,import java.util.Stack。并声明一个栈
2,遍历这个字符串,每次用charAt()具体来看字符串中第i个字符是什么样子的,存成 char c
3,如果c==’(‘ || ‘[‘ ||’{‘ 满足这个条件,将c push进入栈中;否则 (如果当前栈顶没有字符的话,显然匹配失败,则直接return false。)用pop方法查看当前栈顶的字符topchar,如果c是’)’但是当前的topchar不是’(‘则匹配失败;同理,如果c是’]’但是当前的topchar不是’[‘则匹配失败;
4,在循环之外,如果栈里还有字符串则匹配失败。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| import java.util.Stack public class Solution{ public boolean isVaild(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(); } }
|
队列 Quene
特点:先进先出
创建循环队列–对长度取余数
属性:头front,尾tail。front == tail 队列为空;(front+1)%data.length == tail 队列满
几个重要方法
enqueue()方法: 从队尾入队。
1,判断队列是否已经满了(tail转了一圈之后,与front是否相等),若满了则进行扩容。
2,把元素加到队尾(下标为tail)。
3,tail向后移动一位(为了实现循环,因此需要对长度取余数),size数量增加。
1 2 3 4 5 6 7 8 9
| public void enqueue(E e){ if((tail+1)%data.length == front) resize(2*data.length); data[tail] = e; tail = (tail+1)%data.length; size++; }
|
**dequeue()方法:**从队首出队。
1,判断队列是否为空,若为空则抛出异常。
2,把要被删除的元素(下标为front)存入ret中,后删除这个元素(指向null)。
3,front向后移动一位(为了实现循环,因此需要对长度取余数),size数量减少
4,为了节约空间,有必要进行缩容。但是缩容的这个值不应该为0。
1 2 3 4 5 6 7 8 9 10 11 12
| public E dequeue(){ if(isEmpty()) throw new IllegalArgumentException("Cannot dequeue from an empty queue."); E ret = data[front]; data[front] = null; front = (front+1) % data.length; size--; if(size == getCapacity()/4 && getCapacity()/2 != 0 ) resize(getCapacity()/2); return ret; }
|
resize()方法:调整队列的容量。
1,新建数组newData
2,通过循环,把旧数组中元素都复制到新数组中。但是,在原来的data中有可能front不是0,可是我们要把它放在新的空间的0的位置,因此存在front个偏移,由于是循环队列i+front会越界,因此加上偏移后还有对长度取余数。
3,把引用变量指向新数组,并设置front为0,tail为size
1 2 3 4 5 6 7 8
| public void resize(int newCapacity){ E[] newData =(E[]) new Object[newCapacity+1]; for(int i = 0;i < size;i++) newData[i] = data[(i+front)%data.length]; data = newData; front = 0; tail = size; }
|
整体实现——代码实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| public class LoopQuene<E>{ private E[] data; private int front,tail; private int size; public LoopQuene(int capacity){ data = (E[]) new Object[capacity+1]; front = 0; tail = 0; size = 0; } public LoopQuene(){ this(10); } public int getCapacity(){ return data.length-1; } public boolean isEmpty(){ return front == tail; } public int getSize(){ return size; } public void enqueue(E e){ if((front+1)%data.length == tail) resize(2*data.length); data[tail] = e; tail = (tail+1)%data.length; size++; } public E dequeue(){ if(isEmpty()) throw new IllegalArgument(""); E ret = data[front]; front = (front+1)%data.length; data[front] = null; size--; if(getCapacity == size/4 && getCapacity) resize(getCapacity/2); return ret; } public void resize(int newCapacity){ E[] newData = (E[])new Object[newCapacity+1]; for(int i =0;i<size;i++) newData[i] = data[(i+front)%data.length]; data = newData; front = 0 ; tail = size; } public E getFront(){ if(isEmpty()) throw new IllegalArgumentException("Queue is empty."); return data[front]; } }
|