我试图用一维数组来表示队列。我知道人们可能会建议我通过使用列表甚至是默认的java队列对象来获得更轻松的时间,但我在这里学习,所以我不想求助于这样简单的解决方案。到目前为止,我遇到了一些实施问题:
E.g。 QueueArray - > [],[A],[B] 移动它,使它最终像这样:QueueArray - > [A],[B],[]
现在听我说,问题1#。 我的逻辑思维告诉我以某种方式增加队列数组的大小以便能够接收更多的对象,事情是我不知道怎么做而不将所有对象保存到另一个临时数组然后将它们复制到一个新的数组更大的数组。我甚至不确定这是否是一种合理可行的方法来实现这一点。
问题2# 我想可能只是检查队列数组中的空对象,如果找到它们,只需将元素移动一个索引。
这是我的代码,我也对其他改进持开放态度。
import java.util.Scanner;
public class Queue {
Object[] q;
int head, tail;
Scanner in;
public Queue(int size){
q = new Object[size];
menu();
}
public void menu(){
System.out.println("\t");
System.out.println("1. add(x) - Adds the object x to end of the queue");
System.out.println("2. remove() - Removes the first object in the queue");
System.out.println("3. view - Shows contents in queue");
System.out.println("4. exit - Exits program");
System.out.println("Select your operation:"+"\t");
while(true){
in = new Scanner(System.in);
int userInput = in.nextInt();
if(userInput == 1){
System.out.println("Give value of object");
in = new Scanner(System.in);
Object userIn = in.next();
add(userIn);
menu();
}
if(userInput == 2){
remove();
menu();
}
if(userInput == 3){
peek();
menu();
}
if(userInput == 4){
System.exit(0);
}
}
}
// Adds the object to the end of the queue
Object add(Object letter){
// If the queue is not full, add to back of queue
if(tail >= q.length){
System.out.println("Queue is full");
return null;
} else {
q[tail] = letter;
tail++;
}
return tail;
}
// Removes the first object in the queue
Object remove(){
if(q.length == 0){
return null;
} else {
q[head] = null;
head++;
}
return head;
}
// Returns the head, tail and all other objects in the queue
void peek(){
System.out.println("Head: "+q[head]);
System.out.println("Tail: "+q[tail-1]);
System.out.println(q[0]+", "+q[1]+", "+q[2]+", "+q[3]+", "+q[4]+".");
}
public static void main(String[] args){
new Queue(5);
}
}
答案 0 :(得分:2)
在内部,我相信大多数Java列表对象在某些时候实际上只有一个不可变的数组,这就是你遇到的。
他们做什么来调整大小,然后达到一个完整的%阈值(比如75%),他们将创建一个大小翻倍的新数组。因此,如果您有一个4项数组,并插入了三个项目,该结构将在内部将其存储阵列更新为大小为8,并在有6个项目时再次执行此操作。
就实际副本而言,请查看System.arraycopy,它允许您指定源和目标数组。
就转移而言,为什么转变?为什么不保持指向当前索引的指针?
例如,看看这个操作链......
队列对象,队列对象,出列对象,队列对象。
您的结构可能看起来像
[,,,] - head at 0, tail at 0
[obj1,,,] - head at 0, tail at 1
[obj1,obj2,,] - head at 0, tail at 1
[obj1,obj2,,] - head at 1, tail at 1
[obj1,obj2,obj3,] - head at 1, tail at 2
[obj1,obj2,obj3,] - head at 2, tail at 2
使用此方法,并且如其他答案所述,您还可以包装索引以查找仍可用的元素。在上面的示例中,如果您添加了两个元素,因为前两个元素已不再使用,您可以开始用新元素替换它们。
显然,当足够的对象没有出列以允许更多的队列排队时,你仍然需要处理调整大小。
答案 1 :(得分:2)
所以,你是正确的,有些数据结构完全符合你的要求,但由于这更像是一个练习而不是应用,所以这就是我所说的。
#1
将整个 n -length数组复制到 n + 1-length数组的解决方案可行。但是还有另外两种方法可以做到这一点,这些方法通常都是使用的,这两种方法都不涉及复制整个数组。
第一种是在创建队列时预先分配最大大小。这与您在C中为数组预先分配内存的方式类似。这是迄今为止最简单的3种解决方案,而且速度最快。
我要指出,如果你使用这个解决方案,你会经常看到用于实现队列的所谓“循环缓冲区”或“环形缓冲区”[1]。您应该阅读有关此主题的链接文章。
第二种是使用某种链表[2],而不是仅存储值,而是存储(值,下一地址)对。然后,您可以动态添加项目。但是用Java做这件事非常困难。链接的文章提供了有关链接列表的更多信息。
#2
不要转移。 根据队列的大小和元素的大小,可能需要更长的时间 - 转移 < em> O (n) - 如果您不知道这意味着什么,请参阅[3]。
不使用移位,而是使用循环缓冲区[1]。跟踪头部和尾部(或头部和大小)。
如果您使用环形缓冲区执行此类操作,则 O (1) - 更好。
<强>除了强>
在我看来,了解数据结构非常重要,所以很好。但是(同样,我的观点)像Java这样的语言使得理解数据结构的基础知识比比如C或C ++更难。请注意,并非不可能,但Java的托管内存方面混淆了C不具备的一些更精细的数据结构实现点。如果确实想要理解这些数据结构,我强烈建议在某些时候在C / C ++中实现它们,只是为了看看它是什么以及它是如何工作的。
[1] http://en.wikipedia.org/wiki/Circular_buffer
[2] http://en.wikipedia.org/wiki/Linked_list
[3] http://en.wikipedia.org/wiki/Big_O_notation