数据结构之栈和队列
Posted 王嘻嘻-
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构之栈和队列相关的知识,希望对你有一定的参考价值。
目录
1、栈(Stack)
1.1 概念
栈栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。 入栈 push:栈的插入操作叫做进栈/压栈/入栈,入栈数据在栈顶。 出栈 pop:栈的删除操作叫做出栈。出栈数据在栈顶。
1.2 代码实现
1. 利用顺序表实现,即使用尾插 + 尾删的方式实现 2. 利用链表实现,则头尾皆可
相对来说,顺序表的实现上要更为简单一些,所以我们优先用顺序表实现栈。
package stack_queue.stack;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
//基于数组的顺序表实现 栈
public class MyStack<E>
//当前栈的数据个数
private int size;
//实际存储数据的动态数组 - ArrayList
private List<E> data = new ArrayList<>();
/**
* 将val入栈
* @param val
*/
public void push(E val)
//默认尾插
data.add(val);
size++;
/**
* 弹出栈顶元素
* 返回栈顶的值
* @return
*/
public E pop()
if (isEmpty())
//栈为空
throw new NoSuchElementException("stack is empty!cannot pop!");
//删除栈顶元素
E val = data.remove(size - 1);
size--;
return val;
//等同于 return data.remove(--size);
/**
* 返回栈顶元素但不出栈
* @return
*/
public E peek()
if (isEmpty())
throw new NoSuchElementException("stack is empty!cannot peek");
return data.get(size-1);
/**
* 判断当前栈是否为空
* @return
*/
private boolean isEmpty()
return size == 0;
@Override
public String toString()
StringBuilder sb = new StringBuilder();
sb.append("[");
for (int i = 0; i < size; i++)
sb.append(data.get(i));
if (i!=size-1)
//此时还未到栈顶,还没到数组末尾
sb.append(",");
sb.append("] top");
return sb.toString();
2. 队列(Queue)
2.1 概念
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾(Tail/Rear) 出队列:进行删除操作的一端称为队头 (Head/Front)
2.2 代码实现
package stack_queue.queue.impl;
import java.util.NoSuchElementException;
/**
* 基于链表实现的基础队列
*/
public class MyQueue<E> implements Queue<E>
//链表的每个节点
private class Node
E val;
Node next;
public Node(E val)
this.val = val;
//当前队列中的元素个数
private int size;
//队首
private Node head;
//队尾
private Node tail;
//入队
@Override
public void offer(E val)
Node node = new Node(val);
if (head == null)
//此时链表为空
head = tail = node;
else
tail.next = node;
tail = node;
size++;
//出队
@Override
public E poll()
if (isEmpty())
throw new NoSuchElementException("queue is empty!cannot poll!");
E val = head.val;
Node node = head;
head = head.next;
//将原来头节点脱钩
node.next = null;
size--;
return val;
//返回队首元素
@Override
public E peek()
if (isEmpty())
throw new NoSuchElementException("queue is empty!cannot peek!");
return head.val;
@Override
public boolean isEmpty()
return size == 0;
@Override
public String toString()
StringBuilder sb = new StringBuilder();
sb.append("front [");
//链表的遍历
for (Node x =head; x != null;x = x.next)
sb.append(x.val);
if (x.next != null)
//还没走到链表尾部
sb.append(",");
sb.append("]");
return sb.toString();
2.3 循环队列
实际中我们有时还会使用一种队列叫循环队列。如操作系统课程讲解生产者消费者模型时可以就会使用循环队列。 环形队列通常使用数组实现。
数组下标循环的小技巧
1. 下标最后再往后(offset 小于 array.length): index = (index + offset) % array.length
2. 下标最前再往前(offset 小于 array.length): index = (index + array.length - offset) % array.length
2.3.1 思路解析
2.3.2 代码实现
package stack_queue.queue.impl;
import java.util.Arrays;
import java.util.NoSuchElementException;
//基于整形的循环队列
public class LoopQueue implements Queue<Integer>
private Integer[] data;
//指向当前循环队列的队首元素
private int head;
//指向当前循环队列的队尾元素的下一个位置
private int tail;
//当前队列中元素个数
private int size;
//n为希望保存的元素个数
public LoopQueue(int n)
//在循环队列中浪费一个空间不能存储元素,来判断是否已满
data = new Integer[n + 1];
@Override
public void offer(Integer val)
if (isFull())
throw new ArrayIndexOutOfBoundsException("queue is full!cannot offer new val");
data[tail] = val;
tail = (tail + 1) % data.length;
size++;
@Override
public Integer poll()
if (isEmpty())
throw new NoSuchElementException("queue is empty!cannot poll");
Integer val = data[head];
head = (head + 1) % data.length;
size--;
return val;
@Override
public Integer peek()
if (isEmpty())
throw new NoSuchElementException("queue is empty!cannot peek");
return data[head];
@Override
public boolean isEmpty()
return tail == head;
@Override
public String toString()
StringBuilder sb = new StringBuilder();
sb.append("front [");
//取得最后一个元素下标
int lastIndex = tail == 0 ? data.length - 1 : tail - 1;
for (int i = head;i != tail;)
sb.append(data[i]);
if (i!=lastIndex)
sb.append(", ");
i = (i + 1) % data.length;
sb.append("] tail");
return sb.toString();
public boolean isFull()
return (tail + 1) % data.length == head;
3. 双端队列 (Deque)
3.1 概念
双端队列(deque)是指允许两端都可以进行入队和出队操作的队列,deque 是 “double ended queue” 的简称。 那就说明元素可以从队头出队和入队,也可以从队尾出队和入队。
3.2 代码实现
package stack_queue.queue;
import java.util.ArrayDeque;
import java.util.Deque;
//双端队列
public class DequeTest
public static void main(String[] args)
Deque<Integer> deque = new ArrayDeque<>();
deque.addLast(1);
deque.addLast(3);
deque.addLast(5);
//尾插尾删或者头插头删就是栈
while (!deque.isEmpty())
System.out.println(deque.pollLast());//5 3 1
// //头插尾删或者尾插头删就是队列
// while (!deque.isEmpty())
// System.out.println(deque.pollFirst());//1 3 5
//
本节完^_^
以上是关于数据结构之栈和队列的主要内容,如果未能解决你的问题,请参考以下文章