定义一个通用的存储数据的结构,使用时只需更改传入对象的类型就好。这样一个用来存储数据的通用结构就是队列,队列中一般有几种基本的方法:数据对象的添加、插入、删除、获取、队列长度的获取。
有两种基本的实现队列的方法: 用数组实现的队列和用链表实现的队列。
一、用数组实现的队列
1、如何用数组实现队列
用数组实现的队列实质上就是用队列包装了的数组。在队列中还是用一个数组来存储信息,并定义了几个队数组进行基本操作(添加、获取数组元素、数组长度)的方法。
现在假设要定义一个用来存储在画布上画直线信息的队列。那么首先要定义一个直线信息类MyLine,类中有四个属性,即直线的起点终点坐标,以及设置和获取四个属性的方法。
然后要定义一个队列类MyQueue。在队列类中应该有一个存储信息的数组str,由于用户需求的不确定性,一个确定长度的数组肯定是不能满足要求的,所以我们应该使这个数组的长度“可变”。在“添加”方法中,可以这样来实现数组长度的可变性:将数组的初始长度设为0,在方法中新建一个长度比原数组长度大1的数组;将要添加的数据放在新数组的最后一位;遍历原数组,将原数组中数据复制到新数组中;使str指向新数组。这样,每新增一个数组元素,数组长度就加1。能够满足用户的存储要求,同时有不浪费空间。
最后,可以建立一个测试类,对队列功能进行测试。
队列类的具体代码如下:
/** * 用数组实现的队列类 */ public class MyQueue { MyLine myl; private MyLine[] str = new MyLine[0]; /** * 添加直线信息的方法 * @param myl 接收的MyLine类对象 */ public void add(MyLine myl){ //1、创建一个临时数组,它的长度是str的长度加1 MyLine[] str2 = new MyLine[str.length +1]; //2、将接收的ml对象添加到新数组的最后一位 str2[str.length] = myl; //3、将原数组中的信息复制到新数组中 for(int i=0;i<str.length;i++){ str2[i]=str[i]; } //4、使原数组指向新数组 str=str2; } /** * 获得第index位的数组元素的方法 * @param index 指定的位数 * @return 第index位的数组元素信息 */ public MyLine get(int index){ MyLine myl =str[index]; return myl; } /** * 获得队列的长度的方法 * @return 队列长度数值 */ public int size(){ return str.length; } }
2、数组队列的优化
现在,我们已经建立一个数组队列。那么,这个队列是否就是最优队列了呢?
显然不是的,这个队列就有两个明显的缺点:
(1) 数组只能接收MyLine类型的对象。
(2) 每次添加数组元素都要新建一个数组,并把原数组中的数据复制到新数组中,这样不仅浪费内存空间,还延长了执行时间。
(3) 队列中缺少插入和删除的方法。
要解决第一个问题,需要先要理解一个概念:泛型。
所谓泛型,其实就是使一个类中的方法可以接收各种类型的对象,只需在实例化该类是进行指定就行。实现方式为:在类名后加上“<E>”。
定义:public class 类名<E>{}
实例化:类名<要接收的对象类型> 对象名 = new类名<要接收的对象类型>();
要解决第二个问题,可以为数组设置一个初始长度(比如说100),当数组中存满100个数组元素后,新建一个比原数组长10的数组取代原数组。这样,添加前100个数组元素就不用新建数组了。
这样改之后又有一个问题了,用户的需求不同,偏好的数组初始长度和每次增加的长度也不同。为使用户根据自己的需求更改设置,我们可以重载构造方法来设置这两个值。
优化后的数组队列类代码如下:
/** * 队列类,存放数组元素信息(优化后的数组队列) */ public class MyQueue<E> { private int sLength; //数组初始长度 private short inLength; //数组每次增加长度 private int count = 0; //计数器,数值为数组当前长度 private Object[] str; /** * 重载的构造方法,由使用者决定sLength和inLength; * @param sLength 数组初始长度 * @param inLength 数组每次增加的长度 */ public MyQueue(int sLength, short inLength) { this.sLength = sLength; this.inLength = inLength; str = new Object[sLength]; } /** * 重载的构造方法,有使用者决定sLength值,inLength值默认 * @param sLength 数组初始长度 */ public MyQueue(int sLength) { this(sLength, (short) 10); } /** * 重载的构造方法,由使用者决定inLength值,sLength值默认 * @param inLength 数组每次增加的长度 */ public MyQueue(short inLength) { this(100, inLength); } /** * 无参构造器,使用默认的inLength和sLength值 */ public MyQueue() { this(100, (short) 10); } /** * 添加数组元素的方法 * @param e 接受的数组元素对象 */ public void add(E e){ if(count<sLength){ str[count]=e; count++; }else if(count>=sLength){ //1、创建一个临时数组,它的长度是str的长度加inLength Object[] str2 = new Object[str.length +inLength]; //2、将接收的ml对象添加到新数组的最后一位 str2[count] = e; //3、将原数组中的信息复制到新数组中 for(int i=0;i<count;i++) str2[i]=str[i]; //4、使原数组指向新数组 str=str2; count++; } } /** * 获得第index位的数组元素 * @param index 指定的位数 * @return 第index位的数组元素信息 */ public E get(int index) { E e = (E)str[index]; return e; } /** * 将新元素插入到给定的index位置上,原index位置及之后的元素向后移一位 * @param e 要插入的元素 * @param index 插入的位置 */ public void insert(E e,int index){ if(index<0||index>=str.length){ System.out.println("超出数组范围"); }else if(index>=count){ System.out.println("插入的为空区"); }else if(count<str.length){ for(int i=count-1;i>=index;i--) str[i+1]=str[i]; str[index]=e; count++; }else if(count==str.length){ Object[] str3=new Object[str.length +inLength]; for(int i=0;i<index;i++) str3[i]=str[i]; str3[index]=e; for(int i=index;i<count;i++) str3[i+1]=str[i]; str=str3; count++; } } /** * 删除指定位置的数组元素 * @param index 要删除的数组元素位置 * @return 被删除的数组元素 */ public E remove(int index){ if(index<0||index>=str.length){ System.out.println("超出数组范围"); }else if(index>=count){ System.out.println("删除的为空区"); }else if(index<count){ E e =(E)str[index]; for(int i=index;i<count-1;i++) str[i]=str[i+1]; count--; return e; } return null; } /** * 获得队列的长度 * * @return 队列长度数值 */ public int size() { return count; } }
二、用链表实现的队列
在C语言中,链表是一种数据结构。以单链表为例,单链表即由若干物理上不相连的结点链接而成的表,每个结点有一个数据域和一个指针域,数据域中存储要放置的数据,指针域中的指针指向下个结点的存储地址。
在这里我们还是沿用C语言中的定义。要用链表实现队列,首先要定义一个结点类ListNode,其中包括它的数据域和指针域。具体代码如下:
/** * 结点类,定义结点数据域和指针域 */ public class ListNode { private Object obj; private ListNode next; //重载构造方法,初始化数据域的值 public ListNode(Object obj){ this.obj=obj; } /** * 设置数据域的值 * @param obj */ public void setObj(Object obj){ this.obj=obj; } /** * 获取数据域的值 * @return 数据域值 */ public Object getObj(){ return obj; } /** * 设置指针域指向 * @param next */ public void setNext(ListNode next){ this.next=next; } /** * 获得指针域指向 * @return 指针域指向的结点 */ public ListNode getNext(){ return next; } }
这之后,我们就可以建立链表队列类了。链表队列中的基本方法与数字队列一样,只是因结构不同,各个方法内部的实现不同。具体代码如下(以下代码中的方法还有别的实现方法有待探索):
/** * 用链表实现的队列类 */ public class SingleList { //定义头结点 ListNode head;; /** * 向链表中添加新的结点 * @param obj 新结点数据域值 */ public void add(Object obj) { //实例化一个要加入的新结点 ListNode node = new ListNode(obj); //判断头结点是否为空,若为空,则将新结点设为头结点 if (head == null) { head = node; } else { //若头结点非空,将新结点添加到链表最后 ListNode temp = head; //遍历链表,找到目前的最后一个结点 while (temp.getNext() != null) temp = temp.getNext(); //将新结点设为目前最后一个结点的下一个结点 temp.setNext(node); } } /** * 向链表中某位置插入新结点,插入后原位置及之后的结点向后移 * @param obj 新结点数据域值 * @param index 插入位置 */ public void insert(Object obj, int index) { int len = size(); ListNode node = new ListNode(obj); ListNode temp = head; //判断给出的位置是否超出队列范围 if (index < 0 || index >= len) { System.out.println("超出队列范围"); return; } //判断要插入的位置是否为第一个位置 if (index == 0) { //将头结点接到新结点后,并将新结点设为头结点 node.setNext(temp); head = node; } else { //遍历链表,寻找要插入结点的前一个结点 for (int i = 0; i < index-1; i++){ temp = temp.getNext(); } //在index位置插入新结点 node.setNext(temp.getNext()); temp.setNext(node); } } /** * 从链表中移除某位置的结点,移除后该位置之后的结点前移 * @param index 要移除结点的位置 * @return 移除的结点数据域的值 */ public Object remove(int index) { int len = size(); ListNode temp = head; ListNode curNode = head.getNext(); //判断给出的位置是否超出队列范围 if (index < 0 || index >= len) { System.out.println("超出队列范围"); return null; } //判断要移除的结点是否在第一个位置 if(index==0){ //若是,则将头结点的下一个结点设为新的头结点 head=head.getNext(); return temp.getObj(); } //遍历链表,最后curNode为要移除的结点,temp为要移除结点的前一个结点 for(int i=0;i<index-1;i++){ temp=curNode; curNode=curNode.getNext(); } //将temp直接与curNode的下一个结点相连 temp.setNext(curNode.getNext()); return curNode.getObj(); } /** * 获得某位置的结点的数据域值 * @param index 需获得结点的位置 * @return 结点的数据域值 */ public Object get(int index) { int len = size(); ListNode temp = head; //判断给出的位置是否超出队列范围 if (index < 0 || index >= len) { System.out.println("超出队列范围"); return null; } //遍历链表,获得index位置的结点 for (int i = 0; i < index; i++) temp = temp.getNext(); return temp.getObj(); } /** * 求链表长度 * @return 链表长度 */ public int size() { int length = 0; ListNode temp = head; while (temp != null) { temp = temp.getNext(); length++; } //System.out.println("length="+length); return length; } }
当然,链表队列中也可以用泛型。但是,要注意将结点类也用泛型表示。
相关推荐
数组实现队列时,通常使用两个指针,一个指向队首,另一个指向队尾。 2. **入队操作**:当有新元素加入队列时,通常在队尾进行插入。由于数组的固定大小,如果队列已满,需要考虑循环队列的概念,即队列的前后端相遇...
队列可以使用数组或链表实现,数组实现的队列可以快速地随机访问元素,而链表实现的队列可以快速地插入或删除元素。 栈是一种后进先出(Last-In-First-Out,LIFO)的数据结构,元素的添加和删除都是从栈顶进行的。...
"go语言通过数组和链表的方式实现队列" 从给定的文件信息中,我们可以生成以下知识点: 1.队列的定义:队列是一种特殊的线性表,只能在队列的尾部添加元素,在队列的头部删除元素,先进先出(FIFO)。 2.go语言中...
数组、链表、队列、栈数据结构特点,各自优点和缺点 在计算机科学中,数据结构是指用于组织和存储数据的方式。常见的数据结构包括数组、链表、队列、栈等。每种数据结构都有其特点、优点和缺点,本文将对这些数据...
本篇文章将深入探讨如何用数组和链表两种数据结构来实现队列。 ### 数组实现队列 数组实现队列的优势在于访问速度快,因为数组是连续存储的,可以通过下标直接访问元素。但数组的大小是固定的,所以在创建时需要...
本文将深入探讨如何使用C语言实现数组形链表,并详细讲解其相关接口。 首先,我们需要定义数组形链表的数据结构。它通常包含一个数组,用于存储元素,以及一个指示当前数组容量的变量。当数组满时,我们可以通过...
队列是一种特殊的线性表,它只允许在表的前端(front)进行删除操作,只允许在表的后端(rear)进行插入操作,下面介绍一下java使用数组和链表实现队列的示例
与基于数组的实现相比,链表中的元素在逻辑上是相邻的,但在物理位置上不一定相邻。这使得链表具有更高的灵活性,特别是在插入和删除操作方面: - **插入和删除操作**:链表可以在O(1)的时间内完成插入或删除操作,...
数据结构-数组&链表&队列&堆栈代码示例,附有详细的注释说明,简单移动,适合初学者参考学习。
队列可以使用数组或者链表来实现,队列的应用场景非常广泛,如购物队列、打印队列等。 线性表是具有n个数据元素的有限序列,線性表的数据元素可以由若干个数据项组成。線性表有顺序存储结构和非顺序存储结构两种...
arithmetic java算法冒泡排序、二叉树、数组、链表、队列学习简单示例 private static void mpSoft(String [] data) { for (int i = 0; i ; i++) { System.out.println(Arrays.toString(data)); for (int j = 0; ...
在C++中,循环队列可以使用数组或者链表来实现,这两种方式各有优缺点。下面我们将详细探讨这两种实现方式及其基本功能。 首先,我们来看数组实现的循环队列。数组是最基础的数据结构,它的优点是访问速度快,空间...
经过一上午的学习,对数据结构有了新的认识和理解 数组 数组是由有限个相同类型的变量所组成的有序集合,...栈是一种线性逻辑结构,可以使用数组实现,也可以使用链表实现。包含入栈还有出栈操作,遵循先入后出的原则(F
常见的数据结构(栈、队列、数组、链表和红黑树) 数组和链表.pdf
超级数组和链表及栈队列
在编程语言中,数组通常被内置支持,易于理解和使用,而链表则通常需要通过指针和结构体等概念来实现,相对复杂。但考虑到其灵活性,链表在处理动态数据集时显得尤为有用。 总结来说,选择数组还是链表主要取决于...
为了优化算法,还可以使用栈或队列来辅助处理,例如,将被淘汰的节点放入栈中,以避免在主循环中频繁修改链表结构。 总的来说,约瑟夫环问题的解决体现了数据结构和算法的巧妙结合,它不仅考察了基本的数据结构操作...
在 Java 中,LinkedList 的内部使用双端链表队列原理实现,而 ArrayList 的内部使用双端数组队列原理实现。 Java 实现自定义双端队列可以通过链表和数组两种方式实现,双端队列可以充当单端队列,也可以用于充当栈...
在计算机科学中,数据结构是组织、存储和处理数据的方式,它们是算法设计的基础。...在实际编程中,Java提供了ArrayList和LinkedList两种内置的列表实现,分别基于数组和链表,可以根据需要选择使用。