队列简介:
队列入队出队原理图:
队列入队出队代码:
代码演示:
package com.fan.queue;
//此类用来模拟队列,我们
public class LinekdListAndQueue<E> {
//根据队列的基本简介,需要有一个队头和队尾
//1.设置节点内为内部类,是单链表节点
private class Node<E> {
//数据域,为了省略篇幅,没有用私有属性和set,get方法
E e;
//指针域
Node next;
public Node(E e) {
this.e = e;
}
public Node(E e, Node next) {
this.e = e;
this.next = next;
}
@Override
public String toString() {
return "Node{" +
"e=" + e +
'}';
}
}
//2.接下来写队列的队头和队尾,即头节点和尾节点
private Node<E> headNode ;//此指针一直指向队头
private Node<E> tailNode;//此指针一直指向队尾
private int size;//size = 0;
public LinekdListAndQueue() {//构造方法
//构造一个空链表的时候,没有队头和队尾节点,所以让其明显指向null
headNode = null;
tailNode = null;
}
//入队操作offer,e为要入队的元素
public boolean offer(E e){
//将元素封装成新节点
Node<E> newNode = new Node<E>(e);
//1.第一次入空队,判断是否为空,为空要单独添加
if(headNode == null){//如果头节点为空,即当前队列没有节点
headNode = newNode;//让新节点称为队首,即头节点指向新节点
tailNode = newNode;//此时队列中只有一个节点,既是队头也是队尾
}else{//队列不为空,
//将新添加的节点放到尾节点的后边
tailNode.next = newNode;
//现在末尾又增加新节点了,所以,尾节点指针要后移,重新指向最后的尾节点
tailNode = newNode;
}
//如果返回值是boolean类型则这样写,即尾节点地址和新增加的节点地址是否相同
return tailNode == newNode;
}
//出队操作
public E pool(){
//先判断队列是不是为空
if(headNode == null){//如果头节点或者尾节点指向了nul,就证明队列为空
return null;
}
//先将头节点的元素保存
E v = headNode.e;
//然后就可以将当前头节点删除,即出队
headNode = headNode.next;//头节点往后移,尾节点不动
return v;//返回头节点
}
//显示队首元素
public E peek(){
if(headNode == null){
return null;
}
E v = headNode.e;
return v;
}
//获取队列元素个数
public int getSize(){
//定义一个临时节点curr用来遍历
Node<E> curr = headNode;//从头开始遍历
while(true){
if(curr == null){
break;
}
size++;
curr = curr.next;//后移遍历
}
return size;
}
//链表的节点显示
public void show(){
//定义一个临时节点curr用来遍历
Node<E> curr = headNode;//从头开始遍历
while(true){
if(curr == null){
break;
}
System.out.println(curr);//打印节点
curr = curr.next;//后移遍历
}
}
}
测试类:
package com.fan.queue;
public class LinekdListAndQueueTest {
public static void main(String[] args) {
LinekdListAndQueue<Integer> linekdListAndQueue
= new LinekdListAndQueue<Integer>();
System.out.println(linekdListAndQueue.offer(1));
System.out.println(linekdListAndQueue.offer(2));
System.out.println(linekdListAndQueue.offer(3));
linekdListAndQueue.show();
System.out.println("显示队首:"+linekdListAndQueue.peek());
System.out.println("显示队元素个数:"+linekdListAndQueue.getSize());
System.out.println("出队:"+linekdListAndQueue.pool());
System.out.println("出队:"+linekdListAndQueue.pool());
System.out.println("出队:"+linekdListAndQueue.pool());
System.out.println("出队:"+linekdListAndQueue.pool());
}
}
删除某个元素:
//删除某个节点
public E remove(E key){//key为要删除的元素
//因为单链表的删除要找到要删除节点的前一个节点,
// 所以我么设置一个空数据的头节点
Node<E> head = new Node<E>((E) Integer.valueOf(-1),null);
head.next = headNode;//让head作为头节点的上一个节点
Node<E> curr = head;//遍历的临时节点curr,并指向新的头节点
boolean flag = false;//是否找到要删除的节点
while(true){
if(curr.next == null){
break;//到链表末尾
}
if(curr.next.e == key){//找到了
flag = true;
break;
}
curr = curr.next;
}
if(flag){
E v = (E) curr.next.e;
curr.next = curr.next.next;
//让头节点重新指向第一个有效元素,因为show方法是从headNode开始遍历的
headNode = head.next;
return v;
}else{
System.out.println("没找到要删除的元素--");
return null;
}
}
测试类:
package com.fan.queue;
public class LinekdListAndQueueTest {
public static void main(String[] args) {
LinekdListAndQueue<Integer> linekdListAndQueue
= new LinekdListAndQueue<Integer>();
System.out.println(linekdListAndQueue.offer(1));
System.out.println(linekdListAndQueue.offer(2));
System.out.println(linekdListAndQueue.offer(3));
System.out.println(linekdListAndQueue.offer(4));
linekdListAndQueue.show();
System.out.println("显示队首:"+linekdListAndQueue.peek());
System.out.println("显示队元素个数:"+linekdListAndQueue.getSize());
System.out.println("删除元素:"+linekdListAndQueue.remove(8));
System.out.println("删除后显示队列:");
linekdListAndQueue.show();
System.out.println(linekdListAndQueue.offer(5));
linekdListAndQueue.show();
System.out.println("出队:"+linekdListAndQueue.pool());
System.out.println("出队:"+linekdListAndQueue.pool());
System.out.println("出队:"+linekdListAndQueue.pool());
System.out.println("出队:"+linekdListAndQueue.pool());
}
}
测试结果: