Java基础 - 队列的链式存储结构及实现

队列的链式存储结构及实现:
类似于使用链式结构保存线性表,也可以采用链式结构来保存队列的元素,采用链式存储结构的队列也被称为链队列。

对于链队列而言,由于程序需要从rear端添加元素,然后从front端删除元素,因此考虑对链队列增加front、rear两个引用变量,使他们分别指向链队列的头、尾两个节点。如下图所示:

由于链队列采用链式存储结构保存数据元素,该队列允许添加无限多个数据元素,因此链队列不会出现列满的问题。

1、插入队列
对于链队列而言,插入操作的实现非常简单,只要创建一个新节点,让原rear节点的next指向新节点,在让rear指向新节点即可。如下图所示链队列的插入操作:



2、移除队列
对于链队列而言,删除操作的实现也是非常的简单,只要将原front节点指向原front节点的next节点,当然不要忘记释放原front节点的引用。如下图所示链队列的移除操纵:


下面是代码实现:

public class LinkQueue <T> {
	private class Node{
		private T data;
		private Node next;

		@SuppressWarnings("unused")
		public Node(){}
		public Node(T element, Node next){
			this.data = element;
			this.next = next;
		}
	}
	//代表链式队列的大小
	private int size;
	//链式队列的链队首
	private Node front;
	//链式队列的链队尾
	private Node rear;
	
	
	public LinkQueue(){
		size = 0;
		front = null;
		rear = null;
	}
	public LinkQueue(T element){
		rear = new Node(element, null);
		front = rear;
		size ++;
	}
	//返回链式队列的长度
	public int length(){
		return size;
	}
	//判断队列是否为空
	public boolean isEmpty(){
		return size == 0;
	}
	
	//向rear端队尾插入元素
	public void add(T element){
		if(isEmpty()){
			rear = new Node(element, null);
			
			front = rear;
		}else{
			rear.next = new Node(element, null);
			
			rear = rear.next;
		}
		
		size ++;
	}
	//从front端队首移除元素
	public T remove(){
		exceptionForRemove();
		
		Node oldNode = front;
		
		front = front.next;
		
		oldNode.next = null;
		
		size --;
		return oldNode.data;
	}
	
	//返回链式队列的堆首元素,但不删除
	public T element(){
		return front.data;
	}
	
	//清空链式队列
	public void clear(){
		front = null;
		rear = null;
		size = 0;
	}
	//toString 方法
	public String toString(){
		if(isEmpty()){
			return "[]";
		}else{
			StringBuffer sb = new StringBuffer("[");
			for(Node current = front; current != null; current = current.next){
				sb.append(current.data.toString() + ",");
			}
			return sb.toString().substring(0, sb.length() - 1) + "]";
		}
	}
	private void exceptionForRemove(){
		if(isEmpty()){
			throw new IndexOutOfBoundsException("链式队列为空异常");
		}
	}
}
测试代码如下:

import com.yc.list.LinkQueue;

public class LinkQueueTest {
	public static void main(String[] args) {
		LinkQueue<String> queue = new LinkQueue<String>();
		
		queue.add("aaaa");
		queue.add("bbbb");
		queue.add("cccc");
		System.out.println( "链式队列为:  " + queue);
		System.out.println();
		
		System.out.println( "移除队首元素:  " + queue.remove());
		System.out.println( "链式队列为:  " + queue);
		System.out.println();
		
		queue.add("dddd");
		queue.add("eeee");
		System.out.println( "添加 dddd和 eeee链式队列为:  " + queue);
		System.out.println( "此时队首元素为:" + queue.element());
	}
}
测试结果为:

上面创建了一个链队列,但不会出现队列“”满“”的情形,因此程序可以不受限制的向链队列中添加元素。


JAVA集合中的队列:

从JDK 1.5开始,java的集合框架提供了一个Queue接口,该接口代表了一个队列。实现该接口或者实现继承了该接口的类可以当做队列来使用。Queue里包含了 6 个方法,用于代表队列

所包含的3个标志性方法,如下所示:
(1)插入:在rear端插入元素。
(2)移除:在front端删除元素。
(3)访问:在front端访问元素。

Java为上面每个方法都提供了两个版本:具有特殊返回值的版本和抛出异常的版本。这样就产生了 6 个方法。关于Queue接口里定义的 6 个方法的说明如下表所示:

 抛出异常的版本具有特殊返回值的版本
插入add(e)offer(e)
移除remove()poll()
访问element()peek()

Java提供了一个Queue接口,JDK 1.5还为Queue接口提供了一个Deque接口,这个接口代表另外一种特殊的队列--双端队列。


双端队列(有英文单词Deque代表)代表一种特殊的队列,他可以在两端同时进行插入、删除操作。如下图所示:


对于双端队列,由于它可以从两端分别进行插入、删除操作,如果程序将所有的插入、删除操作固定在一端进行,这个双端队列就变成了前面的栈。由此可见,Deque和Queue。Stack之间的关系如下图所示。


从上面图可以看出,双端队列(Deque)既是Queue的子接口,也可说是Stack(虽然jdk并未把Stack作为一个接口)的子接口。因此,Deque既可以当做队列来使用,又可以当做栈来使用。

由此可见,Deque是Queue'和Stack‘的混合而成的一种特殊线性表。

JDK虽然提供一个古老的Stack'类,但现在不推荐开发者使用这个古老的栈实现,而是使用Deque的实现作为栈的使用。

JDK为Deque提供两种ArrayDeque、linkedList这两个常见的实现类,其中ArrayDeque是顺序存储结构实现的双端队列。而LinkedList是链式存储结构实现的双端队列。

在前面的双向链表中还提到了LinkedList代表一种双向、链式存储结构的循环线性表,这里有提到了LinkedList代表线程安全的、链式结构的双端队列,由此可见,LinkedList实在是一个功能非常强大的集合类。事实上,LinkedList几乎是Java集合框架中方法最多的类。

关于JDK提供的线性表、队列、栈的类图如下所示:


从上图可以看出。JDK提供的工具类非常强大,它分别代表线性表、队列、栈三种数据结构提供了两种实现:顺序结构和链式结构。虽然LinkedList工具类的功能非常强大,既可以作为线性表来使用、又可以作为队列来使用,还可作为栈来使用,但对大部分程序而言,使用Arraylist和ArrayDeque时性能可能比LinkedList更好。
  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值