如何理解队列?

我们在学习的阶段时,对一些数据结构的概念、用法,比如:队列。总是不那么熟悉,相信大部分初学者都感同身受,所以在此,我向大家分享一下自己如何将队列的概念、用法融汇贯通的。

对于数据结构中队列的学习,我认为可以分三个阶段:

1.字面理解阶段:

    队列(Queue)是只允许在一端进行插入,而在另一端进行删除的运算受限的线性表。

       (1)允许删除的一端称为队头(head)。
  (2)允许插入的一端称为队尾(last)。
  (3)当队列中没有元素时称为空队列。
  (4)队列亦称作先进先出(First In First Out)的线性表,简称为FIFO表。
     队列的修改是依先进先出的原则进行的。新来的成员总是加入队尾(即不允许"加塞"),每次离开的成员总是队列头上的(不允许中途离队[不能插队]),即当前"最老的"成员离队。
 【例】在队列中依次加入元素a1,a2,…,an之后,a1是队头元素,an是队尾元素。退出队列的次序只能是a1,a2,…,an

图例:

 

2、画图理解阶段与3、实现理解阶段

   1)先确定存储数据的容器。

      a、基于数组

//定义一个储存数据的数组,初始化长度为0
Object[] src = new Object[0];

      b、基于链表

/**
 * 链式结构内部结点类,双链表
 * 
 * @author Administrator
 *
 */
class SNODE<E> {
	// 内容
	E data;
	// 对下一个结点的引用
	SNODE<E> netx = null;
	// 对下一个结点的引用
	SNODE<E> front = null;
	//空的构造函数,用于构造空值的结点
	public SNODE() {
	}
	//构造有值的结点
	public SNODE(E e) {
		data = e;
	}
}


	//定义一个储存数据的链表,头结点初始值为null
	public SNODE<E> head = null;
	//尾结点初始值为null
	private SNODE<E> last = null;
	//定义一个变量保存栈的长度
	private int num = 0;

   2)增加操作

      a、基于数组

图例:


图例解析:将数组src全部复制到数组dest中,再将新数据添到数组dest的最后一位,最后将数组dest赋予数组src,还原数组。
 

	/**
	 * 将数据压入队列
	 * @param e 压入数据
	 */
	public void put(E e){
		//新建一个临时数组dest,长度比数组src大1
		Object[] dest = new Object[src.length+1];
		//将增加的数据添到数组dest的末尾
		dest[src.length]=e;
		//将数组src的数据复制到数组dest中
		System.arraycopy(src, 0, dest, 0, src.length);
		//将临时数组dest赋予数组src,还原数组src
		src=dest;		
	}

      b、基于链表

图例:



 

图例解析:先将尾节点last的next指向新结点node

               再将新结点node的front指向尾节点last

               再将尾节点last指向新结点node

	/**
	 * 将数据放入队列
	 * 
	 * @param e
	 *            放入数据
	 */
	public void put(E e) {
		//建立一个新结点node,值为e,默认无指向
		SNODE<E> node = new SNODE<E>(e);
		//如果栈内没有数据
		if (head == null) {
			//头结点指向新结点node
			head = node;
			//尾结点指向新结点node
			last = node;
			//node结点的front指向null
			node.front = null;
			//node结点的netx指向null
			node.netx = null;
		} else {
			//将尾节点last的netx指向新结点node
			last.netx=node;
			//新结点node的front指向last
			node.front = last;
			//新结点node的netx指向null
			node.netx=null;
			//尾节点last后移一位
			last = node;
		}
		//栈的长度+1
		num++;
	}

   3)删除操作

      a、基于数组

图例:

 

 

图例解析:将数组src从第二个全部复制到数组dest[下标从0开始]中,再将新数据赋予临时变量e,最后将数组dest赋予数组src,还原数组,返回输出e。
 

	/**
	 * 将队列底部数据弹出来
	 * @return 队列底部数据
	 */
	public E poll(){
		//新建一个临时数组dest,长度比数组src小1
		Object[] dest = new Object[src.length-1];
		//将数组src的数据复制到数组dest中,不包括数组src的第一个元素,其他的元素依次复制到数组dest对应位置
		System.arraycopy(src, 1, dest, 0, dest.length);
		//定义一个临时变量装数组src的第一个元素
		E e=(E)src[0];
		//将临时数组dest赋予数组src,还原数组src
		src=dest;
		//返回临时变量e
		return e;
	}

      b、基于链表

图例:


图例解析:先将新结点node指向头结点head

               再将头节点head指向新结点node的下一个结点

               再将旧头结点的next置为空,新头结点的front置为空,最后返回输出旧头结点的值               
 

	/**
	 * 将队列底部数据取出来
	 * 
	 * @return 队列底部数据
	 */
	public E poll() {
		//如果栈内有数据
		if (head.data!= null) {
			//建立一个新结点node,值为空,默认无指向
			SNODE<E> node = new SNODE<E>();
			// 将node指向头结点
			node = head;
			// 头结点head的指向移到下一个结点
			head = node.netx;
			// 旧头结点的指向关系为null
			node.netx = null;
   
			// 新头结点的指向关系为null

			head.front = null;
			//栈长度-1
			num--;
			//返回输出原队列顶部的数据
			return node.data;
		}
		//栈内没有数据就返回输出null
		return null;
	}

   4)判断队列是否为空

	/**
	 * 获得队列长度,基于链表实现[基于数组实现:num改成src.length]
	 * 
	 * @return 队列长度
	 */
	public int size() {
		//返回栈的长度
		return num;
	}

   5)获得队列长度

	/**
	 * 判断队列是否为空,基于链表实现[基于数组实现:num改成src.length]
	 * 
	 * @return true/false
	 */
	public boolean isEmpty() {
		//如果栈长度是0就返回false
		if (num == 0) {
			return true;
		} else {//否则就返回true
			return false;
		}
	}

 
 

猜你喜欢

转载自lqj2711.iteye.com/blog/2346017
今日推荐