Java用数组和链表实现队列

Posted 活跃的咸鱼

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java用数组和链表实现队列相关的知识,希望对你有一定的参考价值。

学过数据结构的人都了解过队列这一常见数据结构。下面我用数组和链表实现队列的两种方式做一个总结。

队列介绍

队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列。
队列的数据元素又称为队列元素。在队列中插入一个队列元素称为入队,从队列中删除一个队列元素称为出队。因为队列只允许在一端插入,在另一端删除,所以只有最早进入队列的元素才能最先从队列中删除,故队列又称为先进先出(FIFO—first in first out)线性表。如下所示
在这里插入图片描述

数组实现顺序队列

队列本身是有序列表,使用数组来声明队列如下图:Maxsize代表队列最大容量
因为队列的输入是从队尾输出是从队首来处理的,所以需要两个变量来代表前后两端,如下图front代表队首,rear代表队尾。front随着数据的输出而改变,rear随着数据的输入而改变。
在这里插入图片描述
其实现方法如下:

class ArrayQueue {
	private int maxSize; // 表示数组的最大容量
	private int front; // 队列头
	private int rear; // 队列尾
	private int[] arr; // 该数据用于存放数据, 模拟队列

	// 创建队列的构造器
	public ArrayQueue(int arrMaxSize) {
		maxSize = arrMaxSize;
		arr = new int[maxSize];
		front = -1; // 指向队列头部,分析出front是指向队列头的前一个位置.
		rear = -1; // 指向队列尾,指向队列尾的数据(即就是队列最后一个数据)
	}

	// 判断队列是否满
	public boolean isFull() {
		return rear == maxSize - 1;
	}

	// 判断队列是否为空
	public boolean isEmpty() {
		return rear == front;
	}

	// 添加数据到队列
	public void addQueue(int n) {
		// 判断队列是否满
		if (isFull()) {
			System.out.println("队列满,不能加入数据~");
			return;
		}
		rear++; // 让rear 后移
		arr[rear] = n;
	}

	// 获取队列的数据, 出队列
	public int getQueue() {
		// 判断队列是否空
		if (isEmpty()) {
			// 通过抛出异常
			throw new RuntimeException("队列空,不能取数据");
		}
		front++; // front后移
		return arr[front];

	}

	// 显示队列的所有数据
	public void showQueue() {
		// 遍历
		if (isEmpty()) {
			System.out.println("队列空的,没有数据~~");
			return;
		}
		for (int i = 0; i < arr.length; i++) {
			System.out.printf("arr[%d]=%d\\n", i, arr[i]);
		}
	}

	// 显示队列的头数据, 注意不是取出数据
	public int headQueue() {
		// 判断
		if (isEmpty()) {
			throw new RuntimeException("队列空的,没有数据~~");
		}
		return arr[front + 1];
	}
}

测试如下:

  public static void main(String[] args) {
        Queue queue = new Queue(7);
        queue.addQueue(1);
        queue.addQueue(7);
        queue.addQueue(4);
        queue.addQueue(2);
        queue.addQueue(9);
        queue.showQueue();
        System.out.println(queue.isEmpty());
        System.out.println(queue.isFull());
        System.out.println(queue.headQueue());
        System.out.println(queue.getQueue());
    }
输出:
arr[0]=1
arr[1]=7
arr[2]=4
arr[3]=2
arr[4]=9
arr[5]=0
arr[6]=0
false
false
1
1

数组模拟环形队列

上述顺序队列只能使用一次并不能达到复用的效果。
何为环形队列
在实际使用队列时,为了使队列空间能重复使用,往往对队列的使用方法稍加改进:无论插入或删除,一旦rear指针增1或front指针增1 时超出了所分配的队列空间,就让它指向这片连续空间的起始位置。自己真从MaxSize-1增1变到0,可用取余运算rear%MaxSize和front%MaxSize来实现。这实际上是把队列空间想象成一个环形空间,环形空间中的存储单元循环使用,用这种方法管理的队列也就称为循环队列。
在这里插入图片描述
实现代码如下:

class CircleArray {
	private int maxSize; // 表示数组的最大容量
	//front 变量的含义做一个调整: front 就指向队列的第一个元素, 也就是说 arr[front] 就是队列的第一个元素 
	//front 的初始值 = 0
	private int front; 
	//rear 变量的含义做一个调整:rear 指向队列的最后一个元素的后一个位置. 因为希望空出一个空间做为约定.
	//rear 的初始值 = 0
	private int rear; // 队列尾
	private int[] arr; // 该数据用于存放数据, 模拟队列
	
	public CircleArray(int arrMaxSize) {
		maxSize = arrMaxSize;
		arr = new int[maxSize];
	}
	
	// 判断队列是否满
	public boolean isFull() {
		return (rear  + 1) % maxSize == front;
	}
	
	// 判断队列是否为空
	public boolean isEmpty() {
		return rear == front;
	}
	
	// 添加数据到队列
	public void addQueue(int n) {
		// 判断队列是否满
		if (isFull()) {
			System.out.println("队列满,不能加入数据~");
			return;
		}
		//直接将数据加入
		arr[rear] = n;
		//将 rear 后移, 这里必须考虑取模
		rear = (rear + 1) % maxSize;
	}
	
	// 获取队列的数据, 出队列
	public int getQueue() {
		// 判断队列是否空
		if (isEmpty()) {
			// 通过抛出异常
			throw new RuntimeException("队列空,不能取数据");
		}
		// 这里需要分析出 front是指向队列的第一个元素
		// 1. 先把 front 对应的值保留到一个临时变量
		// 2. 将 front 后移, 考虑取模
		// 3. 将临时保存的变量返回
		int value = arr[front];
		front = (front + 1) % maxSize;
		return value;

	}
	
	// 显示队列的所有数据
	public void showQueue() {
		// 遍历
		if (isEmpty()) {
			System.out.println("队列空的,没有数据~~");
			return;
		}
		// 思路:从front开始遍历,遍历多少个元素
		for (int i = front; i < front + size() ; i++) {
			System.out.printf("arr[%d]=%d\\n", i % maxSize, arr[i % maxSize]);
		}
	}
	
	// 求出当前队列有效数据的个数
	public int size() {
		// rear = 2
		// front = 1
		// maxSize = 3 
		return (rear + maxSize - front) % maxSize;   
	}
	
	// 显示队列的头数据, 注意不是取出数据
	public int headQueue() {
		// 判断
		if (isEmpty()) {
			throw new RuntimeException("队列空的,没有数据~~");
		}
		return arr[front];
	}
}

链表实现队列

public interface Queue <E>{
    int getSize();//获得队列长度
    boolean isEmpty();//队列是否为空
    void enQueue(E e);//入队
    E deQueue();//出队
    E getHead();//获得队头元素
    void traverse();//遍历队列
}
public class LinkedListQueue<E> implements Queue<E>{
    private Node head,tail;
    private int size;

    public LinkedListQueue() {
        head=tail=new Node();
        size=0;
    }

    private class Node{
        public E e;
        public Node next;

        public Node(E e) {
            this.e = e;
        }

        public Node() {
        }

        public Node(E e, Node next) {
            this.e = e;
            this.next = next;
        }

    }
    @Override
    public int getSize() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return size==0;
    }

    @Override
    public void enQueue(E e) {
        if(tail==null){
            //尾部插入一个元素
            tail=new Node(e);
            head=tail;
        }else {
            tail.next=new Node(e);
            //队尾后移
            tail=tail.next;
        }
        size++;
    }

    @Override
    public E deQueue() {
        if (isEmpty()) {
            throw  new RuntimeException("empty queue");
        }
        //辅助指针
        Node temp=head;
        //头指针后移
        head=head.next;
        temp.next=null;
        if(head==null){
            tail=null;
        }
        size--;
        return temp.e;
    }

    @Override
    public E getHead() {
        if(isEmpty()) {
            throw new RuntimeException("empty queue");
        }
        return head.e;
    }
    //遍历队列
    public void traverse(){
        Node temp=head;
        if(temp==null) {
            throw new RuntimeException("empty queue");
        }
        while (true){
            //遍历到最后
            if (temp==null){
                break;
            }
            System.out.println("the element is:"+temp.e);
            temp=temp.next;//向后遍历
        }
    }
}
public class Test {
    public static void main(String[] args) {
        LinkedListQueue<String> listQueue = new LinkedListQueue<>();
       // Queue
        listQueue.enQueue("a");
        listQueue.enQueue("b");
        listQueue.enQueue("c");
        listQueue.enQueue("d");
        System.out.println(listQueue.isEmpty());
        System.out.println(listQueue.getSize());
        listQueue.deQueue();
        listQueue.traverse();
    }
}
测试结果:
false
4
the element is:a
the element is:b
the element is:c
the element is:d

以上是关于Java用数组和链表实现队列的主要内容,如果未能解决你的问题,请参考以下文章

用数组和链表两种方式实现队列

C中线性表和链表的区别

数组和链表的区别ArrayList和LinkedList的区别使用LinkedList模拟栈和队列

python学习之双端队列和链表实现队列

java实现顺序表

Java数据结构之链表