Java数据结构基础--循环队列与链队列

Java数据结构基础–循环队列与链队列

队列定义:
队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。

在这里插入图片描述

循环队列(基于数组)

完整代码:


public class Queue {
	private int rear,front;//队首,队尾指针
	private Object element[];//存储数组
	private int maxSize;
	
	private boolean IsEmpty(){//判空
		return rear == front?true:false;
	}
	
	private boolean IsFull() {//判满
		return (rear+1)%maxSize==front?true:false;
	}
	
	public int getSize() {//求队长
		return (rear - front + maxSize)%maxSize;
	}
	
	public Queue(int maxSize ) {//构造函数
		this.maxSize = maxSize+1;
		this.front=0;
		this.rear=0;
		element = new Object[maxSize];
	}
	
	public boolean EnQueue(Object x) {//入队列
		if(IsFull() == true) {return false;}
		element[rear] = x;
		rear = (rear + 1)%maxSize;
		return true;
	}
	
	public boolean DeQueue() {//退队列
		if(IsEmpty() == true) {return false;}
		front = (front + 1)%maxSize;
		return true;
	}
	
	public Object getFront() {//取队首
		if(IsEmpty()) {return false;}
		return element[front];
	}
	
	@Override
	public String toString() {
		String result = "";
		for(int i = front;i != rear;i=(i+1)%maxSize) {
			result += element[i] + "-->";
		}
		result += "null";
		return result;
	}
}

部分代码详解:
循环队列将数组头尾相连,形成一个闭合环,通过front和rear的在环内的移动实现入队列和退队列。

在这里插入图片描述

为了区分队列满和队列空,一般会空出一个位置不存数据。从而front=rear时队列空;rear+1=front为队列满。

在这里插入图片描述

判断队列是否已满

private boolean IsFull() {//判满
		return (rear+1)%maxSize==front?true:false;
	}

(1)(x%maxSize)是在0~maxSize-1之间循环的数字;
(2)原先判定条件为rear+1==front则为满,但是在多次入队列和退队列的过程后会出现下图情况。
在这里插入图片描述
(3)则rear+1=front就不能用了。我们应该使判断条件在0~maxSize循环起来,即(rear+1)%maxSize。如图rear=7时,(7+1)%8= =0,队列已满。

求队列长度getSize():

public int getSize() {//求队长
		return (rear - front + maxSize)%maxSize;
	}

此时分为两种情况:rear > frontrear < front:
(1)rear > front
在这里插入图片描述
(rear - front + maxSize)%maxSize式子实际上就变成了
(rear%maxSize - front%maxSize) + 0==》rear - front

(2)rear < front
在这里插入图片描述

(1)rear - front求出来的是负数,同时绝对值也是还未存数据的地方的长度(图中的rear-front=-2,而未存数据的地方时(2)和(3),长度为2)

(2)rear - front + maxSize:最大存储数-空余存储数=已存数据长度

(3)而%maxSize的就是使(rear - front + maxSize)中的maxSize在两种不同情况下取不同的值。

入队列与退队列:

在理解上面之后,入队和退队就变得更好理解了

public boolean EnQueue(Object x) {//入队列
		if(IsFull() == true) {return false;}
		element[rear] = x;
		rear = (rear + 1)%maxSize;
		return true;
	}

(rear + 1)%maxSize就是为了防止下图情况,使rear + 1在0~7之间循环
在这里插入图片描述

public boolean DeQueue() {//退队列
		if(IsEmpty() == true) {return false;}
		front = (front + 1)%maxSize;
		return true;
	}

退队列也是同样的想法。

测试代码:


public class Main {
	public static void main(String[] args) {
				Queue qu = new Queue(6);
				qu.EnQueue(1);
				qu.EnQueue(2);
				System.out.println(qu);
				qu.DeQueue();
				qu.EnQueue(3);
				qu.EnQueue(4);
				System.out.println(qu);
				qu.DeQueue();
				System.out.println(qu);
				System.out.println(qu.getSize());
	}
}

运行结果:
在这里插入图片描述

链式队列(基于链表):


public class Queue {
	class Node{
		private Object data;
		private Node next;
		
		public Node(Object data,Node next) {
			this.data = data;
			this.next = next;
		}
		
		public Node(Object x) {
			this.data = x;
			this.next = null;
		}
	}
	
	private Node front,rear;//头指针,尾指针。
	
	private boolean IsEmpty() {//判空
		return front == null?true:false;
	}
	
	public boolean EnQueue(Object x) {//入队列
		if(IsEmpty()) {
			front = rear = new Node(x);
			if(front == null) {return false;}
		}else {
			rear.next = new Node(x);
			rear = rear.next;
			if(rear == null) {return false;}
		}
		return true;
	}
	
	public boolean DeQueue() {//退队列
		if(IsEmpty()) {return false;}
		front = front.next;
		return true;
	}
	
	public Object getFront() {//取队首
		return front.data;
	}
	
	public int getSize() {//获取长度
		int k =0;
		Node p = front;
		while(p!=null) {
			p=p.next;
			k++;
		}
		return k;
	}
	
	@Override
	public String toString() {
		String result = "";
		Node p = front;
		while(p != null) {
			result += p.data + "-->"; 
			p=p.next;
		}
		return result+"null";
	}
}

在链队列中的rear和front不再是下标,而是两个Node节点。

判空:

private boolean IsEmpty() {//判空
		return front == null?true:false;
	}

只需要判断front是否为空,即头元素是否存在。

入队列与退队列:

public boolean EnQueue(Object x) {//入队列
		if(IsEmpty()) {
			front = rear = new Node(x);
			if(front == null) {return false;}
		}else {
			rear.next = new Node(x);
			rear = rear.next;
			if(rear == null) {return false;}
		}
		return true;
	}

(1)第一个条件判断:
front = rear = new Node(x)==》front与rear指向新节点
在这里插入图片描述
(2)else语句:
rear.next = new Node(x)= =》将rear.next指向新节点
rear = rear.next;= =》rear指针移动

(1)链队列与上面的循环队列的不同在于,链队列rear的指向是已经存数据的了;循环队列rear的指向是未存数据的。
(2)注意rear.next = new Node(x)得在rear = rear.next之前,得先开辟空间,在将指针移动。
在这里插入图片描述

public boolean DeQueue() {//退队列
		if(IsEmpty()) {return false;}
		front = front.next;
		return true;
	}

将front向后移动,改变队首即可。

求长度getSzie():

public int getSize() {//获取长度
		int k =0;
		Node p = front;
		while(p!=null) {
			p=p.next;
			k++;
		}
		return k;
	}

与之前的单链表相同,都是通过指针的后移计数,计算队列长度。

测试代码:


public class Main {
	public static void main(String[] args) {
		Queue qu = new Queue();
		qu.EnQueue(1);
		qu.EnQueue(2);
		qu.EnQueue(3);
		qu.EnQueue(4);
		System.out.println(qu);
		qu.DeQueue();
		System.out.println(qu);
		System.out.println(qu.getSize());
	}
}

运行结果:
在这里插入图片描述
感谢你的阅读,欢迎留言。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值