在 数组 中,可以通过索引访问 随机 元素。 但是,某些情况下,可能需要限制处理的顺序。
栈:是一个 后入先出(LIFO)数据结构。通常,插入操作在栈中被称作入栈 push ,总是在堆栈的末尾添加一个新元素。删除操作,退栈 pop ,将始终删除最后一个元素。
队列:是一个 先入先出(FIFO) 的数据结构。插入(insert)操作也称作入队(enqueue),新元素始终被添加在队列的末尾。 删除(delete)操作也被称为出队(dequeue),只能移除第一个元素。
栈是一种线性结构,相比数组,栈对应的操作是数组的子集,只能从一端添加元素,也只能从一端取出元素,这一端称为栈顶;
栈是一种后进先出的数据结构 LAST IN FIRST OUT(LIFO)。
在计算机的世界里,栈拥有着不可思议的作用,栈的应用:
只允许在栈顶进行操作
ArrayStack
队列是一种线性结构,相比数组,队列对应的操作是数组的子集,只能从一端(队尾)添加元素,只能从另一端(队首)取出元素;
队列是一种先进先出的数据结构,First In First Out(FIFO)。
数组队列:
固定容量循环队列:
动态容量循环队列:
ArrayQueue 数组队列
LoopQueue 固定容量循环队列
LoopQueue 动态容量循环队列
resize() 动态扩缩容
数组栈
public interface Stack<E> {
/** 入栈 */
void push(E e);
/** 出栈 */
E pop();
/** 查看栈顶元素 */
E peek();
/** 查看栈内元素数量 */
int getSize();
/** 是否为空栈 */
boolean isEmpty();
}
public class ArrayStack<E> implements Stack<E>{
public static final int DEFAULT_CAPACITY = 16;
private Array<E> data;
public ArrayStack(){
this(DEFAULT_CAPACITY);
}
public ArrayStack(int capacity){
data = new DynamicArray<>(capacity);
}
@Override
public void push(E e) {
data.addLast(e);
}
@Override
public E pop() {
return data.removeLast();
}
@Override
public E peek() {
return data.get(data.getSize()-1);
}
@Override
public int getSize() {
return data.getSize();
}
@Override
public boolean isEmpty() {
return data.isEmpty();
}
@Override
public String toString() {
StringBuilder sbr = new StringBuilder("stack size:").append(getSize());
sbr.append(" data: [");
for (int i = 0 ; i < getSize() ; i++){
sbr.append(data.get(i));
if(i != getSize() -1 ){
sbr.append(",");
}
}
sbr.append("] top");
return sbr.toString();
}
}
Leetcode练习-20 Valid Parentheses 匹配括号
/**
给定一个只包括 '(',')','{','}','[',']'的字符串,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
示例 1:
输入: "()"
输出: true
示例2:
输入: "()[]{}"
输出: true
示例3:
输入: "(]"
输出: false
示例4:
输入: "([)]"
输出: false
示例5:
输入: "{[]}"
输出: true
*/
public boolean isValid(String s) {
if(s == null || s.length() < 1 ){
return true;
}
if(s.length() % 2 != 0 ){
return false;
}
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 p = stack.pop();
if( ( p == '(' && c != ')' ) || ( p == '[' && c != ']') || ( p == '{' && c != '}') ){
return false;
}
}
}
return stack.isEmpty();
}
数组队列
public interface Queue<E> {
/** 入队 */
void enqueue(E e);
/** 出队 */
E dequeue();
/** 获取队首元素 */
E getFront();
/** 获取队列中元素数量 */
int getSize();
/** 是否为空 */
boolean isEmpty();
}
public class ArrayQueue<E> implements Queue<E>{
public static final int DEFAULT_CAPACITY = 16;
private Array<E> data;
public ArrayQueue(){
this(DEFAULT_CAPACITY);
}
public ArrayQueue(int capacity){
data = new DynamicArray<>(capacity);
}
@Override
public void enqueue(E e) {
data.addLast(e);
}
@Override
public E dequeue() {
return data.removeFirst();
}
@Override
public E getFront() {
return data.get(0);
}
@Override
public int getSize() {
return data.getSize();
}
@Override
public boolean isEmpty() {
return data.isEmpty();
}
@Override
public String toString() {
StringBuilder sbr = new StringBuilder("queue size:").append(getSize()).append(" capacity:").append(data.getCapacity());
sbr.append(" data: front [");
for (int i = 0 ; i < getSize() ; i++){
sbr.append(data.get(i));
if(i != getSize() -1 ){
sbr.append(",");
}
}
sbr.append("] tail");
return sbr.toString();
}
}
固定容量循环队列
public class LoopQueue<E> implements Queue<E>{
public static final int DEFAULT_CAPACITY = 16;
private E[] data;
private int front;
private int tail;
private int size;
public LoopQueue(){
this(DEFAULT_CAPACITY);
}
public LoopQueue(int capacity){
if(capacity < 1){
capacity = DEFAULT_CAPACITY;
}
data = (E[]) new Object[capacity];
}
private boolean isFull(){
return size == data.length;
}
@Override
public void enqueue(E e) {
if(isFull()){
throw new IllegalArgumentException("queue is full!");
}
data[tail] = e;
size++;
tail = (tail + 1) % data.length ;
}
@Override
public E dequeue() {
if(isEmpty()){
throw new IllegalArgumentException("queue is empty!");
}
E e = data[front];
data[front] = null;
size--;
front = (front + 1) % data.length;
return e;
}
@Override
public E getFront() {
if(isEmpty()){
throw new IllegalArgumentException("queue is empty!");
}
return data[front];
}
@Override
public int getSize() {
return size;
}
@Override
public boolean isEmpty() {
return size == 0;
}
@Override
public String toString() {
StringBuilder sbr = new StringBuilder("queue size:").append(getSize()).append(data.length);
sbr.append(" data: front [");
for (int i = 0 ; i < size ; i++){
int index = (front + i) % data.length;
sbr.append(data[index]);
if(i != size -1 ){
sbr.append(",");
}
}
sbr.append("] tail");
return sbr.toString();
}
}
动态容量循环队列
public class DynamicLoopQueue<E> implements Queue<E> {
public static final int DEFAULT_CAPACITY = 16;
private E[] data;
private int front;
private int tail;
private int size;
public DynamicLoopQueue(){
this(DEFAULT_CAPACITY);
}
public DynamicLoopQueue(int capacity){
if(capacity < 1){
capacity = DEFAULT_CAPACITY;
}
// 多留一个空间,用于区分队列空和满的情况
data = (E[])new Object[capacity+1];
}
private boolean isFull(){
return front == (tail + 1) % data.length;
}
private int getCapacity(){
return data.length - 1 ;
}
@Override
public void enqueue(E e) {
if(isFull()){
resize(getCapacity() * 2);
}
data[tail] = e;
tail = (tail +1)%data.length;
size++;
}
@Override
public E dequeue() {
if(isEmpty()){
throw new IllegalArgumentException("queue is empty!");
}
E e = data[front];
data[front] = null;
front = (front + 1) % data.length;
size--;
if(size < (getCapacity() / 4) && (getCapacity() / 2) != 0){
resize(getCapacity()/2);
}
return e;
}
@Override
public E getFront() {
if(isEmpty()){
throw new IllegalArgumentException("queue is empty!");
}
return data[front];
}
@Override
public int getSize() {
return size;
}
@Override
public boolean isEmpty() {
return front == tail;
}
private void resize(int newCapacity) {
E[] newData = (E[])new Object[newCapacity+1];
for (int i = 0 ; i < size ; i++ ){
int index = (front + i)%data.length;
newData[i] = data[index];
}
front = 0 ;
tail = size ;
data = newData;
}
@Override
public String toString() {
StringBuilder sbr = new StringBuilder(String.format("queue size= %d capacity= %d",getSize(),getCapacity()));
sbr.append(" data: front [");
for (int i = 0 ; i < size ; i++){
int index = (front + i) % data.length;
sbr.append(data[index]);
if(i != size -1 ){
sbr.append(",");
}
}
sbr.append("] tail");
return sbr.toString();
}
}
Leetcode 102. Binary Tree Level Order Traversal 二叉树层序遍历
public List<List<Integer>> levelOrder(TreeNode root) {
if(root == null){
return new ArrayList<>();
}
List<List<Integer>> result = new ArrayList<>();
Queue<Node> queue = new DynamicLoopQueue<>();
queue.enqueue(new Node(root,0));
int level = 0 ;
List<Integer> tmpList = new ArrayList<>();
while (!queue.isEmpty()){
Node node = queue.dequeue();
if(node.level != level){
result.add(tmpList);
tmpList = new ArrayList<>();
level = node.level;
}
tmpList.add(node.treeNode.val);
if(node.treeNode.left != null){
queue.enqueue(new Node(node.treeNode.left,node.level+1));
}
if(node.treeNode.right != null){
queue.enqueue(new Node(node.treeNode.right,node.level+1));
}
}
result.add(tmpList);
return result;
}
gitee地址:https://gitee.com/chentian114/chen_datastruct_study
github地址:https://github.com/chentian114/data-struct-and-algorithm
CSDN地址:https://blog.csdn.net/chentian114/category_9997109.html
Leetcode
刘宇波《玩转数据结构》课程