《Java数据结构和算法》学习笔记(3)——栈和队列

来源:互联网 发布:js数组怎么删除元素 编辑:程序博客网 时间:2024/05/21 22:55

每篇笔记都会附上随书的Applet演示程序,有算法看不明白的,可以下载Applet运行起来(直接打开html文件即可),可以很容易地看清楚算法的每一步。


是一种先进后出(FILO)的线性数据结构,先进后出的意思就是……举个例子吧,我先把1放进一个栈里,再把2放进去,最后把3放进去,取出来的时候只能先得到3,再取能得到2,最后是1。栈一次只允许访问一个数据项(最顶端的那个),常用操作有入栈(push,把数据压入栈里)和出栈(pop,把顶端的数据从栈里弹出),peek用于查看栈顶数据。
下面是一个简单的栈的实现

Java代码
  1. package dsaa.array;  
  2.   
  3. import java.util.EmptyStackException;  
  4.   
  5. /** 
  6.  * @(#)Stack.java 2008-12-26 下午03:41:57 
  7.  *  
  8.  * @author Qiu Maoyuan 
  9.  * Stack 
  10.  */  
  11. public class Stack<E> {  
  12.   
  13.     private Object[] stackArray;  
  14.     private int topIndex = -1;  
  15.     private int size = 0;  
  16.       
  17.     public Stack(){  
  18.         stackArray = new Object[10];  
  19.     }  
  20.       
  21.     public Stack(int size){  
  22.         stackArray = new Object[size];  
  23.     }  
  24.       
  25.     public void push(E value){  
  26.         ensureCapacity();  
  27.         stackArray[++topIndex] = value;  
  28.         size++;  
  29.     }  
  30.       
  31.     @SuppressWarnings("unchecked")  
  32.     public E peek(){  
  33.         if(topIndex==-1)  
  34.             throw new EmptyStackException();  
  35.         return (E)stackArray[topIndex];  
  36.     }  
  37.       
  38.     public E pop(){  
  39.         E value = peek();  
  40.         topIndex--;  
  41.         size--;  
  42.         return value;  
  43.     }  
  44.       
  45.     public boolean isEmpty(){  
  46.         return size==0;  
  47.     }  
  48.       
  49.     private void ensureCapacity() {  
  50.         if(size==stackArray.length){  
  51.             Object[] newArray = new Object[size * 3 / 2 + 1];  
  52.             System.arraycopy(stackArray, 0, newArray, 0, size);  
  53.             stackArray = newArray;  
  54.         }  
  55.     }  
  56. }  


在给一个数组或者字符串进行反向排序的时候,栈是一个不错的工具:

Java代码
  1. Stack<Character> stack = new Stack<Character>();  
  2. String input = "hello stack!";  
  3. for(int i=0; i<input.length(); i++)  
  4.     stack.push(input.charAt(i));  
  5.   
  6. StringBuilder buffer = new StringBuilder();  
  7. while(!stack.isEmpty()){  
  8.     buffer.append(stack.pop().charValue());  
  9. }  
  10. String output = buffer.toString();  
  11. System.out.println(output);  


利用栈还可以实现回文判断、词法分析等功能。
显而易见,栈的push和pop操作的时间复杂度为O(1)。

队列


队列是一种先进先出(FIFO)的线性数据结构,常用操作有插入(insert)和删除(remove)。
一个简单的队列实现如下:

Java代码
  1. package dsaa.array;  
  2. /** 
  3.  * @(#)Queue.java 2008-12-27 上午01:21:46 
  4.  *  
  5.  * @author Qiu Maoyuan 
  6.  * Queue 
  7.  */  
  8. public class Queue<E> {  
  9.   
  10.     private Object[] queueArray;  
  11.     private int head = 0;  
  12.     private int tail = -1;  
  13.       
  14.     public Queue(int size){  
  15.         queueArray = new Object[size];  
  16.     }  
  17.   
  18.     @SuppressWarnings("unchecked")  
  19.     public E peek(){  
  20.         if(isEmpty())  
  21.             throw new IllegalStateException("Queue is empty");  
  22.         return (E)queueArray[head];  
  23.     }  
  24.       
  25.     public void insert(E value){  
  26.         if(isFull())  
  27.             throw new IllegalStateException("Queue is full");  
  28.         queueArray[++tail] = value;  
  29.     }  
  30.       
  31.     public E remove(){  
  32.         E value = peek();  
  33.         head++;  
  34.         return value;  
  35.     }  
  36.       
  37.     public boolean isEmpty(){  
  38.         return tail - head == -1;  
  39.     }  
  40.       
  41.     public boolean isFull(){  
  42.         return tail == queueArray.length-1;  
  43.     }  
  44. }  


以上队列存在一个问题,队列满了以后,无论删除掉多少个数据项,甚至清空这个队列,仍然不能插入新的数据。其实有一种解决方法就是,在删除数据项的时候,后面的所有数据项都往前移动,但这样效率很低。
为了避免队列不满却不能插入新数据项的问题,可以让队头队尾指针绕回到数组开始的位置,这样的队列叫循环队列
改进后的代码如下:

Java代码
  1. package dsaa.array;  
  2. /** 
  3.  * @(#)Queue.java 2008-12-27 上午01:21:46 
  4.  *  
  5.  * @author Qiu Maoyuan 
  6.  * Queue 
  7.  */  
  8. public class Queue<E> {  
  9.   
  10.     private Object[] queueArray;  
  11.     private int head = 0;  
  12.     private int tail = -1;  
  13.     private int elementsCount = 0;  
  14.       
  15.     public Queue(int size){  
  16.         queueArray = new Object[size];  
  17.     }  
  18.   
  19.     @SuppressWarnings("unchecked")  
  20.     public E peek(){  
  21.         if(isEmpty())  
  22.             throw new IllegalStateException("Queue is empty");  
  23.         return (E)queueArray[head];  
  24.     }  
  25.       
  26.     public void insert(E value){  
  27.         if(isFull())  
  28.             throw new IllegalStateException("Queue is full");  
  29.         if(tail == queueArray.length - 1){  
  30.             tail = 0;  
  31.             queueArray[tail] = value;  
  32.         }else{  
  33.             queueArray[++tail] = value;  
  34.         }  
  35.         elementsCount++;  
  36.     }  
  37.       
  38.     public E remove(){  
  39.         E value = peek();  
  40.         if(head == queueArray.length - 1){  
  41.             head = 0;  
  42.         }else{  
  43.             head++;  
  44.         }  
  45.         elementsCount--;  
  46.         return value;  
  47.     }  
  48.       
  49.     public boolean isEmpty(){  
  50.         return elementsCount == 0;  
  51.     }  
  52.       
  53.     public boolean isFull(){  
  54.         return elementsCount == queueArray.length;  
  55.     }  
  56. }  


队列的效率和栈一样,插入和删除数据项的时间复杂度均为O(1)。
还有一种队列叫做双端队列,顾名思义就是对两端都可以进行插入、删除操作的队列。如果封闭了其中一端,它就变成了一个栈;如果只允许一端插入,另一端删除,那它就成了一个普通队列。
优先级队列和普通队列的不同之处是:它在插入数据时是有序的。所以优先级队列的插入效率会比较低,时间复杂度为O(N),删除操作则为O(1)。

Java代码
  1. package dsaa.array;  
  2. /** 
  3.  * @(#)PriorityQueue.java 2008-12-27 下午01:03:01 
  4.  *  
  5.  * @author Qiu Maoyuan 
  6.  * Priority Queue 
  7.  */  
  8. public class PriorityQueue {  
  9.   
  10.     private int[] queueArray;  
  11.     private int head = -1;  
  12.       
  13.     public PriorityQueue(int initialCapacity){  
  14.         queueArray = new int[initialCapacity];  
  15.     }  
  16.       
  17.     public void insert(int value){  
  18.         if(isFull())  
  19.             throw new IllegalStateException("Queue is full");  
  20.           
  21.         if (isEmpty()){  
  22.             queueArray[++head] = value;  
  23.         } else {  
  24.             int i=head;  
  25.             while (i>-1){  
  26.                 if (queueArray[i]>value){  
  27.                     queueArray[i + 1] = queueArray[i];  
  28.                 } else {  
  29.                     break;  
  30.                 }  
  31.                 i--;  
  32.             }  
  33.             queueArray[i + 1] = value;  
  34.             head++;  
  35.         }  
  36.     }  
  37.       
  38.     public boolean isFull(){  
  39.         return head == queueArray.length - 1;  
  40.     }  
  41.       
  42.     public boolean isEmpty(){  
  43.         return head == -1;  
  44.     }  
  45.       
  46.     public int remove(){  
  47.         int value = peek();  
  48.         head--;  
  49.         return value;  
  50.     }  
  51.       
  52.     public int peek(){  
  53.         if(isEmpty())  
  54.             throw new IllegalStateException("Queue is empty");  
  55.         return queueArray[head];  
  56.     }  
  57. }
原创粉丝点击