代码随想录算法训练营day10|栈和队列(JAVA版)| 232用栈实现队列| 235用队列实现栈

1 基础知识

​ https://blog.csdn.net/AlinaQ05/article/details/126196718

​ https://blog.csdn.net/qq_43647936/article/details/131940968

​ https://blog.51cto.com/bitzmbdp/6273652

以上为本篇总结的来源

1.1 栈

​ 栈是一种仅支持在表尾进行插入和删除操作的线性表,这一端被称为栈顶,另一端被称为栈底。元素入栈指的是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;元素出栈指的是从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。栈中的元素遵守后进先出(LIFO)的原则.

在这里插入图片描述

  • 栈的种类

    栈的底层实现有两种,基于数组的实现:顺序栈(ArrayList);基于链表的实现:链式栈(LinkedList)。

1.2栈的实现

1.2.1 数组实现
// 数组栈
public class ArrayStack {
	
	int maxSize;
	int[] list;    //数组模拟栈,数据放在该数组
	int top = 0;   //表示栈顶,初始化为0
	// 初始化栈
	public ArrayStack(int maxSize) {
		this.maxSize = maxSize;
		list = new int[maxSize];
		
	}
	
	// 入栈操作
	public void push(int val) {
		if (top >= maxSize) {
			System.out.println("The stack is max!");
		} else {
			list[top] = val;
			top++;
		}
	}
	
	// 出栈操作
	public void pop() {
		if (top == 0) {
			System.out.println("Error! The stack is empty!");
		} else {
			top--;
		}
	}
	
	// 打印栈
	public void display() {
        if(top == 0){
            System.out.println("The stack is empty!");
           return;
        }
		for(int i = 0; i < top; i++) {
			System.out.print(list[i]+" ");
		}
		System.out.println();
	}
	
	// 清空栈
    public void clear() {
    	top = 0;
    }
    
    // 判空
    public boolean isEmpty() {
    	if (top == 0) {
    		return true;
    	} else {
    		return false;   		
    	}
    }
 
    // 返回栈顶元素
    public Object peek() {
    	if (top != 0) {
    		return list[top-1];    		
    	} else {
    		return null;
    	}
    }
	
	public static void main(String[] args) {
		ArrayStack arrayStack = new ArrayStack(5);

		System.out.println(arrayStack.isEmpty());
		arrayStack.push(1);
		arrayStack.push(2);
		arrayStack.push(3);
		arrayStack.push(4);
		arrayStack.display();		
		arrayStack.pop();
		arrayStack.display();		
		arrayStack.push(5);
		arrayStack.display();
		System.out.println(arrayStack.peek());
		System.out.println(arrayStack.isEmpty());
		arrayStack.clear();
		arrayStack.display();
		System.out.println(arrayStack.peek());
		System.out.println(arrayStack.isEmpty());
	}	
}


1.2.3 链表实现
// 链栈
public class LinkStack {	
	// 链栈的结点构造
	class StackNode{
		int val; // 每个节点存放的值
		StackNode next; // 指向下一个节点
		StackNode() {
		}
		StackNode(int val) { 
			this.val = val; 
		}
		StackNode(int val, StackNode next) {
			this.val = val;
			this.next = next; 
		}		
	}
	int size = 0;
	StackNode topNode;
	
	// 入栈操作!即把元素插入栈顶,和头插法相同
	public void push (int val) {
		StackNode newStackNode = new StackNode();
		newStackNode.val = val;
		if (topNode == null) {
			topNode = newStackNode;
			size ++;
		} else {
			newStackNode.next = topNode;
			topNode = newStackNode;
			size ++;
		}
		System.out.println(val + " has been stacked!");
	}
	
	// 出栈操作!top指针直接下移即可
	public void pop () {
		if (topNode == null) {
			System.out.println("Error! The stack is empty!");
		} else {
			int popValue = topNode.val; // 接收一下出栈的元素,方便后面打印出来
			topNode = topNode.next; // 栈顶指针(即链表头结点)直接指向下一个元素即可删除
			size--;
			System.out.println(popValue + " is out of stack!");
		}
	}
	//打印栈 输出栈中的元素
	public void display () {
		StackNode current = topNode;
		while(current != null){
			System.out.print(current.val);
			if (current.next != null) {
				System.out.print(" ");
			}
			current = current.next;
		}
		System.out.println();
	}
	//返回栈顶元素
	public int peek() {
		if(topNode == null) {
			System.out.println("The stack is empty!");
		}
		return topNode.val;		
	}
	//清空
	public void clear () {
		if(topNode == null) {
			System.out.println("The stack is empty!");
		} else {
			topNode = null;
			System.out.println("Stack has been emptied!");
		}
	}
	//是否为空
	public boolean isEmpty () {
		if (topNode == null) {
			return true;
		} else {
			return false;
		}
	}
	
	public static void main(String[] args) {
		LinkStack linkStack = new LinkStack();
		
		linkStack.push(2);
		linkStack.push(3);
		linkStack.display();
		
		linkStack.pop();
		
		linkStack.display();
		System.out.println("The topNode is "+linkStack.peek());
		linkStack.clear();
		System.out.println("The stack is null? "+linkStack.isEmpty());
		linkStack.push(8);
		linkStack.push(7);
		linkStack.push(5);
		linkStack.display();
		System.out.println("The stack is null? "+linkStack.isEmpty());
	}
	
}


1.2.3 java导包实现栈

https://blog.51cto.com/bitzmbdp/6273652 来源

  • 普通顺序栈

首先我们先学习普通顺序栈,创建一个栈得知道栈的类是是什么->Stack,并且还要导包,我们试着创建一个这个类的对象,代码实现如下:

import java.util.Stack;//栈的包
public class Test {
    public static void main(String[] args) {
        Stack</*数据类型*/> stack = new Stack</*数据类型*/>();
    }
}

如上,一个顺序栈就创建好了,但是,在Java 1.4及之前版本中,Stack底层采用了Vector类作为其内部实现(Vector是一种以动态数组实现的序列容器)。而在Java 1.5之后的版本中,Stack被废弃了,官方推荐使用DequeArrayDeque代替。而Deque接口的其中一个实现就是LinkedList类,也就是说,如果使用LinkedList作为一个栈的基本数据结构,那么它底层的实现是基于双向链表的数据结构,而LinkedList就是下文需要讲述的对象。

  • 链式栈

通俗点来说就是以双链表为底层来实现的栈,在双链表尾部入栈,尾部出栈,或者头部入栈,头部出栈。上文说到Srack不常用了,所以一般现在都用链式栈,链式栈的类是Deque,它不仅仅可以当作栈,还可以当作队列,因为Deque类里面还实现了队列的方法,下文会细说。创建链式栈代码实现如下:

import java.util.LinkedList;
import java.util.Queue;
public class Test {
    public static void main(String[] args) {
       Deque<Integer> stack = new LinkedList<>();
    }

}
  • 栈的常用方法
方法功能
Stack()创建一个空栈
E push(E e)返回值类型是入栈元素的类型,将e入栈,并返回e
E pop()返回值类型入栈元素的类型,将栈顶元素出栈并返回
E peek()返回值类型入栈元素的类型,获取栈顶元素
int size()返回值类型是int类型,获取栈中有效元素个数
boolean empty()返回值类型是布尔类型,检测栈是否为空,为空返回true,否则返回false

下面是每个方法的使用代码实现:

import java.util.Stack;
public class Test {
    public static void main(String[] args) {
        //Stack():创建栈,使用实现代码如下:
        Stack<Integer> stack = new Stack<>();
        //如上就创建了一个栈,栈里储存的数据类型是Integer类型
        
        //push(E e):将元素入栈
        int a = stack.push(1);
        int b = stack.push(2);
        stack.push(3);
        stack.push(4);
        stack.push(5);
        System.out.println(a);
        System.out.println(b);
        System.out.println("==================");
        // pop():出栈 将栈最顶上一个元素返回,并且删除该元素
        int pop = stack.pop();
        System.out.println(pop);
        System.out.println("==================");
        // peek():查看栈顶元素 就仅仅只是查看栈顶元素,但是不删除
        int pek1 = stack.peek();
        int pek2 = stack.peek();
        System.out.println(pek1);
        System.out.println(pek2);
        System.out.println("==================");
        //size():获取栈中有效元素个数
        System.out.println(stack.size());
        System.out.println("==================");
        // empty():判断栈是否为空 判断栈内是否有元素,为空返回true,不为空返回false
        System.out.println(stack.empty());
        // 全部出栈,让栈空掉
        while (!stack.empty()) {
            stack.pop();
        }
        System.out.println(stack.empty());
    }
}

1.3 队列

  • 队列的概念

    ​ 队列是一种常见的数据结构,它以先进先出方式处理数据。这意味着只有最早进入队列的元素才能首先被弹出,后来越晚加入的元素会排在较深的位置,等待之前元素全部出队后才能被依次出队。现实生活中也有很多例子,比如排队打饭,排队候车等等。

在这里插入图片描述

  • 队列的种类

    队列的种类也分两种,顺序队列和链式队列

    • 顺序队列:底层是数组,从一端进,另一端出

    • 链式队列:链式队列底层是链表,也是从一端进,另一端出

1.3.1 数组实现
package queue;

// 队列
public class ArrayQueue {
	
	int maxSize; // 队列最大容量
	int[] list; //数组模拟队列,数据放在该数组
	int front = 0; //队头指针front,指向队头元素
	int rear = 0; //队尾指针rear,指向下一个入队元素的存储位置
	int currentSize; // 记录当前队列有几个元素
	// 初始化队列
	public ArrayQueue(int maxSize) {
		this.maxSize = maxSize;
		list = new int[maxSize];
        front = 0;
        rear = 0;
        currentSize = 0;
	}
	
	// 入队
    //将要入队的值存入数组中,同时队尾指针rear后移。
	//如果队列已经满了,则添加失败。
	//可以在队列满后创建一个更大的数组来优化操作
	public void enQueue (int val) {
		if (currentSize >= maxSize) {
			System.out.println("Error! The queue is full!");
		} else {
			list[rear % maxSize] = val;
			rear ++;
			currentSize ++;
			System.out.println(val + " has been queued!");
		}		
	}
	
	// 出队 队头指针front后移
	public void deQueue () {
		if (currentSize == 0) {
			System.out.println("Error! The queue is empty!");
		} else {
			int dequeueValue = list[front];
			front = (front + 1) % maxSize;
			currentSize --;
			System.out.println(dequeueValue + " is dequeued!");
		}
	}
	//打印列
	public void display () {
        if(rear == front){
            System.out.println("The queue is empty!");
           return;
        }
		for(int i = front; i < rear; i++) {
			System.out.print(list[i % maxSize]+" ");
		}
		System.out.println();
	}
	
	public static void main(String[] args) {
		ArrayQueue arrayQueue = new ArrayQueue(9);
		
		arrayQueue.enQueue(1);
		arrayQueue.enQueue(2);
		arrayQueue.enQueue(3);
		arrayQueue.enQueue(4);
		arrayQueue.enQueue(5);
		arrayQueue.enQueue(6);
		arrayQueue.enQueue(7);
		arrayQueue.enQueue(8);
		arrayQueue.enQueue(9);
		
		arrayQueue.display();
		
		arrayQueue.deQueue();
		arrayQueue.enQueue(1);
		arrayQueue.display();
	}
}

1.3.2 链表实现
package queue;

// 链式队列
public class LinkQueue {
	// 链式队列的结点构造
	static class QueueNode{	
		int val; 
		QueueNode next;
		// 初始化栈
		QueueNode() {
		}
		QueueNode(int val) { 
			this.val = val; 
		}
		QueueNode(int val, QueueNode next) {
			this.val = val;
			this.next = next;
		}
	}

	int size = 0; // 记录当前队列有几个元素
	QueueNode front; // 队头指针front,指向队头元素
	QueueNode rear; // 队尾指针rear,指向下一个入队元素的存储位置
	QueueNode back; // 队尾指针back,指向队尾元素
	
	public void enQueue(int val) {
		 QueueNode queueNode = new QueueNode();
		 queueNode.val = val;
		 if (front == null) {
			 front = queueNode;
			 back = queueNode;
			 System.out.println(val + " has been queued!");
			 size ++;
		 } else {
			 back.next = queueNode;
			 back = back.next;
			 System.out.println(val + " has been queued!");
			 size ++;
		 }
	}
	
	public void deQueue() {
		if (front == null) {
			System.out.println("Error! The queue is empty!");
		} else {
			front = front.next;
		}
	}
	
	public void display () {
		QueueNode current = front;
		while(current != null){
			System.out.print(current.val);
			if (current.next != null) {
				System.out.print(" ");
			}
			current = current.next;
		}
		System.out.println();
	}
	
	public static void main(String[] args) {
		LinkQueue linkQueue = new LinkQueue();		
		linkQueue.enQueue(1);
		linkQueue.enQueue(2);
		linkQueue.enQueue(3);
		linkQueue.enQueue(4);		
		linkQueue.display();
		linkQueue.deQueue();		
		linkQueue.display();		
	}
}

1.3.3 java导包实现
  • 顺序队列

首先我们得知道队列的类是ArrayDeque,它实现了Queue接口,所以代码实现入下:

import java.util.ArrayDeque;
import java.util.Queue;
public class ArrayDequeQueueExample {
    public static void main(String[] args) {
        // 创建一个ArrayDeque作为队列
        Queue</*元素类型*/> queue = new ArrayDeque<>();
    }
}
  • 链式队列

链式队列的类是LinkedList,它也实现了Queue接口,代码实现如下:

import java.util.LinkedList;
import java.util.Queue;
public class Test {
    public static void main(String[] args) {
        // 创建一个LinkedList作为队列
        Queue<Integer> queue1 = new LinkedList<>();
    }
}
  • 队列的常用方法
方法功能
boolean offer(E e)返回值类型是布尔类型,入队列
E poll()返回值类型是队列中元素的类型,出队列
E peek()返回值类型是队列中元素的类型,获取队头元素
int size()返回值类型是int类型,获取队列中有效元素个数
boolean isEmpty()返回值类型是布尔类型,检测队列是否为空
import java.util.LinkedList;
import java.util.Queue;
public class Test {
    public static void main(String[] args) {
        // 创建一个LinkedList作为队列
        Queue<Integer> queue = new LinkedList<>();
        // boolean offer(E e):表示将元素入队列 入队成功返回true,失败则返回false
        boolean falg = queue.offer(1);
        queue.offer(2);
        queue.offer(3);
        queue.offer(4);
        queue.offer(5);
        System.out.println(falg);
        System.out.println("==================");
        // E poll():将元素弹出队列,返回该元素
        int a = queue.poll();
        int b = queue.poll();
        System.out.println(a);
        System.out.println(b);
        System.out.println("==================");
        // E peek():返回队头元素 返回队列头部元素,但是不删除
        int c = queue.peek();
        int d = queue.peek();
        System.out.println(c);
        System.out.println(d);
        System.out.println("==================");
        // int size():获取队列中有几个元素,返回元素个数
        int size = queue.size();
        System.out.println(size);
        System.out.println("==================");
        // boolean isEmpty():判空判断队列是否为空,为空返回true,否则返回false
        falg = queue.isEmpty();
        System.out.println(falg);
        // 将队列全部弹出
        while (!queue.isEmpty()) {
            queue.poll();
        }
        falg = queue.isEmpty();
        System.out.println(falg);

    }
}

2 Leetcode题

232.用栈实现队列

力扣题目链接 (opens new window)

使用栈实现队列的下列操作:

push(x) – 将一个元素放入队列的尾部。
pop() – 从队列首部移除元素。
peek() – 返回队列首部的元素。
empty() – 返回队列是否为空。

示例:

MyQueue queue = new MyQueue();
queue.push(1);
queue.push(2);
queue.peek();  // 返回 1
queue.pop();   // 返回 1
queue.empty(); // 返回 false

说明:

  • 你只能使用标准的栈操作 – 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。
  • 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
  • 假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)。

思路:

用输入栈和输出栈实现队列

把出栈的元素放到输出栈中

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wIyrFOE4-1691121265539)(C:\Users\86188\AppData\Roaming\Typora\typora-user-images\1691118196562.png)]

执行语句:
queue.push(1);
queue.push(2);
queue.pop(); 注意此时的输出栈的操作
queue.push(3);
queue.push(4);
queue.pop();
queue.pop();注意此时的输出栈的操作
queue.pop();
queue.empty();

  • **模拟入队:**在push数据的时候,只要数据放进输入栈就好,

  • 模拟出队:输出栈如果为空,就把进栈数据全部导入进来(注意是全部导入),再从出栈弹出数据,如果输出栈不为空,则直接从出栈弹出数据就可以了。

  • 如何判断队列为空呢?如果进栈和出栈都为空的话,说明模拟的队列为空了。

class MyQueue {

    Stack<Integer> inStack;
    Stack<Integer> outStack;
    public MyQueue() {
        inStack=new Stack<>();
        outStack=new Stack<>();

    }
    
    public void push(int x) {
        inStack.push(x);

    }
    
    public int pop() {
        transfer();
        return outStack.pop();
    }
    
    public int peek() {
         transfer();
         return outStack.peek();

    }
    
    public boolean empty() {
        return inStack.isEmpty() && outStack.isEmpty();
    }
    public void transfer(){
        if(!outStack.isEmpty()) return;
        while(!inStack.isEmpty()){
            outStack.push(inStack.pop());
        }
    }

225. 用队列实现栈

力扣题目链接 (opens new window)

使用队列实现栈的下列操作:

  • push(x) – 元素 x 入栈
  • pop() – 移除栈顶元素
  • top() – 获取栈顶元素
  • empty() – 返回栈是否为空

注意:

  • 你只能使用队列的基本操作-- 也就是 push to back, peek/pop from front, size, 和 is empty 这些操作是合法的。

  • 你所使用的语言也许不支持队列。 你可以使用 list 或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。

  • 你可以假设所有操作都是有效的(例如, 对一个空的栈不会调用 pop 或者 top 操作)。

  • 使用两个队列实现

class MyStack {
    //q1作为主要的队列,其元素排列顺序和出栈顺序相同
    Queue<Integer> q1 = new ArrayDeque<>();
    //q2仅作为临时放置
    Queue<Integer> q2 = new ArrayDeque<>();

    public MyStack() {

    }
    //在加入元素时先将q1中的元素依次出栈压入q2,然后将新加入的元素压入q1,再将q2中的元素依次出栈压入q1
    public void push(int x) {
        while (q1.size() > 0) {
            q2.add(q1.poll());
        }
        q1.add(x);
        while (q2.size() > 0) {
            q1.add(q2.poll());
        }
    }

    public int pop() {
        return q1.poll();
    }

    public int top() {
        return q1.peek();
    }

    public boolean empty() {
        return q1.isEmpty();
    }
}

  • 使用一个队列实现
class MyStack {

    Queue<Integer> queue;

    public MyStack() {
        queue = new LinkedList<>();
    }

    //每 offer 一个数(A)进来,都重新排列,把这个数(A)放到队列的队首
    public void push(int x) {
        queue.offer(x);
        int size = queue.size();
        //移动除了 A 的其它数
        while (size-- > 1)
            queue.offer(queue.poll());
    }

    public int pop() {
        return queue.poll();
    }

    public int top() {
        return queue.peek();
    }

    public boolean empty() {
        return queue.isEmpty();
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
代码随想录算法训练营是一个优质的学习和讨论平台,提供了丰富的算法训练内容和讨论交流机会。在训练营中,学员们可以通过观看视频讲解来学习算法知识,并根据讲解内容进行刷题练习。此外,训练营还提供了刷题建议,例如先看视频、了解自己所使用的编程语言、使用日志等方法来提高刷题效果和语言掌握程度。 训练营中的讨论内容非常丰富,涵盖了各种算法知识点和解题方法。例如,在第14天的训练营中,讲解了二叉树的理论基础、递归遍历、迭代遍历和统一遍历的内容。此外,在讨论中还分享了相关的博客文章和配图,帮助学员更好地理解和掌握二叉树的遍历方法。 训练营还提供了每日的讨论知识点,例如在第15天的讨论中,介绍了层序遍历的方法和使用队列来模拟一层一层遍历的效果。在第16天的讨论中,重点讨论了如何进行调试(debug)的方法,认为掌握调试技巧可以帮助学员更好地解决问题和写出正确的算法代码。 总之,代码随想录算法训练营是一个提供优质学习和讨论环境的平台,可以帮助学员系统地学习算法知识,并提供了丰富的讨论内容和刷题建议来提高算法编程能力。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [代码随想录算法训练营每日精华](https://blog.csdn.net/weixin_38556197/article/details/128462133)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值