当前位置:   article > 正文

数据结构之栈和队列_public override string tostring() { stringbuilder

public override string tostring() { stringbuilder sb = new stringbuilder();

目录

1、栈(Stack)

1.1 概念

1.2 代码实现

2. 队列(Queue)

2.1 概念

2.2 代码实现

2.3 循环队列

2.3.1 思路解析  

2.3.2 代码实现

3. 双端队列 (Deque)

3.1 概念

3.2 代码实现


1、栈(Stack)

1.1 概念

栈栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。                                                                                                                                          入栈 push:栈的插入操作叫做进栈/压栈/入栈,入栈数据在栈顶。                                                出栈 pop:栈的删除操作叫做出栈。出栈数据在栈顶

 

1.2 代码实现

1. 利用顺序表实现,即使用尾插 + 尾删的方式实现                                                                         2. 利用链表实现,则头尾皆可

相对来说,顺序表的实现上要更为简单一些,所以我们优先用顺序表实现栈。

  1. package stack_queue.stack;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import java.util.NoSuchElementException;
  5. //基于数组的顺序表实现 栈
  6. public class MyStack<E> {
  7. //当前栈的数据个数
  8. private int size;
  9. //实际存储数据的动态数组 - ArrayList
  10. private List<E> data = new ArrayList<>();
  11. /**
  12. * 将val入栈
  13. * @param val
  14. */
  15. public void push(E val){
  16. //默认尾插
  17. data.add(val);
  18. size++;
  19. }
  20. /**
  21. * 弹出栈顶元素
  22. * 返回栈顶的值
  23. * @return
  24. */
  25. public E pop(){
  26. if (isEmpty()){
  27. //栈为空
  28. throw new NoSuchElementException("stack is empty!cannot pop!");
  29. }
  30. //删除栈顶元素
  31. E val = data.remove(size - 1);
  32. size--;
  33. return val;
  34. //等同于 return data.remove(--size);
  35. }
  36. /**
  37. * 返回栈顶元素但不出栈
  38. * @return
  39. */
  40. public E peek(){
  41. if (isEmpty()){
  42. throw new NoSuchElementException("stack is empty!cannot peek");
  43. }
  44. return data.get(size-1);
  45. }
  46. /**
  47. * 判断当前栈是否为空
  48. * @return
  49. */
  50. private boolean isEmpty() {
  51. return size == 0;
  52. }
  53. @Override
  54. public String toString() {
  55. StringBuilder sb = new StringBuilder();
  56. sb.append("[");
  57. for (int i = 0; i < size; i++) {
  58. sb.append(data.get(i));
  59. if (i!=size-1){
  60. //此时还未到栈顶,还没到数组末尾
  61. sb.append(",");
  62. }
  63. }
  64. sb.append("] top");
  65. return sb.toString();
  66. }
  67. }

2. 队列(Queue)

2.1 概念

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾(Tail/Rear) 出队列:进行删除操作的一端称为队头 (Head/Front)

 

2.2 代码实现

  1. package stack_queue.queue.impl;
  2. import java.util.NoSuchElementException;
  3. /**
  4. * 基于链表实现的基础队列
  5. */
  6. public class MyQueue<E> implements Queue<E> {
  7. //链表的每个节点
  8. private class Node{
  9. E val;
  10. Node next;
  11. public Node(E val){
  12. this.val = val;
  13. }
  14. }
  15. //当前队列中的元素个数
  16. private int size;
  17. //队首
  18. private Node head;
  19. //队尾
  20. private Node tail;
  21. //入队
  22. @Override
  23. public void offer(E val) {
  24. Node node = new Node(val);
  25. if (head == null){
  26. //此时链表为空
  27. head = tail = node;
  28. }else {
  29. tail.next = node;
  30. tail = node;
  31. }
  32. size++;
  33. }
  34. //出队
  35. @Override
  36. public E poll() {
  37. if (isEmpty()){
  38. throw new NoSuchElementException("queue is empty!cannot poll!");
  39. }
  40. E val = head.val;
  41. Node node = head;
  42. head = head.next;
  43. //将原来头节点脱钩
  44. node.next = null;
  45. size--;
  46. return val;
  47. }
  48. //返回队首元素
  49. @Override
  50. public E peek() {
  51. if (isEmpty()){
  52. throw new NoSuchElementException("queue is empty!cannot peek!");
  53. }
  54. return head.val;
  55. }
  56. @Override
  57. public boolean isEmpty() {
  58. return size == 0;
  59. }
  60. @Override
  61. public String toString() {
  62. StringBuilder sb = new StringBuilder();
  63. sb.append("front [");
  64. //链表的遍历
  65. for (Node x =head; x != null;x = x.next){
  66. sb.append(x.val);
  67. if (x.next != null){
  68. //还没走到链表尾部
  69. sb.append(",");
  70. }
  71. }
  72. sb.append("]");
  73. return sb.toString();
  74. }
  75. }

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 代码实现

  1. package stack_queue.queue.impl;
  2. import java.util.Arrays;
  3. import java.util.NoSuchElementException;
  4. //基于整形的循环队列
  5. public class LoopQueue implements Queue<Integer> {
  6. private Integer[] data;
  7. //指向当前循环队列的队首元素
  8. private int head;
  9. //指向当前循环队列的队尾元素的下一个位置
  10. private int tail;
  11. //当前队列中元素个数
  12. private int size;
  13. //n为希望保存的元素个数
  14. public LoopQueue(int n){
  15. //在循环队列中浪费一个空间不能存储元素,来判断是否已满
  16. data = new Integer[n + 1];
  17. }
  18. @Override
  19. public void offer(Integer val) {
  20. if (isFull()){
  21. throw new ArrayIndexOutOfBoundsException("queue is full!cannot offer new val");
  22. }
  23. data[tail] = val;
  24. tail = (tail + 1) % data.length;
  25. size++;
  26. }
  27. @Override
  28. public Integer poll() {
  29. if (isEmpty()){
  30. throw new NoSuchElementException("queue is empty!cannot poll");
  31. }
  32. Integer val = data[head];
  33. head = (head + 1) % data.length;
  34. size--;
  35. return val;
  36. }
  37. @Override
  38. public Integer peek() {
  39. if (isEmpty()){
  40. throw new NoSuchElementException("queue is empty!cannot peek");
  41. }
  42. return data[head];
  43. }
  44. @Override
  45. public boolean isEmpty() {
  46. return tail == head;
  47. }
  48. @Override
  49. public String toString() {
  50. StringBuilder sb = new StringBuilder();
  51. sb.append("front [");
  52. //取得最后一个元素下标
  53. int lastIndex = tail == 0 ? data.length - 1 : tail - 1;
  54. for (int i = head;i != tail;){
  55. sb.append(data[i]);
  56. if (i!=lastIndex){
  57. sb.append(", ");
  58. }
  59. i = (i + 1) % data.length;
  60. }
  61. sb.append("] tail");
  62. return sb.toString();
  63. }
  64. public boolean isFull(){
  65. return (tail + 1) % data.length == head;
  66. }
  67. }

3. 双端队列 (Deque)

3.1 概念

双端队列(deque)是指允许两端都可以进行入队和出队操作的队列,deque 是 “double ended queue” 的简称。 那就说明元素可以从队头出队和入队,也可以从队尾出队和入队。

3.2 代码实现

  1. package stack_queue.queue;
  2. import java.util.ArrayDeque;
  3. import java.util.Deque;
  4. //双端队列
  5. public class DequeTest {
  6. public static void main(String[] args) {
  7. Deque<Integer> deque = new ArrayDeque<>();
  8. deque.addLast(1);
  9. deque.addLast(3);
  10. deque.addLast(5);
  11. //尾插尾删或者头插头删就是栈
  12. while (!deque.isEmpty()){
  13. System.out.println(deque.pollLast());//5 3 1
  14. }
  15. // //头插尾删或者尾插头删就是队列
  16. // while (!deque.isEmpty()){
  17. // System.out.println(deque.pollFirst());//1 3 5
  18. // }
  19. }
  20. }

本节完^_^

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/640370
推荐阅读
相关标签
  

闽ICP备14008679号