• 数据结构-栈与队列


    1. 相比于数组这种存储数据的数据,栈(Stock)和队列(Queue)主要作用是在程序中作为构思算法的辅助工具,是一种程序员开发过程中的便利工具。Stock和Queue具有访问受限以及更加抽象的特征。

    一、栈

    栈只允许访问最后一个插入的元素,即栈是先进后出(FILO)的一种数据结构。栈主要提供的算法包括push,pop和peek。其中push是插入一个元素,pop是弹出最近添加的一个元素,peek是返回最近添加的一个元素。

    栈的底层实现可以是数组,也可以是链表,这里采用数组实现一个栈,代码如下:

     1 public class Stock1<T> {
     2     private static final int EMPTY_TOP = -1;
     3     private int maxSize;
     4     private Object[] stockArray;
     5     private int top;
     6 
     7     public Stock1() {
     8         this(16);
     9     }
    10 
    11     public Stock1(int initialCapacity) {
    12         if (initialCapacity < 0) {
    13             throw new IllegalArgumentException("The initialCapacity value must > 0, this value is:" + initialCapacity);
    14         }
    15 
    16         this.maxSize = initialCapacity;
    17         this.top = EMPTY_TOP;
    18         this.stockArray = new Object[this.maxSize];
    19     }
    20 
    21     public void push(T value) {
    22         this.checkIndex(this.top + 1);
    23         this.stockArray[++this.top] = value;
    24     }
    25 
    26     @SuppressWarnings("unchecked")
    27     public T pop() {
    28         this.checkIndex(this.top);
    29         return ((T) this.stockArray[this.top--]);
    30     }
    31 
    32     @SuppressWarnings("unchecked")
    33     public T peek() {
    34         this.checkIndex(this.top);
    35         return (T) this.stockArray[this.top];
    36     }
    37 
    38     public boolean isEmpty() {
    39         return this.top == EMPTY_TOP;
    40     }
    41 
    42     public boolean isFull() {
    43         return this.top == this.maxSize - 1;
    44     }
    45 
    46     public int size() {
    47         return this.top + 1;
    48     }
    49 
    50     private void checkIndex(int index) {
    51         if (index < 0 || index >= maxSize) {
    52             throw new IllegalArgumentException("The index is error, index:=" + index + ", the max index is:" + (maxSize - 1));
    53         }
    54     }
    55 
    56     @Override
    57     public String toString() {
    58         StringBuffer sb = new StringBuffer(this.maxSize);
    59         for (int i = this.top; i >= 0; i--) {
    60             sb.append(this.stockArray[i]).append(",");
    61         }
    62         return "[" + sb.substring(0, Math.max(sb.length() - 1, 0)) + "]";
    63     }
    64 }
    View Code

    二、队列

    队列和栈一样,也只允许访问一个元素,但是这个元素是最早插入的,即队列是一个先进先出(FIFO)的数据结构。队列主要提供的算法包括insert,remove和peek。其中insert是在队列的尾部插入一个元素;remove是在队列的头部删除一个元素,并返回;peek是返回队列头部的元素的值。

    队列的底层实现和栈一样,可以是数组或者是链表,代码如下:

     1 public class Queue1<T extends Comparable<T>> {
     2     private static int EMPTY_INDEX = 0;
     3     protected final int maxSize;
     4     protected final Comparable<T>[] queueArray;
     5     protected int head;
     6     protected int tail;
     7     protected int size;
     8 
     9     @SuppressWarnings("unchecked")
    10     public Queue1(int initialCapacity) {
    11         if (initialCapacity < 0) {
    12             throw new IllegalArgumentException("The initialCapacity value must > 0, this value is:" + initialCapacity);
    13         }
    14 
    15         this.maxSize = initialCapacity;
    16         this.queueArray = (Comparable<T>[]) Array.newInstance(Comparable.class, this.maxSize);
    17         this.head = EMPTY_INDEX;
    18         this.tail = EMPTY_INDEX;
    19         this.size = 0;
    20     }
    21 
    22     public void push(T value) {
    23         if (isFull()) {
    24             throw new IllegalArgumentException("The queue is full, can't push value to this queue.");
    25         } else {
    26             this.size++;
    27             this.queueArray[(this.tail++) % this.maxSize] = value;
    28         }
    29     }
    30 
    31     @SuppressWarnings("unchecked")
    32     public T pop() {
    33         if (isEmpty()) {
    34             throw new IllegalArgumentException("The queue is empty, can't pop value.");
    35         } else {
    36             this.size--;
    37             return (T) this.queueArray[(this.head++) % this.maxSize];
    38         }
    39     }
    40 
    41     @SuppressWarnings("unchecked")
    42     public T peek() {
    43         if (isEmpty()) {
    44             throw new IllegalArgumentException("The queue is empty, can't peek value.");
    45         } else {
    46             return (T) this.queueArray[this.head % this.maxSize];
    47         }
    48     }
    49 
    50     public boolean isEmpty() {
    51         return this.size == 0;
    52     }
    53 
    54     public boolean isFull() {
    55         return this.size == this.maxSize;
    56     }
    57 
    58     public int size() {
    59         return this.size;
    60     }
    61 }
    View Code

    这段代码中我将insert方法换成了push方法,remove方法换成了pop方法。

    三、优先级队列

    优先级队列和普通队列类似,区别在于在remove元素的时候,返回的元素值是按照某种顺序来定义的。实现优先级队列有两种方式:

    第一种,在插入元素的时候,按顺排列。即每次插入的时候,都会将要插入的元素插入到对应位置,并移动其他元素。此时插入的时间复杂度是O(n2),但是这样删除的代码和普通队列一样。

    第二中,在插入元素的时候,直接将元素填充到队列尾部,但是在删除的时候,search全部数据,选择出要删除的数据出来。此时插入时间复杂度O(1),删除复杂度为O(n2)。

    我们采用第一种方式来实现一个队列,针对插入数据慢的问题,我们可以采用堆来解决这个问题,以后再说。代码如下:

    第一种代码是继承普通队列,只修改push方法:

     1 public class PriorityQueue1<T extends Comparable<T>> extends Queue1<T> {
     2     public PriorityQueue1(int initialCapacity) {
     3         super(initialCapacity);
     4     }
     5 
     6     public void push(T value) {
     7         if (isFull()) {
     8             throw new IllegalArgumentException("This queue is full");
     9         } else {
    10             int index = super.head;
    11             for (int i = 0; i < super.size; i++) {
    12                 int compareResult = super.queueArray[index++ % super.maxSize].compareTo(value);
    13                 if (compareResult >= 0) {
    14                     index--;
    15                     break;
    16                 }
    17             }
    18 
    19             for (int i = super.tail; i > index; i--) {
    20                 super.queueArray[i % super.maxSize] = super.queueArray[(i - 1) % super.maxSize];
    21             }
    22 
    23             super.queueArray[index] = value;
    24             super.tail++;
    25             super.size++;
    26         }
    27     }
    28 }
    View Code

    第二种是不继承普通队列,自己实现:

     1 public class PriorityQueue2<T extends Comparable<T>> {
     2     protected final int maxSize;
     3     protected int nItems;
     4     protected Comparable<T>[] basicArray;
     5 
     6     @SuppressWarnings("unchecked")
     7     public PriorityQueue2(int initialCapacity) {
     8         if (initialCapacity < 0) {
     9             throw new IllegalArgumentException("The initialCapacity value must > 0, this value is:" + initialCapacity);
    10         }
    11 
    12         this.maxSize = initialCapacity;
    13         this.basicArray = (Comparable<T>[]) Array.newInstance(Comparable.class, this.maxSize);
    14         this.nItems = 0;
    15     }
    16 
    17     public boolean isEmpty() {
    18         return this.nItems == 0;
    19     }
    20 
    21     public boolean isFull() {
    22         return this.nItems == this.maxSize;
    23     }
    24 
    25     public int size() {
    26         return this.nItems;
    27     }
    28 
    29     public void push(T value) {
    30         if (this.isFull()) {
    31             throw new IllegalArgumentException("This queue is full, can't push value.");
    32         } else {
    33             int index = 0;
    34             for (; index < this.nItems; index++) {
    35                 if (this.basicArray[index].compareTo(value) <= 0) {
    36                     break;
    37                 }
    38             }
    39 
    40             for (int j = this.nItems; j > index; j--) {
    41                 this.basicArray[j] = this.basicArray[j - 1];
    42             }
    43 
    44             this.basicArray[index] = value;
    45             this.nItems++;
    46         }
    47     }
    48 
    49     @SuppressWarnings("unchecked")
    50     public T pop() {
    51         if (this.isEmpty()) {
    52             throw new IllegalArgumentException("This queue is empty, can't pop value.");
    53         } else {
    54             return (T) this.basicArray[--nItems];
    55         }
    56     }
    57 
    58     @SuppressWarnings("unchecked")
    59     public T peek() {
    60         if (this.isEmpty()) {
    61             throw new IllegalArgumentException("This queue is empty, can't peek value.");
    62         } else {
    63             return (T) this.basicArray[this.nItems - 1];
    64         }
    65     }
    66 }
    View Code

    四、其他代码

    1.解析表达式,将中缀表达式转换成后缀表达式

      1 public class InToPost {
      2     private Stock1<Character> stock;
      3     private Queue1<String> queue;
      4     private String input;
      5     private StringBuffer sb;
      6 
      7     public InToPost(String input) {
      8         if (input != null && input.length() != 0) {
      9             this.input = input.trim();
     10         } else {
     11             this.input = "";
     12         }
     13 
     14         this.stock = new Stock1<>(this.input.length());
     15         this.sb = new StringBuffer(this.input.length());
     16         this.queue = new Queue1<>(this.input.length());
     17     }
     18 
     19     public String getInput() {
     20         return input;
     21     }
     22 
     23     public String getOutput() {
     24         return this.sb.toString();
     25     }
     26 
     27     public String doTranshi() {
     28         StringBuffer tmp = new StringBuffer();
     29 
     30         for (int j = 0; j < this.input.length(); j++) {
     31             char ch = this.input.charAt(j);
     32             switch (ch) {
     33             case '+':
     34             case '-':
     35                 pushValueToQueue(tmp.toString());
     36                 sb.append(tmp.toString());
     37                 tmp = new StringBuffer();
     38                 gotPot(ch, 1);
     39                 break;
     40 
     41             case '*':
     42             case '/':
     43                 pushValueToQueue(tmp.toString());
     44                 sb.append(tmp.toString());
     45                 tmp = new StringBuffer();
     46                 gotPot(ch, 2);
     47                 break;
     48 
     49             case '(':
     50                 this.stock.push(ch);
     51                 break;
     52 
     53             case ')':
     54                 pushValueToQueue(tmp.toString());
     55                 sb.append(tmp.toString());
     56                 tmp = new StringBuffer();
     57                 while (!this.stock.isEmpty()) {
     58                     char chx = this.stock.pop();
     59                     if (chx == '(') {
     60                         break;
     61                     } else {
     62                         sb.append(chx);
     63                         pushValueToQueue(String.valueOf(chx));
     64                     }
     65                 }
     66                 break;
     67 
     68             default:
     69                 tmp.append(ch);
     70                 break;
     71             }
     72         }
     73 
     74         pushValueToQueue(tmp.toString());
     75         sb.append(tmp.toString());
     76 
     77         while (!this.stock.isEmpty()) {
     78             char ch = this.stock.pop();
     79             this.sb.append(ch);
     80             pushValueToQueue(String.valueOf(ch));
     81         }
     82 
     83         return this.getOutput();
     84     }
     85 
     86     private void gotPot(char ch, int prec) {
     87         while (!this.stock.isEmpty()) {
     88             char chx = this.stock.pop();
     89             if (chx == '(') {
     90                 this.stock.push(chx);
     91                 break;
     92             } else {
     93                 int prec2 = 2;
     94                 if (chx == '+' || chx == '-') {
     95                     prec2 = 1;
     96                 }
     97                 if (prec2 >= prec) {
     98                     sb.append(chx);
     99                     pushValueToQueue(String.valueOf(chx));
    100                 } else {
    101                     this.stock.push(chx);
    102                     break;
    103                 }
    104             }
    105         }
    106         this.stock.push(ch);
    107     }
    108 
    109     private void pushValueToQueue(String value) {
    110         if (value == null || value.trim().length() == 0) {
    111             return;
    112         }
    113         this.queue.push(value.trim());
    114     }
    115 
    116     public Queue1<String> getQueue() {
    117         return this.queue;
    118     }
    119 }
    120 
    121 class InToPostUtil {
    122     public static String doTranshi(String line) {
    123         return new InToPost(line).doTranshi();
    124     }
    125 }
    126 
    127 class InToPostApp {
    128     public static void main(String[] args) {
    129         System.out.println(InToPostUtil.doTranshi(null));
    130         System.out.println(InToPostUtil.doTranshi(""));
    131         System.out.println(InToPostUtil.doTranshi("     "));
    132         System.out.println(InToPostUtil.doTranshi("a*b+c"));
    133         System.out.println(InToPostUtil.doTranshi("a*(b+c)"));
    134         System.out.println(InToPostUtil.doTranshi("a*(b+c*d)"));
    135         System.out.println(InToPostUtil.doTranshi("a*(b+c*d/(e-f*g))"));
    136     }
    137 }
    View Code

    2.计算后缀表达式的值

     1 package com.augmentum.gby.ds;
     2 
     3 public class ParsePost {
     4     private String line;
     5     private InToPost inToPost;
     6 
     7     public ParsePost(String line) {
     8         this.line = line;
     9         this.inToPost = new InToPost(this.line);
    10     }
    11 
    12     public double doParse() {
    13         String reline = this.inToPost.doTranshi();
    14         if (reline == null || reline.length() == 0) {
    15             throw new IllegalArgumentException("The input line value is empty. can't calc those value.");
    16         } else {
    17             Stock1<Double> stock = new Stock1<>(reline.length());
    18             Queue1<String> queue = this.inToPost.getQueue();
    19             while (!queue.isEmpty()) {
    20                 String value = queue.pop();
    21                 if ("+".equals(value) || "-".equals(value) || "*".equals(value) || "/".equals(value)) {
    22                     double num1 = stock.pop();
    23                     double num2 = stock.pop();
    24                     switch (value.charAt(0)) {
    25                     case '+':
    26                         stock.push(num1 + num2);
    27                         break;
    28                     case '-':
    29                         stock.push(num2 - num1);
    30                         break;
    31                     case '*':
    32                         stock.push(num2 * num1);
    33                         break;
    34                     case '/':
    35                         stock.push(num2 / num1);
    36                         break;
    37                     }
    38                 } else {
    39                     stock.push(Double.valueOf(value));
    40                 }
    41             }
    42             return stock.pop();
    43         }
    44     }
    45 }
    46 
    47 class ParsePostUtil {
    48     public static double doParse(String line) {
    49         return new ParsePost(line).doParse();
    50     }
    51 }
    52 
    53 class ParsePostApp {
    54     public static void main(String[] args) {
    55         System.out.println(InToPostUtil.doTranshi("2*((3+4)*5+5)"));
    56         System.out.println(InToPostUtil.doTranshi("2*3+4") + "; The result is:" + ParsePostUtil.doParse("2*3+4"));
    57         System.out.println(InToPostUtil.doTranshi("2*(3+4)") + "; The result is:" + ParsePostUtil.doParse("2*(3+4)"));
    58         System.out.println(InToPostUtil.doTranshi("2*(3+4*5)") + "; The result is:" + ParsePostUtil.doParse("2*(3+4*5)"));
    59         System.out.println(InToPostUtil.doTranshi("2*3+4*5") + "; The result is:" + ParsePostUtil.doParse("2*3+4*5"));
    60         System.out.println(InToPostUtil.doTranshi("2*((3+4)*5+5)") + "; The result is:" + ParsePostUtil.doParse("2*((3+4)*5+5)"));
    61         System.out.println(InToPostUtil.doTranshi("2*((3+4)*5+9)") + "; The result is:" + ParsePostUtil.doParse("2*((3+4)*5+9)"));
    62         System.out.println(InToPostUtil.doTranshi("20*3+4") + "; The result is:" + ParsePostUtil.doParse("20*3+4"));
    63         System.out.println(InToPostUtil.doTranshi("20.5*4+4") + "; The result is:" + ParsePostUtil.doParse("20.5*4+4"));
    64     }
    65 }
    View Code
  • 相关阅读:
    第一次迭代心得
    RDF搜索引擎——需求分析心得
    RDF搜索引擎——数据库设计心得
    RDF搜索引擎——数据库具体设计
    服务器上修改运行scala
    结对编程项目的收获与总结(支持UI背景与背景音乐的刷题器)
    取长补短——结对编程项目之队友代码分析
    团队项目——测试心得
    第一次迭代开发心得
    团队项目——需求心得
  • 原文地址:https://www.cnblogs.com/liuming1992/p/4205303.html
Copyright © 2020-2023  润新知