循环队列的顺序结构及实现

循环队列

队列的头尾相连的顺序结构称为循环队列

1. 为何有循环队列

队列的不足
在这里插入图片描述
在这里插入图片描述

每次出队的时候,队首后面的元素都得一个一个往前移一位,保证队首在下标为0处
插入的时候,插入位置后面元素都得往后移动一位
时间复杂度为O(n)

2.解决办法

不去移动元素,而去移动元素所在下标,将队列目前第一个元素所在角标作为队首
定义头指针front,与尾指针rear去进行移动
初始条件头尾指针都位于0处,插入时rear指针向后移动,出队时front指针也向后移动

在这里插入图片描述

但当rear移动到队尾时再进行后移时将移动到?

在这里插入图片描述

当reae指针移到队尾时,若队首还有位置则跳到队首,将队尾与队首相连

在这里插入图片描述

入队出队操作,当rear=front时队满,进行扩容

在这里插入图片描述

3.循环队列的问题

队满时 front = rear
队空时 front = rear
满和空的条件都一样,如何判断

4.其中一种解决办法

front指针指向队首,rear指针指向队尾后一个位置,留出一个null的位置作为标志位

在这里插入图片描述

队满条件:(rear+1)%data.length ==front
队空条件:rear==front
时间复杂度变为O(1)

5.代码实现方法

1. 定义及构造方法
/**
 * 循环队列的顺序结构的实现
 * @author TZH
 * @param <E>
 */
public class ArrayQueueLoop<E> implements Queue<E> {
	private E[] data;	//泛型数组
	private int front;	//头指针
	private int rear;	//尾指针
	private int size;	//元素个数
	private static int SIZE = 10;	//默认容量
	
	
	//指定容量的循环队列
	public ArrayQueueLoop(int capaticy) {
		data = (E[]) new Object[capaticy+1];	
		/**
		 * +1主要是因为尾指针后还预留了一个null的位置,便于确定元素容量满的状态
		 * 头尾指针默认都从0处开始,元素个数初始为0
		 */
		front = 0;
		rear = 0;
		size = 0;
	}
	//默认容量的循环队列
	public ArrayQueueLoop (){
		this(SIZE);
	}
2.得到元素个数,清空,判空方法
public int getSize() {
		return size;
	}

	public boolean isEmpty() {
		return front==rear&&size==0;
	}

	public void clear() {
		front=0;
		rear=0;
		size=0;
	}
3.入队
/**入队
	 * 
	 */
	public void enqueue(E e) {
		if((rear+1)%data.length==front){
			resize(data.length*2-1);	//扩容
		}
		data[rear] = e;					//null所在位置为新元素入队位置
		rear = (rear+1)%data.length;	//尾指针右移一位
		size++;
	}
	
4.出队
/**
	 * 出队
	 */
	public E dequeue() {
		if(isEmpty()){
			throw new NullPointerException("循环队列为空");
		}
		E e = data[front];				//出队元素
		front = (front+1)%data.length;	//头指针向右移一位
		size--;							//元素个数减一
		if(data.length>SIZE+1&&size<=data.length/4){
			//长度大于默认容量+1,留有一个空闲null
			//元素个数<=长度的1/4
			resize(data.length/2+1);
		}
		return e;
	}
5.容量变化过程
/**
	 * 容量变化过程
	 * @param i
	 */
	@SuppressWarnings("unchecked")
	private void resize(int newLen) {
		E[] newdata = (E[]) new Object[newLen];
			//创建一个数组用来存放扩容前元素,向下转型
		int index = 0;	//标记取出元素个数
		for(int i=front;i!=rear;i=(i+1)%data.length){
			/*
			 * 从头指针开始取出元素
			 * 当取到尾指针的位置时退出循环
			 * 取出一个i往后移动,不能直接++,对length取余得出所在位置
			 */
			newdata[index++] = data[i];	//赋值且index向右移动
		}
		front = 0;		//头指针重新为0
		rear = index;	//扩容后的尾指针为index值
		data = newdata;	//更新数组
		
	}
6.得到队尾队首元素
/**
	 * 得到队首元素,不出队
	 * 
	 */
	public E getFront() {
		
		return data[front];
	}
	/**
	 * 得到队尾元素,不出队
	 */
	public E getRear() {
		// 元素456 123 
		// 角标0123456
		// 7+3-1=9%7=2
		return data[(data.length+rear-1)%data.length];
	}
7.toString()方法
@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append("ArrayQueueLoop size="+getSize()+",capacity ="+(data.length-1)+"\n");
		if(isEmpty()){
			sb.append("[]");
		}else{
			sb.append('[');
			for(int i=front;i!=rear;i=(i+1)%data.length){
				//i为取出元素时的指针
				//i=rear的时候循环退出
				//当i+1取余,而不是i++
				sb.append(data[i]);
				if((i+1)%data.length==rear){	
					//当i与尾指针重合时取出的是最后一个元素
					sb.append(']');
				}else{
					sb.append(',');
				}
			}
		}
		return sb.toString();
	}
}

8.equals()
@Override
	public boolean equals(Object obj) {
		if(obj==null){
			return false;
		}
		if(obj==this){
			return true;
		}
		if(obj instanceof ArrayQueueLoop ){
			ArrayQueueLoop queue = (ArrayQueueLoop) obj;
			if(queue.getSize()==getSize()){
				
				for(int i=front;i!=rear;i=(i+1)%data.length){
					if(data[i]!=queue.data[i]){
						return false;
					}
				}
//				for(int i=0;i<getSize();i++){
//					if(queue.dequeue()!=dequeue()){
//						return false;
//					}
//				}
				return true;
			}
		}
		return false;
	}
	
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值