• 【数据结构】栈和队列重点知识汇总(附有OJ题)


    目录

    思维导图:

    1.栈(Stack):

    2.栈的模拟实现:

    3.栈的OJ题:

    4.队列(Queue):

    5.队列的模拟实现:

    6.队列的OJ题:


    思维导图

    1.栈(Stack):

    1. 栈是一种线性表,只允许固定的一端进行插入和删除操作,栈中元素遵循着“先进后出”的原则。往栈中插入元素叫做压栈;栈中弹出删除元素叫做出栈。想象一下装满子弹的弹夹,先装的子弹最后才会被打出去;而最后装的子弹最先打出去,栈就和弹夹的类似。底层上看栈就类似于数组
    2. 栈的使用方法
      方法作用
      push(x);压栈,将元素x入栈
      pop();出栈,删除栈顶元素
      peek();获取栈顶元素,但不删除
      size();获取栈中有效的元素个数
      empty();检测栈是否为空,空返回 true
    3. 栈和虚拟机栈还有函数栈帧不是一个东西!
       

    2.栈的模拟实现:

    底层是数组实现的

    1. public class MyStack {
    2. public int[] elem;
    3. public int usedSize;//存放有效元素个数
    4. public static final int DEFAULT_CAPACITY = 20;//默认容量
    5. public MyStack(){
    6. elem = new int[DEFAULT_CAPACITY];
    7. }
    8. //压栈
    9. public void push(int data){
    10. if(isFull()){
    11. elem = Arrays.copyOf(elem,elem.length*2);
    12. }
    13. elem[usedSize] = data;
    14. usedSize++;
    15. }
    16. //判断elem有没有满,满了返回true
    17. private boolean isFull() {
    18. return elem.length == usedSize;
    19. }
    20. //判断elem是否为空,空则返回true
    21. public boolean isEmpty(){
    22. return usedSize==0;
    23. }
    24. //删除栈顶元素
    25. public int pop(){
    26. if(isEmpty()){
    27. return -1;
    28. }
    29. int oldvalue = elem[usedSize-1];
    30. usedSize--;
    31. return oldvalue;
    32. }
    33. //查看栈顶元素,不删除
    34. public int peek(){
    35. if(isEmpty()){
    36. return -1;
    37. }
    38. int ret = elem[usedSize-1];
    39. return ret;
    40. }
    41. //获取栈中元素个数
    42. public int size(){
    43. return usedSize;
    44. }
    45. }

    3.栈的OJ题:

    1.不可能的出栈顺序:出栈的时候也可以进栈。

    2.逆波兰表达式(往栈中存放数字,遇到符号就从栈中拿出俩个数字,运算后结果放回栈中)。

    1. public class Test {
    2. public int evalRPN(String[] tokens) {
    3. Stack stack = new Stack<>();
    4. for (String x : tokens){
    5. if(!isOpeation(x)){
    6. stack.push(Integer.parseInt(x));
    7. }else{
    8. //num2在+-*/的右边,num1在左边。顺序不能换
    9. int num2 = stack.pop();
    10. int num1 = stack.pop();
    11. switch (x){
    12. case "+":
    13. stack.push(num1+num2);
    14. break;
    15. case "-":
    16. stack.push(num1-num2);
    17. break;
    18. case "*":
    19. stack.push(num1*num2);
    20. break;
    21. case "/":
    22. stack.push(num1/num2);
    23. break;
    24. }
    25. }
    26. }
    27. return stack.pop();
    28. }
    29. private boolean isOpeation(String str) {
    30. if(str.equals("+")||str.equals("-")
    31. ||str.equals("*")||str.equals("/")){
    32. return true;
    33. }
    34. return false;
    35. }
    36. }

    3.判断括号匹配(判断匹配有俩个条件,字符串遍历完成了;栈为空)。

    1. class Solution {
    2. public boolean isValid(String s) {
    3. Stack stack = new Stack<>();
    4. for (int i = 0; i < s.length(); i++) {
    5. char ch = s.charAt(i);
    6. if(ch=='[' || ch=='{' || ch=='('){
    7. stack.push(ch);
    8. }else{
    9. //必须要判断栈是否为空,否则会报错
    10. if(stack.empty()){
    11. return false;
    12. }
    13. if(ch == ']' && stack.peek() == '['
    14. ||ch == '}' && stack.peek() == '{'
    15. ||ch == ')' && stack.peek() == '('){
    16. stack.pop();
    17. }else{
    18. return false;
    19. }
    20. }
    21. }
    22. //如果栈不为空,则左括号多
    23. if(stack.empty()){
    24. return true;
    25. }else{
    26. return false;
    27. }
    28. }
    29. }

    4.实现递归:逆序打印链表。

    1. class Solution {
    2. //实现递归
    3. public void printList(ListNode head){
    4. if(head == null) return;
    5. if(head.next == null){
    6. System.out.println(head.val+" ");
    7. return;
    8. }
    9. printList(head.next);
    10. System.out.println(head.val+" ");
    11. }
    12. //栈实现递归,使用到了单链表
    13. public void printList2(ListNode head){
    14. Stack stack = new Stack<>();
    15. ListNode cur = head;
    16. while(cur != null){
    17. stack.push(cur);
    18. cur = cur.next;
    19. }
    20. while(!stack.empty()){
    21. System.out.print(stack.pop());
    22. }
    23. }
    24. }

    5.判断出栈次序是否匹配。

    1. public class Solution {
    2. public boolean IsPopOrder(int [] pushA,int [] popA) {
    3. if(pushA.length == 0 || popA.length == 0){
    4. return false;
    5. }
    6. Stack stack = new Stack<>();
    7. int j = 0;
    8. for (int i = 0; i < pushA.length; i++) {
    9. stack.push(pushA[i]);
    10. //特别注意这个循环条件
    11. while(i < popA.length
    12. && !stack.empty()
    13. //stack.peek()和popA[j]比较时用equal更好,==不严谨
    14. && stack.peek().equals(popA[j])){
    15. stack.pop();
    16. j++;
    17. }
    18. }
    19. return stack.empty();
    20. }
    21. }

    4.队列(Queue):

    1. 队列是允许一端进行插入元素和另外一端进行删除操作,队列遵循“先进先出”的原则。类似于大家排队做核酸,先来的人就先做。Queue是一个接口,底层是通过链表实现的;在实例化时必须实例化LinkedList的对象,因为LinkedList实现了Queue接口。
    2. 队列的使用方法
      方法作用
      offer(x);将元素x尾插放入队列
      poll();将队头元素移出队列,返回改元素
      peek();获取队头元素
      size();获取队列中有效元素的个数
      isEmpty();检测队列是否为空,空返回 true
    3. 双端队列(Deque):元素可以从队头入队和出队,也可以从队尾出队和入队。

    5.队列的模拟实现:

    底层是由单链表实现的采用链式存储,加上了一个尾节点,这样尾插法入队还是头节点出队时间复杂度都为O(1)

    1. public class MyQueue {
    2. static class ListNode{
    3. public int val;
    4. public ListNode next;
    5. public ListNode(int val) {
    6. this.val = val;
    7. }
    8. }
    9. public ListNode head;
    10. public ListNode last;//队列的尾巴节点
    11. //入队
    12. public void offer(int data){
    13. ListNode node = new ListNode(data);
    14. if(head == null){
    15. head = node;
    16. last = node;
    17. }else{
    18. last.next = node;
    19. last = last.next;
    20. }
    21. }
    22. //出队
    23. public int poll(){
    24. if(head == null){
    25. return -1;
    26. }
    27. int oldvalue = head.val;
    28. if(head.next == null){
    29. head = null;
    30. last = null;
    31. }else{
    32. head = head.next;
    33. }
    34. return oldvalue;
    35. }
    36. //peek()查看当前队头元素是谁
    37. public int peek(){
    38. if(head == null){
    39. return -1;
    40. }
    41. return head.val;
    42. }
    43. //检查队列是否为空
    44. public boolean isEmpty(){
    45. return head == null;
    46. }
    47. //获取队列中有效元素的个数
    48. public int size(){
    49. if(head == null) return 0;
    50. int count = 0;
    51. ListNode cur = head;
    52. while(cur != null){
    53. count++;
    54. cur = cur.next;
    55. }
    56. return count;
    57. }
    58. }

    6.队列的OJ题:

    1.用队列实现栈(用到俩个队列,俩个队列之间元素的相互调整来实现栈的基本功能)。

    1. public class MyStack {
    2. //用队列来实现栈
    3. Queue qu1;
    4. Queue qu2;
    5. public int usedSize;
    6. public MyStack(){
    7. qu1 = new LinkedList<>();
    8. qu2 = new LinkedList<>();
    9. }
    10. //入栈
    11. public void push(int data){
    12. if(!qu1.isEmpty()){
    13. qu1.offer(data);
    14. } else if (! qu2.isEmpty()) {
    15. qu2.offer(data);
    16. }else{
    17. qu1.offer(data);
    18. }
    19. usedSize++;
    20. }
    21. //出栈
    22. public int poll(){
    23. if (empty()) {
    24. return -1;
    25. }
    26. if(! qu1.isEmpty()){
    27. //size()会发生变化,用cursize记录下来就好
    28. int cursize = qu1.size();
    29. for (int i = 0; i < cursize-1; i++) {
    30. int ret = qu1.poll();
    31. qu2.offer(ret);
    32. }
    33. usedSize--;
    34. return qu1.poll();
    35. }else{
    36. int cursize = qu2.size();
    37. for (int i = 0; i < cursize-1; i++) {
    38. int ret = qu2.poll();
    39. qu1.offer(ret);
    40. }
    41. usedSize--;
    42. return qu2.poll();
    43. }
    44. }
    45. //如果为空返回true
    46. private boolean empty(){
    47. return usedSize==0;
    48. }
    49. //获取栈顶元素
    50. public int peek(){
    51. if (empty()) {
    52. return -1;
    53. }
    54. if(! qu1.isEmpty()){
    55. int cursize = qu1.size();
    56. int ret = -1;
    57. for (int i = 0; i < cursize; i++) {
    58. ret = qu1.poll();
    59. qu2.offer(ret);
    60. }
    61. return ret;
    62. }else{
    63. int cursize = qu2.size();
    64. int ret = -1;
    65. for (int i = 0; i < cursize; i++) {
    66. ret = qu2.poll();
    67. qu1.offer(ret);
    68. }
    69. return ret;
    70. }
    71. }
    72. }

    2.用栈实现队列(用到俩个栈,将元素从一个栈转到另外一个栈从而完成队列的基本功能)。

    1. //用栈来模拟实现队列
    2. public class MyQueue {
    3. Stack s1;
    4. Stack s2;
    5. public MyQueue(){
    6. s1 = new Stack<>();
    7. s2 = new Stack<>();
    8. }
    9. //入队
    10. public void offer(int data){
    11. s1.push(data);
    12. }
    13. //出栈
    14. public int pop(){
    15. if(isEmpty()){
    16. return -1;
    17. }
    18. if(s2.empty()){
    19. while(!s1.empty()){
    20. s2.push(s1.pop());
    21. }
    22. }
    23. return s2.pop();
    24. }
    25. //查看队头元素
    26. public int peek(){
    27. if(isEmpty()){
    28. return -1;
    29. }
    30. if(s2.empty()){
    31. while(!s1.empty()){
    32. s2.push(s1.pop());
    33. }
    34. }
    35. return s2.peek();
    36. }
    37. //检查元素是否为空,空返回
    38. public boolean isEmpty(){
    39. return s1.empty() && s2.empty();
    40. }
    41. }

    3.实现一个最小栈(用到俩个栈,一个存放push进来的元素,一个存放最小的元素)。

    1. public class MinStack {
    2. Stack s;
    3. Stack minStack;
    4. public MinStack(){
    5. s = new Stack<>();
    6. minStack = new Stack<>();
    7. }
    8. //入栈
    9. public void push(int data){
    10. s.push(data);
    11. if(minStack.empty()){
    12. minStack.push(data);
    13. }else{
    14. if(minStack.peek() >= data){
    15. minStack.push(data);
    16. }
    17. }
    18. }
    19. //出栈
    20. public void pop(){
    21. if(!s.empty()) {
    22. int popV = s.pop();
    23. int minV = minStack.peek();
    24. if (popV == minV) {
    25. minStack.pop();
    26. }
    27. }
    28. }
    29. //获取栈顶元素,不是删除
    30. public int peek(){
    31. if(!s.empty()){
    32. return s.peek();
    33. }
    34. return -1;
    35. }
    36. //获取栈顶最小元素
    37. public int peekmin(){
    38. if(!minStack.empty()){
    39. return minStack.peek();
    40. }
    41. return -1;
    42. }
    43. }

    如果对您有帮助的话,

    不要忘记点赞+关注哦,蟹蟹

    如果对您有帮助的话,

    不要忘记点赞+关注哦,蟹蟹

    如果对您有帮助的话,

    不要忘记点赞+关注哦,蟹蟹

  • 相关阅读:
    23种设计模式之创建型模式篇
    【学习记录】autoware标定相机与激光雷达外参
    2022/7/27 考试总结
    集成crawlergo和xray的src漏洞挖掘利器(hscan)
    Linux下的多线程编程:原理、工具及应用(2)
    二十、一起学习Lua 面向对象
    java 上机练习题
    GDB符号表概念及Linux获取符号表的方式
    维视智造x西安电子科技大学,联合授课助力AI产业人才培养
    环状分组柱状图 Python
  • 原文地址:https://blog.csdn.net/qq_68993495/article/details/127033640