栈和队列
栈和队列不适合作为数据的记录工具,它们更多地是作为程序员的工具来运用。主要作为构思算法的辅助工具,而不是完全的数据存储工具。这些数据结构的生命周期比数组、链表等数据库类型的结构要短的多。在程序操作执行期间他们才被创建,通常用它们去执行某项特殊的任务;当完成任务后,它们就被销毁。
下面的StackX类,实现一个栈的功能:
package com.js.ai.modules.pointwall.testxfz; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; /** * * @ClassName: StackX * @Description: 堆栈类 * @author: xfzhong * @date: 2017年5月24日 */ class StackX{ private int maxSize; private char[] stackArray; private int top; /** * * @Title:StackX * @Description:StackX是构造方法,根据参数规定的容量创建一个新栈。 * 栈的域包括表示最大容量的变量、数组本身以及变量top,它存储栈顶元素的下标。 * @param max */ public StackX(int max) { maxSize=max; stackArray=new char[maxSize]; top=-1; } /** * * @Title: push * @Description: Push(入栈)方法中将top值增加一, * 使它指向原顶端数据项的上面的一个位置, * 并在在这个位置上存储一个数据项, * 再次提醒,top是在插入数据项之前递增的。 * 入栈,注意要先将top指针上移,然后将数据赋值给新的top位置 * @param j * @return: void */ public void push(char j){ stackArray[++top]=j; } /** * * @Title: pop * @Description: Pop方法返回top标识的数据项值,然后top减一。 * 这个方法有效地从栈中移除了数据项;虽然数据项仍然存在数组中, * 直到有新的数据项压入栈中覆盖这个数据项。但是它不能再被访问了。 * 出栈,先取得数据,然后将top下移 * @return * @return: char */ public char pop(){ return stackArray[top--]; } /** * * @Title: peek * @Description: Peek方法仅返回top所指的数据项的值,不对栈做任何改动。 只查看栈顶的元素,top指针不动。 * @return * @return: char */ public char peek(){ return stackArray[top]; } /** * * @Title: isEmpty * @Description: IsEmpty方法在栈空时返回true,栈空时top值为-1。 * @return * @return: boolean */ public boolean isEmpty(){ return (top==-1); } } /** * * @ClassName: BracketChecker * @Description: 分隔符匹配(检查) * 一种典型的应用是栈用于解析某种类型的文本串。通常,文本串是计算机语言写的代码行, * 而解析它们的程序就是编译器。一个典型的例子是分隔符匹配程序,它从字符串中不断读取字符, * 每次读取一个字符。若发现它是一个左分隔符,将它压入栈中。当从输入中读到一个右分隔符时, * 弹出栈顶的左分隔符,并且查看它是否合右分隔符相匹配。如果它们不匹配,则程序报错。 * 如果栈中没有左分隔符和右分隔符匹配,或者一直存在着没有被匹配的分隔符,程序也报错。 * 这个方法的可行性在于,最后出现的左边分隔符需要最先匹配,这个规律符合栈的后进先出的特点。 下面是分隔符匹配程序的代码: * @author: xfzhong * @date: 2017年5月24日 */ class BracketChecker{ private String input; public BracketChecker(String in) { input=in; } public void check(){ int stackSize=input.length(); StackX theStack=new StackX(stackSize); for(int j=0;j<input.length();j++){ char ch=input.charAt(j); switch (ch) { case '{': case '[': case '(': theStack.push(ch); break; case '}': case ']': case ')': if(!theStack.isEmpty()){ char chx=theStack.pop(); if((ch=='}' && chx!='{')||(ch==']' && chx!='[')||(ch==')' && chx!='(')){ System.out.println("error:"+ch+"at"+j); } } else { System.out.println("error:"+ch+"at"+j); } break; default: break; } } if(!theStack.isEmpty()) System.out.println("error:missing right delimiter!"); } } /** * * @ClassName: BracketsApp * @Description: 括号类BracketsApp * @author: xfzhong * @date: 2017年5月24日 */ class BracketsApp{ public static String getString() throws IOException{ InputStreamReader isr=new InputStreamReader(System.in); BufferedReader br=new BufferedReader(isr); String s=br.readLine(); return s; } public static void main(String[] args) throws IOException { String input; while(true){ System.out.println("error:string containing delimiter!"); System.out.flush(); input=getString(); if(input.equals("")) break; BracketChecker theChecker=new BracketChecker(input); theChecker.check(); } } } /** * * @ClassName: Queue * @Description: 队列实现代码 * @author: xfzhong * @date: 2017年5月24日 */ class Queue{ private int maxSize; private long[] queArray; private int front; private int rear; private int nItems; public Queue(int s) { maxSize=s; queArray=new long[maxSize]; front=0; rear=-1; nItems=0; } /** * * @Title: insert * @Description: insert()方法:运行的前提条件是队列未满, * 若插入已满队列时,会抛出异常。若可以插入,则是将rear(队尾指针)加一后, * 在队尾指针所指的位置处插入新的数据项。但是当rear指针指向数组的顶端, * 即maxSize-1位置的时候,在插入数据之前,它必须回绕到数组的底端。 * 回绕操作把rear设置为-1, * 因此当rear加1后,它等于0,是数组底端的下标值。最后年Items加1。 * @param j * @throws Exception * @return: void */ public void insert(long j) throws Exception{ if(this.isFull()) throw new Exception("can not insert because queue is full!"); if(rear==maxSize)//deal with wraparound rear=-1; queArray[++rear]=j;//increment rear and insert增量后插 nItems++;//one more item } /** * * @Title: remove * @Description: remove()方法:前提是队列不空,若对空队列执行此操作时, * 会抛出异常提示。若不空,由front指针得到队头数据项的值, * 然后将front加1。但是如果这样做是front的值超过数组的顶端, * front就必须绕回到数组下标为0的位置上。 * 作这个检验之前,先将返回值临时村到,最后年Items减1。 * @return * @throws Exception * @return: long */ public long remove() throws Exception{ if(this.isEmpty()) throw new Exception("can not remove because queue is empty!"); long temp=queArray[front++]; if(front==maxSize) front=0; nItems--; return temp; } public boolean isFull(){ return (nItems==maxSize); } public boolean isEmpty(){ return (nItems==0); } public int size(){ return nItems; } /** * * @Title: peekFront * @Description: peek()方法:返回front指针所指数据项的值。isFull()、 * isEmpty()、size()都依赖于nItems字段。 * @return * @return: long */ public long peekFront(){ return queArray[front]; } public static void main(String[] args) { Queue theQueue=new Queue(5); try { theQueue.insert(10); theQueue.insert(20); theQueue.insert(30); theQueue.insert(40); } catch (Exception e) { e.printStackTrace(); } try { theQueue.remove(); theQueue.remove(); theQueue.remove(); } catch (Exception e) { e.printStackTrace(); } try { theQueue.insert(50); theQueue.insert(60); theQueue.insert(70); theQueue.insert(80); } catch (Exception e) { e.printStackTrace(); } while(!theQueue.isEmpty()){ long n=0; try { n=theQueue.remove(); } catch (Exception e) { e.printStackTrace(); } System.out.println("n="+n); System.out.println(" "); } System.out.println(""); } } public class TestClass { }
优先级队列是比栈和队列更专用的数据结构。它也有队头和队尾指针,也是从队头移除数据项。不过在优先级队列中,数据项按关键字的值有序,这样关键字最小的数据项总是在队头。数据插入的时候会按照顺序插入到合适的位置以确保队列的有序性。下面给出一种使用简单的数组实现优先级队列。这种实现方法插入比较慢,但是它比较简单,适用于数据量比较小,并且不是很注重插入速度的情况。代码如下: