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

[b]每篇笔记都会附上随书的Applet演示程序,有算法看不明白的,可以[url="http://yuan.iteye.com/topics/download/4e55231d-40fd-3954-a5ff-6ac60f34e306"]下载Applet[/url]运行起来(直接打开html文件即可),可以很容易地看清楚算法的每一步。[/b]
[size=large][align=center][b]栈[/b][/align][/size]
[b]栈[/b]是一种先进后出(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)。
[align=center][size=large][b]队列[/b][/size][/align]
[b]队列[/b]是一种先进先出(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;
}
}

以上队列存在一个问题,队列满了以后,无论删除掉多少个数据项,甚至清空这个队列,仍然不能插入新的数据。其实有一种解决方法就是,在删除数据项的时候,后面的所有数据项都往前移动,但这样效率很低。
为了避免队列不满却不能插入新数据项的问题,可以让队头队尾指针绕回到数组开始的位置,这样的队列叫[b]循环队列[/b]。
改进后的代码如下:
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)。
还有一种队列叫做[b]双端队列[/b],顾名思义就是对两端都可以进行插入、删除操作的队列。如果封闭了其中一端,它就变成了一个栈;如果只允许一端插入,另一端删除,那它就成了一个普通队列。
[b]优先级队列[/b]和普通队列的不同之处是:它在插入数据时是有序的。所以优先级队列的插入效率会比较低,时间复杂度为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];
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值