我们在学习的阶段时,对一些数据结构的概念、用法,比如:队列。总是不那么熟悉,相信大部分初学者都感同身受,所以在此,我向大家分享一下自己如何将队列的概念、用法融汇贯通的。
对于数据结构中队列的学习,我认为可以分三个阶段:
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; } }