Stack:是一种后进先出LIFO的线性数据结构。只能从一端添加元素,也只能从同一端取出元素,这一端就是栈顶。
栈的应用:
- 无处不在的Undo操作(撤销)
-
程序调用的系统栈
-
括号的匹配LeetCode
栈的复杂度分析
interface Stack<E>
- void push(E e) O(1)
- E pop O(1)
- E peek O(1)
- int getSize() O(1)
- boolean isEmpty O(1)
栈的实现
package com.yan.study.algorithm.stack;
import com.yan.study.algorithm.array.Array;
/**
* 基于之前的动态数组实现自己的栈
*/
public class ArrayStack<E> implements Stack<E>{
private Array<E> array;
public ArrayStack(int capacity){
array = new Array<>(capacity);
}
public ArrayStack(){
array = new Array<>();
}
@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 int getSize() {
return array.getSize();
}
@Override
public boolean isEmpty() {
return array.isEmpty();
}
public int capacity(){
return array.getCapacity();
}
@Override
public String toString(){
StringBuilder res = new StringBuilder();
res.append("stack: [");
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();
}
}
Queue:是一种先进先出FIFO的线性数据结构。只能从一端(队尾)添加元素,从另一端(队首)取出元素。
队列的实现
public interface Queue<E> {
void enqueue(E e);
E dequeue();
E getFront();
int getSize();
boolean isEmpty();
}
数组队列的实现
package com.yan.study.algorithm.queue;
import com.yan.study.algorithm.array.Array;
//数组队列的实现
public class ArrayQueue<E> implements Queue<E> {
private Array<E> array;
public ArrayQueue(int capacity){
array = new Array<>(capacity);
}
public ArrayQueue(){
array = new Array<>();
}
@Override
public void enqueue(E e) {
array.addLast(e);
}
@Override
public E dequeue() {
return array.removeFirst();
}
@Override
public E getFront() {
return array.getFirst();
}
@Override
public int getSize() {
return array.getSize();
}
@Override
public boolean isEmpty() {
return array.isEmpty();
}
@Override
public String toString(){
StringBuilder res = new StringBuilder();
res.append("QUEUE : front[");
for (int i =0;i<array.getSize();i++){
res.append(array.get(i));
if(i != array.getSize()-1){
res.append(", ");
}
}
res.append("]tail");
return res.toString();
}
}
数组队列的问题?
取出队首的元素的时候,其它的值需要往前移动造成算法的复杂度变成O(n).
循环队列的实现
维护两个索引,front指向队首的元素,tail指向队尾的下一个存放的位置。front == tail 队列为空,(tail+1)% capacity == front 队列为满。因此
capacity中浪费一个空间。
package com.yan.study.algorithm.queue;
/**
* 循环队列的过程和之前实现的动态数组是一样的,关键在于如何维护front和tail两个索引的指向
* 在循环中需要注意取模的计算
* @param <E>
*/
public class LoopQueue<E> implements Queue<E>{
private E[] data;
private int front,tail;
private int size;
private int capacity;
//循环队列初始front,tail都是为0,front = tail 为空,tail指向下一个存放的位置
public LoopQueue(int capacity){
data = (E[])new Object[capacity+1];//因为front = tail+1%c为满,所以浪费了一个空间
front = 0;
tail = 0;
}
public LoopQueue(){
this(10);
}
@Override
public void enqueue(E e) {
//因为front = tail+1%c为满,余数的取值范围为0到除数之间(不包括除数)的整数如24÷8=3,其中8是除数
if((tail+1)%data.length == front){
resize(getCapacity() * 2);
}
data[tail] =e;
tail = (tail+1)%data.length;
size++;
}
private void resize(int newCapacity) {
E[] newData = (E[])new Object[newCapacity+1];
//和下面toStirng两种遍历方式
for (int i =0;i<size;i++){
newData[i] = data[(front+1)%data.length];
}
data = newData;
front = 0;
tail = size;
}
@Override
public E dequeue() {
if(isEmpty()){
throw new IllegalArgumentException("cannot dequeue from 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;
}
@Override
public E getFront() {
if(isEmpty()){
throw new IllegalArgumentException("can not getFront from empty queue");
}
return data[front];
}
@Override
public int getSize() {
return size;
}
@Override
public boolean isEmpty() {
return front == tail;
}
public int getCapacity(){
return data.length-1;
}
@Override
public String toString(){
StringBuilder res = new StringBuilder();
res.append("QUEUE : front[");
for (int i =front;i!=tail;i=(i+1)%data.length){
res.append(data[i]);
if((i+1) %data.length!=tail){
res.append(", ");
}
}
res.append("]tail");
return res.toString();
}
}
循环队列的复杂度
- void enqueue(E e); O(1)均摊
- E dequeue(); O(1)均摊
- E getFront(); O(1)
- int getSize(); O(1)
- boolean isEmpty(); O(1)