双端队列的实现

Deque是一个双端队列接口,继承自Queue接口,Deque的实现类是LinkedList、ArrayDeque、LinkedBlockingDeque,其中LinkedList是最常用的。

Deque是一个线性collection,支持在两端插入和移除元素。名称 deque 是“double ended queue(双端队列)”的缩写,通常读为“deck”。大多数 Deque 实现对于它们能够包含的元素数没有固定限制,但此接口既支持有容量限制的双端队列,也支持没有固定大小限制的双端队列。

此接口定义在双端队列两端访问元素的方法。提供插入、移除和检查元素的方法。每种方法都存在两种形式:一种形式在操作失败时抛出异常,另一种形式返回一个特殊值(null 或 false,具体取决于操作)。
 

双端队列的接口:


public interface DequeInterface<T> { 
    public void addToFront(T newEntry);
 
    public void addToBack(T newEntry);
 
    public T removeFront();
 
    public T removeBack();
 
    public T getFront();
 
    public T getBack();
 
    public boolean isEmpty();
 
    public void clear();
       
    public int size();

}

实现接口的类

使用LinkedList来实现:

import java.util.LinkedList;
 
/**
 * 双向链表/LinkedList实现双端队列。
 */
public class LinkedDeque<T> implements DequeInterface<T> {
    private LinkedList<T> list;
 
    public LinkedDeque() {
        // 初始化链表
        list = new LinkedList<T>();
    }
 
    @Override
    public void addToFront(T newEntry) {
        // 从队列的头部近入
        list.addFirst(newEntry);
    }
 
    @Override
    public void addToBack(T newEntry) {
        // 从队列的尾部近入
        list.addLast(newEntry);
    }
 
    @Override
    public T removeFront() {
        // 移除首位元素
        return list.removeFirst();
    }
 
    @Override
    public T removeBack() {
        // 移除尾部元素
        return list.removeLast();
    }
 
    @Override
    public T getFront() {
        // 类似于peek(),将首位元素返回,不进行操作。
        return list.getFirst();
    }
 
    @Override
    public T getBack() {
        // 得到尾部元素,不进行操作
        return list.getLast();
    }
 
    @Override
    public boolean isEmpty() {
        // 容量,可以选择size==0,也可以直接调用siEmpty
        return list.isEmpty();
    }
 
    @Override
    public void clear() {
        // 清空即可
        list.clear();
    }
    @Override
    public int size() {
        return list.size();
    }
}
 

自定义一个双向链表,替换掉LinkedList:


package com.openlab.queue;
 
import java.util.LinkedList;
 
/**
 *双向链表实现双端队列。
 */
public class LinkedDeque<T> implements DequeInterface<T> {
    // private LinkedList<T> list;
 
    // 使用一个值保存头结点,一个保存尾结点。 没有必要使用循环链表,因为判断起来比较麻烦。
    private Node first;
    private Node last;
    int size;
 
    public LinkedDeque() {
        // 初始化链表
        // list = new LinkedList<T>();
 
        // 初始化属性
        first = null;
        last = null;
        size = 0; // 虽然有默认初始化,此处仍需初始化,养成一个好的编码习惯
    }

    class Node {
        T data;
        Node prev;
        Node next;
 
        public Node(T data, Node prev, Node next) {
            this.data = data;
            this.prev = prev;
            this.next = next;
        }
 
        public Node(T data) {
            this(data, null, null);
        }
    }
 
    @Override
    public void addToFront(T newEntry) {
        // 从队列的头部近入
        Node newNode = new Node(newEntry);
        if (isEmpty()) {
            // 尾结点也是头结点 <---> 头结点也是尾结点
            last = newNode;
        } else {
            // 新节点与首节点建立双向链接
            first.prev = newNode;
            newNode.next = first;
        }
        first = newNode;
        size++;
        // list.addFirst(newEntry);
    }
 
    @Override
    public void addToBack(T newEntry) {
        // 从队列的尾部近入
        Node newNode = new Node(newEntry);
        if (isEmpty()) {
            // 尾结点也是头结点 <---> 头结点也是尾结点
            first = newNode;
        } else {
            // 新节点与尾节点建立双向链接
            newNode.prev = last;
            last.next = newNode;
        }
        last = newNode;
        size++;
 
        // 从队列的尾部近入
        // list.addLast(newEntry);
    }
 
    @Override
    public T removeFront() {
        // 移除首位元素
        // return list.removeFirst();
        if (isEmpty()) {
            // 抛出异常
        }
        Node front = first;
        // 首节点后移
        first = first.next;
        if (first == null) {
            last = null;
        } else {
            // 断开双向链接
            first.prev = null;
            front.next = null;
        }
        size--;
        return front.data;
    }
 
    @Override
    public T removeBack() {
        if (isEmpty()) {
            // 抛出异常
        }
        Node back = last;
        last = last.prev;
        if (last == null) {
            first = null;
        } else {
            // 断开双向链接
            last.next = null;
            back.prev = null;
        }
        size--;
        return back.data;
        // 移除尾部元素
        // return list.removeLast();
    }
 
    @Override
    public T getFront() {
        // 类似于peek(),将首位元素返回,不进行操作。
        // return list.getFirst();
        if (isEmpty()) {
            // 抛出异常
        }
        return first.data;
    }
 
    @Override
    public T getBack() {
        // 得到尾部元素,不进行操作
        // return list.getLast();
        if (isEmpty()) {
            // 抛出异常
        }
        return last.data;
    }
 
    @Override
    public boolean isEmpty() {
        // 容量,可以选择size==0,也可以直接调用siEmpty
        // return list.isEmpty();
        // 当first 和 back 都为空时,双向链表为空
        return (first == null) && (last == null);
    }
 
    @Override
    public void clear() {
        // 双向链表实现,必须考虑两个对象相互引用的情况,如果出现,那么GC就不会清理这个内存,从而导致内存泄漏。
        // 所以我们需要遍历链表并将其置为null
        for (Node x = first; x != null && x != last;) {
            Node next = x.next;
            x.data = null;
            x.next = null;
            x.prev = null;
            x = next;
        }
        first = last = null;
        size = 0;
        // 清空即可
        // list.clear();
    }
 
    @Override
    public int size() {
        return size;
        // return list.size();
    }
 
}

/* * 基于双向链表实现双端队列结构 */ package dsa; public class Deque_DLNode implements Deque { protected DLNode header;//指向头节点(哨兵) protected DLNode trailer;//指向尾节点(哨兵) protected int size;//队列中元素的数目 //构造函数 public Deque_DLNode() { header = new DLNode(); trailer = new DLNode(); header.setNext(trailer); trailer.setPrev(header); size = 0; } //返回队列中元素数目 public int getSize() { return size; } //判断队列是否为空 public boolean isEmpty() { return (0 == size) ? true : false; } //取首元素(但不删除) public Object first() throws ExceptionQueueEmpty { if (isEmpty()) throw new ExceptionQueueEmpty("意外:双端队列为空"); return header.getNext().getElem(); } //取末元素(但不删除) public Object last() throws ExceptionQueueEmpty { if (isEmpty()) throw new ExceptionQueueEmpty("意外:双端队列为空"); return trailer.getPrev().getElem(); } //在队列前端插入新节点 public void insertFirst(Object obj) { DLNode second = header.getNext(); DLNode first = new DLNode(obj, header, second); second.setPrev(first); header.setNext(first); size++; } //在队列后端插入新节点 public void insertLast(Object obj) { DLNode second = trailer.getPrev(); DLNode first = new DLNode(obj, second, trailer); second.setNext(first); trailer.setPrev(first); size++; } //删除首节点 public Object removeFirst() throws ExceptionQueueEmpty { if (isEmpty()) throw new ExceptionQueueEmpty("意外:双端队列为空"); DLNode first = header.getNext(); DLNode second = first.getNext(); Object obj = first.getElem(); header.setNext(second); second.setPrev(header); size--; return(obj); } //删除末节点 public Object removeLast() throws ExceptionQueueEmpty { if (isEmpty()) throw new ExceptionQueueEmpty("意外:双端队列为空"); DLNode first = trailer.getPrev(); DLNode second = first.getPrev(); Object obj = first.getElem(); trailer.setPrev(second); second.setNext(trailer); size--; return(obj); } //遍历 public void Traversal() { DLNode p = header.getNext(); while (p != trailer) { System.out.print(p.getElem()+" "); p = p.getNex
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Night-Monkey

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值