`

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

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

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

import java.util.EmptyStackException;

/**
 * @(#)Stack.java 2008-12-26 下午03:41:57
 * 
 * @author Qiu Maoyuan
 * Stack
 */
public class Stack<E> {

	private Object[] stackArray;
	private int topIndex = -1;
	private int size = 0;
	
	public Stack(){
		stackArray = new Object[10];
	}
	
	public Stack(int size){
		stackArray = new Object[size];
	}
	
	public void push(E value){
		ensureCapacity();
		stackArray[++topIndex] = value;
		size++;
	}
	
	@SuppressWarnings("unchecked")
	public E peek(){
		if(topIndex==-1)
			throw new EmptyStackException();
		return (E)stackArray[topIndex];
	}
	
	public E pop(){
		E value = peek();
		topIndex--;
		size--;
		return value;
	}
	
	public boolean isEmpty(){
		return size==0;
	}
	
	private void ensureCapacity() {
		if(size==stackArray.length){
			Object[] newArray = new Object[size * 3 / 2 + 1];
			System.arraycopy(stackArray, 0, newArray, 0, size);
			stackArray = newArray;
		}
	}
}

在给一个数组或者字符串进行反向排序的时候,栈是一个不错的工具:
		Stack<Character> stack = new Stack<Character>();
		String input = "hello stack!";
		for(int i=0; i<input.length(); i++)
			stack.push(input.charAt(i));
		
		StringBuilder buffer = new StringBuilder();
		while(!stack.isEmpty()){
			buffer.append(stack.pop().charValue());
		}
		String output = buffer.toString();
		System.out.println(output);

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

队列是一种先进先出(FIFO)的线性数据结构,常用操作有插入(insert)和删除(remove)。
一个简单的队列实现如下:
package dsaa.array;
/**
 * @(#)Queue.java 2008-12-27 上午01:21:46
 * 
 * @author Qiu Maoyuan
 * Queue
 */
public class Queue<E> {

	private Object[] queueArray;
	private int head = 0;
	private int tail = -1;
	
	public Queue(int size){
		queueArray = new Object[size];
	}

	@SuppressWarnings("unchecked")
	public E peek(){
		if(isEmpty())
			throw new IllegalStateException("Queue is empty");
		return (E)queueArray[head];
	}
	
	public void insert(E value){
		if(isFull())
			throw new IllegalStateException("Queue is full");
		queueArray[++tail] = value;
	}
	
	public E remove(){
		E value = peek();
		head++;
		return value;
	}
	
	public boolean isEmpty(){
		return tail - head == -1;
	}
	
	public boolean isFull(){
		return tail == queueArray.length-1;
	}
}

以上队列存在一个问题,队列满了以后,无论删除掉多少个数据项,甚至清空这个队列,仍然不能插入新的数据。其实有一种解决方法就是,在删除数据项的时候,后面的所有数据项都往前移动,但这样效率很低。
为了避免队列不满却不能插入新数据项的问题,可以让队头队尾指针绕回到数组开始的位置,这样的队列叫循环队列
改进后的代码如下:
package dsaa.array;
/**
 * @(#)Queue.java 2008-12-27 上午01:21:46
 * 
 * @author Qiu Maoyuan
 * Queue
 */
public class Queue<E> {

	private Object[] queueArray;
	private int head = 0;
	private int tail = -1;
	private int elementsCount = 0;
	
	public Queue(int size){
		queueArray = new Object[size];
	}

	@SuppressWarnings("unchecked")
	public E peek(){
		if(isEmpty())
			throw new IllegalStateException("Queue is empty");
		return (E)queueArray[head];
	}
	
	public void insert(E value){
		if(isFull())
			throw new IllegalStateException("Queue is full");
		if(tail == queueArray.length - 1){
			tail = 0;
			queueArray[tail] = value;
		}else{
			queueArray[++tail] = value;
		}
		elementsCount++;
	}
	
	public E remove(){
		E value = peek();
		if(head == queueArray.length - 1){
			head = 0;
		}else{
			head++;
		}
		elementsCount--;
		return value;
	}
	
	public boolean isEmpty(){
		return elementsCount == 0;
	}
	
	public boolean isFull(){
		return elementsCount == queueArray.length;
	}
}

队列的效率和栈一样,插入和删除数据项的时间复杂度均为O(1)。
还有一种队列叫做双端队列,顾名思义就是对两端都可以进行插入、删除操作的队列。如果封闭了其中一端,它就变成了一个栈;如果只允许一端插入,另一端删除,那它就成了一个普通队列。
优先级队列和普通队列的不同之处是:它在插入数据时是有序的。所以优先级队列的插入效率会比较低,时间复杂度为O(N),删除操作则为O(1)。
package dsaa.array;
/**
 * @(#)PriorityQueue.java 2008-12-27 下午01:03:01
 * 
 * @author Qiu Maoyuan
 * Priority Queue
 */
public class PriorityQueue {

	private int[] queueArray;
	private int head = -1;
	
	public PriorityQueue(int initialCapacity){
		queueArray = new int[initialCapacity];
	}
	
	public void insert(int value){
		if(isFull())
			throw new IllegalStateException("Queue is full");
		
		if (isEmpty()){
			queueArray[++head] = value;
		} else {
			int i=head;
			while (i>-1){
				if (queueArray[i]>value){
					queueArray[i + 1] = queueArray[i];
				} else {
					break;
				}
				i--;
			}
			queueArray[i + 1] = value;
			head++;
		}
	}
	
	public boolean isFull(){
		return head == queueArray.length - 1;
	}
	
	public boolean isEmpty(){
		return head == -1;
	}
	
	public int remove(){
		int value = peek();
		head--;
		return value;
	}
	
	public int peek(){
		if(isEmpty())
			throw new IllegalStateException("Queue is empty");
		return queueArray[head];
	}
}

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics