数据结构-栈和队列篇
一. 栈
栈也是一种线性结构,相比数组,栈对应的操作是数组的子集
只能从一端添加,也只能从一端去除元素,这一端称为栈顶
栈是一种后进先出的数据结构(Last In First Out)
栈的应用:
-
系统中常用的"撤销操作";
-
程序调用的系统栈(记录子程序调用时中断点的位置):在编程进行子过程的调用时(当fun A()进行到2号中断点时,程序会调用fun B,即A2进栈),当一个子过程进行完毕后会自动转入到上层调用中断的位置(当fun C结束后,会转到fun B的2号位置,即B2出栈),继续执行下去。
类似于程序的递归调用
程序调用的系统栈
递归调用是有代价的:函数调用+系统栈空间
栈的实现:
Stack<Element>
1. void push(Element) 入栈
2. Element pop() 出栈
3. Element peek() 查看栈顶元素
4. int getSize() 获取栈的元素个数
5. boolean isEmpty() 判断栈是否为空
时间复杂度都为O(1)
定义栈
public interface Stack<E> {
int getSize(); //获取栈的元素个数
void push(E e); //入栈
boolean isEmpty(); //判断栈是否为空
E pop(); //出栈
E peek(); //查看栈顶元素是什么
}
实现
public class ArrayStack<E> implements Stack<E> {
Array1<E> array;
public ArrayStack(int capacity) {
array = new Array1<>(capacity);
}
public ArrayStack(){
array = new Array1<>();
}
@Override
public int getSize() {
return array.getSize();
}
@Override
public void push(E e) {
array.addList(e);
}
@Override
public boolean isEmpty() {
return array.isEmpty();
}
@Override
public E pop() {
return array.removeLast();
}
@Override
public E peek() {
return array.getLast();
}
public int getCapacity(){
return array.getCapacity();
}
@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();
}
}
测试类
public class StackMain {
public static void main(String[] args) {
ArrayStack<Integer> stack = new ArrayStack<Integer>();
for (int i = 0; i < 5; i++) {
stack.push(i);
System.out.println(stack);
}
stack.pop();
System.out.println(stack);
}
}
二. 队列
队列也是一种线性结构,相比数组,队列对应的操作时数组的子集
只能从一端(队尾)添加元素,只能从另一端(队首)取出元素
队列是一种先进先出的数据结构(First In First Out)
队列的实现
Queue<E>
1. void enqueue(E)
2. E dequeue()
3. E getFront() 获取队首元素
4. int getSize()
5. boolean isEmpty()
时间复杂度: dequeue出队 O(n) ,其余都是O(1)
定义队列
public interface Queue<E> {
int getSize();
boolean isEmpty();
void enqueue(E e); //入队
E dequeue(); //出队
E getFront(); //获取队首元素
}
实现
public class ArrayQueue<E> implements Queue<E> {
private Array1<E> array;
public ArrayQueue(int capacity) {
array = new Array1<>(capacity);
}
public ArrayQueue() {
array = new Array1<>();
}
@Override
public int getSize() {
return array.getSize();
}
@Override
public boolean isEmpty() {
return array.isEmpty();
}
@Override
public void enqueue(E e) {
array.addList(e);
}
@Override
public E dequeue() {
return array.removeFirst();
}
@Override
public E getFront() {
return array.getFirst();
}
public int getCapacity() {
return array.getCapacity();
}
@Override
public String toString() {
StringBuilder res = new StringBuilder();
res.append("Queue:");
res.append("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();
}
测试类
public static void main(String[] args) {
ArrayQueue<Integer> queue = new ArrayQueue<>();
for(int i=0;i<10;i++){
queue.enqueue(i);
System.out.println(queue);
if(i%3==2){
queue.dequeue();
System.out.println(queue);
}
}
}
}
三. 循环队列
实现
public class LoopQueue<E> implements Queue<E> {
private E[] data;
private int front, tail;
private int size;
public LoopQueue(int capacity) {
data = (E[]) new Object[capacity + 1];
front = 0;
tail = 0;
size = 0;
}
public LoopQueue() {
this(10);
}
public int getCapacity() {
return data.length - 1;
}
/**
* 队列是否为空
*
* @return
*/
@Override
public boolean isEmpty() {
return front == tail;
}
@Override
public int getSize() {
return size;
}
/**
* 循环队列入队过程
*
* @param e
*/
@Override
public void enqueue(E e) {
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];
//遍历循环队列的方式一
for (int i = 0; i < size; i++) {
newData[i] = data[(i + front) % data.length];
}
data = newData;
front = 0;
tail = size;
}
/**
* 循环队列出队过程
*/
@Override
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;
System.out.println(front);
size--;
if (size == getCapacity() / 4 && getCapacity() / 2 != 0)
resize(getCapacity() / 2);
return ret;
}
@Override
public E getFront() {
if (isEmpty())
throw new IllegalArgumentException("Queue is empty");
return data[front];
}
@Override
public String toString() {
StringBuilder res = new StringBuilder();
res.append(String.format("Queue : size:%d,capzcity:%d\n", size, getCapacity()));
res.append("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();
}
}
测试类
public static void main(String[] args) {
LoopQueue<Integer> queue = new LoopQueue<>();
for (int i = 0; i < 10; i++){
queue.enqueue(i);
System.out.println(queue);
if(i%3==2){
queue.dequeue();
System.out.println(queue);
}
}
}