一 栈和队列
1 栈(Stack)
先入后出
Java中的栈(Stack):
import java.util.Stack;
Stack<Character> stack = new Stack<>();
方法 | 说明 |
---|---|
E push(E e) | 压栈 |
E pop() | 出栈 |
E peek() | 查看栈顶元素 |
boolean empty() | 判断栈是否为空 |
1)顺序栈
数组实现,采用尾插尾删的方式
2) 链式栈
单链表实现,头尾皆可
尾插入栈:O(n) 出栈尾出:O(n)
头插入栈:O(1) 出栈头出: O(1)
使用头插入栈,时间复杂度较低。
数组实现栈:
public class MyStack<T> {
public T[] elem;
public int top;//下标
public MyStack() {
this.elem = (T[]) new Object[10];
this.top = 0;
}
private boolean isFull() {
return this.top == this.elem.length;
}
public void push(T val) {
if(isFull()) {
return;
}
this.elem[this.top] = val;
this.top++;
}
private boolean isEmpty() {
return this.top == 0;
}
//出栈
public T pop() {
if(isEmpty()) {
return null;
}
T tmp = this.elem[top-1];//保存你出栈的数据
this.top--;//真正的出栈
return tmp;
}
//得到栈顶元素,但是不出栈 peek
public T getTop() {
if(isEmpty()) {
return null;
}
return this.elem[top-1];
}
}
2 队列(Queue)
先进先出
Java中的队列Queue:
import java.util.Queue;
Queue<Integer> queue = new LinkedList<>();
抛出异常 | 返回特征值 | |
---|---|---|
入队列 | add(e) | offer() |
出队列 | remove() | poll() |
队首元素 | element() | peek() |
队列可以采用数组和链表实现,使用链表的结构更优一些。
如果采用数组的结构,出队列再数组头上出数据,效率会比较低。
1) 链式队列
入队头插O(1) 出队 队尾O(n)
入队尾插:O(n) 出队 队头O(1)
定义一个指向队尾的引用,则能达到入队:O(1) 出队 O(1)
2) 顺序队列
如果采用数组实现队列可以用循环队列,即通过牺牲一定的空间,来达到时间复杂度的降低。
单链表实现队列:
/**
* 单链表实现队列,带索引
*/
public class MyListQueue {
static class Node {
public int data;
public Node next;
public Node(int data) {
this.data = data;
}
}
public Node front;
public Node rear;
public int usedSize;
public boolean isEmpty() {
return this.usedSize == 0;
}
//入队
public void offer(int data) {
Node node = new Node(data);
if(isEmpty()) {
this.front = node;
this.rear = front;
}else {
this.rear.next = node;
this.rear = node;
}
this.usedSize++;
}
public int poll() {
if(isEmpty()) {
throw new UnsupportedOperationException("队列为空");
}
int val = this.front.data;
this.front = this.front.next;
this.usedSize--;
return val;
}
public int peek() {
if(isEmpty()) {
throw new UnsupportedOperationException("队列为空");
}
return this.front.data;
}
}
循环数组实现队列:
/**
* 循环队列
*/
public class MyCircularQueue {
public int[] elem;
public int front;
public int rear;
public int usedSize;
/** Initialize your data structure here.
* Set the size of the queue to be k. */
public MyCircularQueue(int k) {
this.elem = new int[k];
this.front = 0;
this.rear = 0;
this.usedSize = 0;
}
/** Insert an element into the circular queue. Return true if the operation is successful. */
public boolean enQueue(int value) {
if(isFull()) {
return false;
}
this.elem[this.rear] = value;
this.rear = (this.rear+1)%this.elem.length;//防止越界
this.usedSize++;
return true;
}
/** Delete an element from the circular queue. Return true if the operation is successful. */
public boolean deQueue() {
if(isEmpty()) {
return false;
}
this.front = (this.front+1)%this.elem.length;
this.usedSize--;
return true;
}
/** Get the front item from the queue. */
public int Front() {
if(isEmpty()) {
return -1;
}
return this.elem[this.front];
}
/** Get the last item from the queue. */
public int Rear() {
if(isEmpty()) {
return -1;
}
int index = this.rear == 0 ?
this.elem.length-1 : this.rear-1;
return this.elem[index];
}
/** Checks whether the circular queue is empty or not. */
public boolean isEmpty() {
return this.front == this.rear;
}
/** Checks whether the circular queue is full or not. */
public boolean isFull() {
return (this.rear+1)%this.elem.length == this.front;
}
}