java队列和栈_java栈和队列

本文探讨了使用数组和链表分别实现栈和队列的原理,强调了数组在空间效率上的限制及其动态调整策略,以及链表的灵活性。通过对比两种数据结构在存取方式、存储位置、空间利用及操作性能上的差异,揭示了它们各自的优势和适用场景。
摘要由CSDN通过智能技术生成

可变长数组实现

链表实现

数组与链表的对比

队列

链表实现

下压栈(简称栈)是一种基于后进后出(LIFO)策略的集合类型。这里学习分别用数组和链表这两种基础数据结构来实现栈。

栈支持的基本操作有push,pop。

可变长数组实现

要用数组实现栈,可以声明一个int型的标记,这个标记指向的位置即为栈顶,push操作时,将值放在数据中标记的位置,同时将标记+1,pop时,返回数组在标记位置的值,同时标记-1。

但java中的数组在声明的时候其长度就已经固定了,所以栈使用的空间只能是这个数组最大容量的一部分。为了能容纳更多的数据而声明一个特别大的数组会非常浪费空间,那如何解决这个问题,达到既不会浪费数组空间也不会超出数组范围呢?

可以采用动态调整数组大小的方式,在push操作导致栈已满时,重新创建一个数组,其容量为原数组的两倍。同理在pop操作使数组的闲置空间达到一定程度时,重新创建一个容量更小的数组。但闲置的判断标准不能为一半1/2,否则会造成在1/2的临界点处push和pop操作时发生“抖动”,即频繁地进行数组扩容、缩容操作,这会极大地降低栈的性能。所以通常的做法是在减少到数组容量的1/4时缩容为1/2。

实现可变长数组的代码如下:

public class StackResizeArray{private Item[] a; //array of items

private int n; //number of elements on stack

publicStackResizeArray() {

a= (Item[]) new Object[2];

n= 0;

}public booleanisEmpty() {return n == 0;

}public intsize() {returnn;

}private void resize(intcapacity) {assert capacity >=n;

Item[] temp= (Item[]) newObject[capacity];for (int i = 0; i < n; i++) {

temp[i]=a[i];

}

a=temp;

}public voidpush(Item item) {if (n ==a.length)

resize(2 * a.length); //double size of array if necessary

a[n++] = item; //add item

}publicItem pop() {if(isEmpty())throw new NoSuchElementException("Stack underflow");

Item item= a[n - 1];

a[n- 1] = null; //to avoid loitering

n--;//shrink size of array if necessary

if (n > 0 && n == a.length / 4)

resize(a.length/ 2);returnitem;

}

}

pop方法中,a[n - 1] = null将数组中已经出栈的位置设为null,是为了避免对象游离,否则这个位置的对象虽然已经不在栈中,但还被数组引用着,导致GC无法对其回收。

链表实现

栈的另外一种实现方式是采用链表,链表是一种递归的数据结构,它或者为空,或者指向一个结点的引用,该结点含有一个泛型的元素和一个指向另一条链表的引用。 构成链表的基本结点可以为:

private static class Node{publicItem item;publicNode next;

}

其中泛型的item变量存放数据,同样是Node类型的next变量用来指向下一个结点。将链表的头部作为栈顶,push相当于在表头插入元素,pop是从表头删除元素。 代码如下:

public class StackLinkedList{private static class Node{publicItem item;publicNode next;

}private Nodefirst;private intN;private booleanisEmpty() {return first == null;

}public intsize() {returnN;

}public voidpush(Item item) {

Node oldFirst =first;

first= new Node();

first.item=item;

first.next=oldFirst;

N++;

}publicItem pop() {if(isEmpty())throw new NoSuchElementException("Stack underflow");

Item item=first.item;

first=first.next;

N--;returnitem;

}

}

数组与链表的对比

数组与链表的区别决定了两种栈实现的区别:

存取方式上,数组可以顺序存取或者随机存取,而链表只能顺序存取;

存储位置上,数组逻辑上相邻的元素在物理存储位置上也相邻,而链表不一定;

存储空间上,链表由于带有指针域,存储密度不如数组大;

按序号查找时,数组可以随机访问,需要的时间是常数,而链表不支持随机访问,需要的时间与数据规模成线性关系。

按值查找时,若数组无序,数组和链表时间复杂度均为O(n),但是当数组有序时,可以采用折半查找将时间复杂度降为O(logn);

插入和删除时,数组平均需要移动n/2个元素,而链表只需修改指针即可;

空间分配方面: 虽然可变长数组可以扩充,但需要移动大量元素,导致操作效率降低,而且如果内存中没有更大块连续存储空间将导致分配失败; 链表存储的节点空间只在需要的时候申请分配,只要内存中有空间就可以分配,操作比较灵活高效;

队列

链表实现

先进先出队列(简称队列)是一种基于先进先出(FIFO)策略的集合类型。这里只关注队列的链表实现。与链表实现的栈类似,用结点包含泛型的item变量和next变量,前者存放数据,后者用来指向下一个结点。不同之处在于链表的头部、尾部都会被操作,从链表的一端入队(enqueue),从另一端出队(dequeue) 代码:

public class Queue{private static class Node{publicItem item;publicNode next;

}private Nodefirst;private Nodelast;private intN;public voidenqueue(Item item) {

Node oldLast =last;

last= new Node();

last.item=item;if(isEmpty()) {

first=last;

}else{

oldLast.next=last;

}

N++;

}publicItem dequeue() {if(isEmpty()) {return null;

}

Item result=first.item;

first=first.next;if(isEmpty()) {

last= null;

}

N--;returnresult;

}public booleanisEmpty() {return N == 0;

}public intsize() {returnN;

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值