数据结构之循环队列实现思路

循环队列数据结构是什么样的?
循环结构底层实现:数组
数据控制:由指针控制数据进出。
怎么循环?:看代码 模糊的说就是根据指针把空间填满。一般队列是数据出去后前面的空间就为空,而循环队列就是将那些空出来的空间进行循环使用。
实现接口:

public   class ArrayQueueLoop1<E> implements Queue<E> {		
		public E[] data; 	// 定义数组	
		private int front;  // 定义头指针: 也可以叫出队指针		
		private int rear;   // 定义尾指针 进队指针		
		private int size;   // 定义数据长度		
    		final private static int DEFAULT_LENGTH = 10;// 定义默认长度
    
    		// 定义构造方法 一个默认 一个有参 分别定义一个默认长度的循环队列 和一个 指定长度的循环队列
    		public ArrayQueueLoop1() {
    			data = (E[]) new Object[DEFAULT_LENGTH+1];
    			front = 0;
    			rear = 0;
    			size = 0;
    		}
    
    		public ArrayQueueLoop1(int capacity) {
			data = (E[]) new Object[capacity+1];
			front = 0;
			rear = 0;
			size = 0;
		}

		//只能進行擴容  縮容不行
//		public void resize(int newLength) {
//			E[] newE = (E[]) new Object[newLength+1];
//			int k = 0;
			
//			for (int i = 0; i < getSize(); i++) {
//				
//				if (rear - front < 0) {
//					for (int j = 0; j < rear; j++) {
//						newE[k] = data[i];
//						k++;
//					}
//				}
//			
//				newE[k] = data[i];
//				k++;
//				
//			}
//			front = 0;
//			rear = getSize();			
//			data = newE;
//			

//		}
		public void resize(int newLen) {
			// 扩容:怎么扩?创建一个新的数组,从出栈指针开始进行遍历,将元素放进新数组,
			//如果进栈指针减去出栈指针是负数,那就证明出栈指针前面也是有元素的,
			//并且是它自身后面的元素,那么从0开始,把进栈指针之前的元素也复制进新数组中,最后替换数组,并重新设置指针。
			E[] newData = (E[]) new Object[newLen+1];
			int index = 0;// 新数组角标
			for (int i = front; i != rear; i = (i + 1) % data.length) {
				newData[index++] = data[i];
			}
			front = 0;
			rear = index;
			data=newData;
		}
		// 扩容另一种实现方法
		
		@Override
		public int getSize() {
			// TODO Auto-generated method stub
			// 计算循环队列元素个数:n=(rear-front+ MAXSIZE) mod MAXSIZE 这个公式 有两种情况 头在前
			// 尾在后,头减去尾就可以计算出 元素个数 第二种情况 尾在前头在后,那么尾数减去头的话就是负数 依然代表元素个数
			// 加上总长度,求余总长度,巧妙的公式 
			return (rear - front + data.length) % data.length;
			//return size;
		}

		@Override
		public boolean isEmpty() {
			// TODO Auto-generated method stub
			// 非空判断 怎么判断?进队列指针==出队列指针
			// 就肯定为空了,还有另一种情况,出队列指针永远指向一个空的元素空间。这样就要是出队指针+1==进队指针
			return front + 1 == rear;
		}

		@Override
		public void clear() {
			// TODO Auto-generated method stub
			// 清除数据
			// 进队指针==0;出队指针==0;数据长度==0;这样就清零了
			front = 0;
			rear = 0;
			size = 0;
		}
		

		@Override
		public void enqueue(E e) {
			// TODO Auto-generated method stub
			// 入队 1.容量判断
			
			if (size>(data.length * 0.7)) {
				// 当数组中元素个数大于等于数组容量的7%时,我们就要进行扩容了
				resize((int)(data.length-1) * 2);// 定义一个扩容方法
			}

			data[rear] = e;// 将传进来的参数赋给进队指针rear的空间。因为我们的进队指针和出队指针同时指向0;所以只需将进队指针+1
			rear++; // 进队指针++
			size++; // 元素个数++;
		}

		@Override
		public E dequeue() {
			// TODO Auto-generated method stub
			// 出队 依照出队规则 我们需要将第一个进来的数据返回出去 需要进行缩容判断
			if (size <(data.length/4)) {
				System.out.println("進入縮容方法");
				resize((data.length/2));
			}

			front++;
			size--;
			return data[front]; // 返回出去后,我们的出队指针就要指向第二个进队的元素 所以front++;

		}

		@Override
		public E getFront() {
			// TODO Auto-generated method stub
			// 获取队首元素 不删除 在出队与入队过程中,我们的指针是变化的所以直接返回出队指针即可 进行非空验证
			if (isEmpty()) {
				throw new NullPointerException("队列为空");
			}
			return data[front];
		}

		@Override
		public E getRear() {
			// TODO Auto-generated method stub
			// 获取队尾元素 不删除 与取队首原理相同,直接取队尾的元素,记得减一 因为我们的队尾指针指向的是一个空元素
			return data[rear - 1];

		}
		
		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){
					sb.append(data[i]);
					if((i+1)%data.length==rear){
						
						sb.append(']');
						
					}else{
					
						sb.append(',');
					}
				}
			}
			return sb.toString();
		}
		


}

简单的实现这几个方法,如果还需要实现什么方法可以自己加。纯手打,有错欢迎批评指正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值