本篇文章给大家带来了关于Java的相关知识,其中主要整理了栈和队列的相关问题,包括了栈和队列的定义、应用、实现和操作等等内容,下面一起来看一下,希望对大家有帮助。
|
本篇文章给大家带来了关于java的相关知识,其中主要整理了栈和队列的相关问题,包括了栈和队列的定义、应用、实现和操作等等内容,下面一起来看一下,希望对大家有帮助。
推荐学习:《java视频教程》 在学习栈和队列 之前,先了解一下什么是线性表:一次保存单个同类型的元素,多个元素之间逻辑上连续,比如数组,链表,字符串,栈和队列 一、栈1.定义只能在一端插入元素,也只能在这一端删除元素(栈顶),可以把栈看作一个“水杯”,只能从一端添加元素,也只能从一段删除元素,而且,先进入水杯的水在杯底,后进入水杯的水在杯顶,往出倒水的时候,也是倒出的杯顶的水,栈也是一样,先入栈的元素在栈底,后入栈的元素在栈顶,所以先入栈的元素后出,后入栈的元素先出,这也是栈的特性“先进后出,后进先出”Last In First Out(LIFO),取出元素和添加元素只能在栈顶。 2.栈的应用1.无处不在的undo(撤销)操作在任何一个编辑器中输错一个内容后,使用Ctrl + z就返回到了输入的内容; 2.操作系统栈程序再执行的过程中,从A函数调用B函数,从B函数调用C函数,调用结束,返回执行时,如何得知从哪继续开始执行呢,背后也是栈这个结构 3.栈的实现基于链表实现的栈 – 链式栈 //基于动态数组实现的顺序栈public class MyStack<E> {
//记录当前栈的元素个数
private int size;
//实际存储数据的动态数组,此时在栈中只能在数组的尾部添加和删除元素
private List<E> data = new ArrayList<>();
}4.栈的操作1.向栈中添加一个元素 /**
* 向当前栈中添加元素 -- >压栈操作
* @param val
*/
public void push(E val){
data.add(val);
size++;
}2.当前从栈顶弹出一个元素 /**
* 弹出当前栈顶元素,返回栈顶元素的值
* @return
*/
public E pop(){
if (isEmpty()){
//栈为空无法弹出
throw new NoSuchElementException("stack is empty!cannot pop!");
}
//在数组末尾删除元素
E val = data.get(size - 1);
data.remove(size - 1);
size --;
return val;
}3.查看当前栈顶元素,但不弹出 /**
* 查看当前栈顶元素值,不弹出该元素
* @return
*/
public E peek(){
if (isEmpty()){
throw new NoSuchElementException("stack is empty!cannot peek!");
}
return data.get(size - 1);
}二、队列1.定义队列:先进先出(FIFO)的数据结构i,元素只能从队尾添加到队列中,也只能从队首出队列,元素的出队顺序和入队顺序保持一致 2.队列的应用现实生活中,各种各样的“排队”操作 3.队列的实现基于数组实现的队列 – 顺序队列 public interface Queue<E> {
//入队操作
void offer(E val);
//出队操作
E poll();
//查看队首元素
E peek();
boolean isEmpty();}对于栈来说队列的实现子类是比较多的,比如 4.FIFO队列1.定义一个FIFO队列 // An highlighted blockvar foo = 'bar'; 2.向队列中添加一个元素 public void offer(E val) {
Node<E> node = new Node<>(val);
if (head == null){
head = tail = node;
}else{
//链表的尾插
tail.next = node;
tail = node;
}
size++;
}3.从当前队首出队一个元素 public E poll() {
if (isEmpty()){
throw new NoSuchElementException("queue is empty! cannot poll!");
}
//头删
E val = head.val;
Node<E> node = head;
head = head.next;
node.next = node = null;
size--;
return val;
}4.查看当前队列的队首元素 public E peek() {
if (isEmpty()){
throw new NoSuchElementException("queue is empty!cannot peek!");
}
return head.val;
}5.循环队列1.定义:基本上都是使用固定长度的数组来实现,数组在实现队时,若从数组头部删除元素需要频繁的移动后面的元素,效率比较低;出队和入队操作,使用两个引用,一个head,一个tail,添加元素在数组的尾部添加,删除元素只需要移动head引用指向的地址即可(逻辑删除)
6.循环队列的操作1.定义一个循环队列 //基于整形的循环队列public class LoopQueue implements Queue<Integer> {
//定长数组
private Integer[] data;
//指向队首元素
int head;
//指向队尾元素的下一个元素
int tail;
public LoopQueue(int size){
data = new Integer[size + 1];
}}2.向循环队列中添加一个元素 @Override public void offer(Integer val) {
if (isFull()){
throw new ArrayIndexOutOfBoundsException("loopQueue is full!cannot offer");
}
data[tail] = val;
tail = (tail + 1) % data.length;
}3.从循环队列中出队一个元素 @Override public Integer poll() {
if (isEmpty()){
throw new NoSuchElementException("loopQueue is empty!cannot poll!");
}
Integer val = data[head];
head = (head + 1) % data.length;
return val;
}4.查看当前循环队列队首元素 @Override public Integer peek() {
if (isEmpty()){
throw new NoSuchElementException("loopQueue is empty!cannot peek!");
}
return data[head];
}5.判断当前循环队列是否为空 @Override public boolean isEmpty() {
return head == tail;
}6.判断当前循环队列是否已满 public boolean isFull(){
return (tail + 1) % data.length == head;
}7.toString方法 public String toString(){
StringBuilder sb = new StringBuilder();
sb.append("front [");
//最后一个有效元素的索引
int lsatIndex = tail == 0 ? data.length - 1 : tail - 1;
for (int i = head; i != tail;) {
sb.append(data[i]);
if (i != lsatIndex){
sb.append(", ");
}
i = (i + 1) % data.length;
}
sb.append("] tail");
return sb.toString();
}7.双端队列双端队列:Deque是Queue的子接口,这个队列既可以尾插,头出;也可以头插,尾出 推荐学习:《java视频教程》 以上就是一文带你认识Java栈和队列的详细内容,更多请关注模板之家(www.mb5.com.cn)其它相关文章! |
