1

一直在用 Java 做这个项目。建议我为我的程序使用链接列表或数组列表,这非常有意义。然而,教授说我们必须利用节点制作和使用我们自己的链表。尽管在课堂上进行了一些研究和询问,但使用 Nodes 让我非常困惑。我确定这是我缺少的一些简单的东西,但我现在完全不知所措。这是存储列表的类(我认为)。之所以命名为 Aircraft,是因为我们正在创建一个列表来存储多架飞机以及与它们相关的一些详细信息(航班名称、速度、高度、飞机类型)。我有一个用户与之交互的 Main 类(未列出) - 我已经处理了该类。

package airTraffic;

public class Aircraft  {

public static String name;
public static String type;
public static int speed;
public static int alt;

Aircraft nextCraft;

public Aircraft (String n, String t, int s, int a) {
    name = n;
    type = t;
    speed = s;
    alt = a;
}

public Aircraft() {

}

public static void setName(String n) {
    name = n;
}

public static String getName (String lookUp) {
    return name;
}

public static void removeName () {
    //remove the flight - not sure what to place here
}

public static void setType (String t) {
    type = t;
}

public static String getType () {
    return type;
}

public static void setSpeed (int s) {
    speed = s;
}

public static int getSpeed () {
    return speed;
}

public static void setAlt(int a) {
    alt = a;
}

public static int getAlt () {
    return alt;
}

public Aircraft next = null;

//auto generated method from ATControl 
public static void add(String s) {

}

//auto generated methods from ATControl - what goes here???
public static void remove() {

}

public Object getNext() {
    // TODO Auto-generated method stub
    return null;
}

public void setNext(Object next2) {
    // TODO Auto-generated method stub

}
 }

下面,我有我认为是创建和存储节点的类。这是我非常困惑并认为我错了的地方。我不确定如何调用节点来实际添加和存储数据。我还需要能够获取节点(通过航班名称)并删除节点(通过航班名称)

package airTraffic;

import java.util.*;
import airTraffic.Aircraft;

public class ATControl {


static Main m = new Main ();
Aircraft aircraft = new Aircraft ();

//declare node names for list
public static Aircraft head = new Aircraft ();
public static Aircraft tail = new Aircraft ();

// stores data
private static final int INITIAL_ALLOCATION = 20;
private static int size = INITIAL_ALLOCATION; 

// tells list to add nodes
public static void Nodes (String s, int n) {
    n = size;
    head.next = tail;
    tail.next = tail;
    Aircraft temp = head;
    for (int i= 0; i < size; ++i) {
        temp.next = new Aircraft ();
        temp = temp.next;
    }
    temp.next = tail;
}

public static void addNodes (int n) {
    n = size;
    Aircraft temp = new Aircraft ();
    Aircraft current = head;
    for (int i = 1; i < n && current.getNext() != null; i++) {
        current = (Aircraft) current.getNext();
        temp.setNext(current.getNext());
        current.setNext (temp);
        size++;
    }
}

//add plane and details
public static void addToList (Scanner in) {
    // should add new aircraft to new node on linked list
    System.out.printf("Enter flight number: ");
    String add = in.next();
    Aircraft.setName (add);
    ATControl.addNodes (Integer.parseInt(add));

    //type of plane
    System.out.printf("Enter type of plane: ");
    String plane = in.next();
    Aircraft.setType (plane);

    //plane speed
    System.out.printf("Enter current speed: ");
    int speed = in.nextInt();
    Aircraft.setSpeed (speed);
    ATControl.addNodes (Integer.parseInt(add));


    //add Altitude 
    System.out.printf("Enter current altitude: ");
    int alt = in.nextInt();
    Aircraft.setAlt(alt);
    ATControl.addNodes (Integer.parseInt(add));  // I am fairly certain this is wrong
}

//show flight
public static void showFlight (Scanner in) {
    System.out.printf("Enter flight number for details: ");
    String lookUp = in.next();
    Aircraft.getName(lookUp);

}
// display all flights
public static void displayAll (Scanner in) {
    System.out.printf("All flights: " );

}
//remove flight
public static void removeFlight (Scanner in) {
    System.out.printf("Enter flight number to be removed: ");

}
}
4

5 回答 5

2

你越来越近了。首先,链表是对象的列表,通常称为节点,每个节点都有一个或多个指向其他对象的链接。在您的情况下,节点是飞机。

这应该对您有所帮助:Wikipedia:Linked List

到目前为止,您的主要问题是您的飞机类中没有链接。由于这是一个链接列表,因此您需要包含对列表中下一个元素的引用。在 Aircraft 类中,您应该有一个名为nextAircraft 类型的属性,它将您链接到列表中的下一个 Aircraft。这允许您调用myAircraft.next,就像您目前在代码中一样,这将允许您按顺序在列表中移动。我会让你自己弄清楚其余的,这是家庭作业,但如果你需要更多解释,请随时发表评论。

于 2012-08-01T02:57:47.317 回答
1

我认为您非常接近 - 但很难准确地说出您的 ATControl 课程中发生了什么。通常,链表上的 add 方法采用节点(在您的情况下为 Aircraft),而不是数字。

链表的关键是每个节点都有一个指向链表中下一个节点的指针。在您的 Aircraft 类中,您有: Aircraft next,它将用作该指针。

我建议在 ATControl 中实现以下方法:

public static Aircraft getUserInput(Scanner in)
{
  Aircraft aircraft = new Aircraft();

  // get your values from the user and set them in your new aircraft
  return aircraft;
}

public static void add(Aircraft aircraft) 
{
  // starting at head, walk through the list (repeatedly call next on 
  // the current Aircraft) until you reach the desired position 

  Aircraft temp = head;

  while (temp != null) // ...
}

public static void remove(String flightNum)
{
  // again, the same way you did in add, walk through the list until you find it
    if (current.getName().equals(flightNum))
      // we found it, so remove it
}
于 2012-08-01T02:47:25.343 回答
1

除非您对 OOP 和引用类型有非常牢固的掌握,否则尝试编写 LinkedList 实现是一种自虐实践。

以下将是漫长的,可能是痛苦/羞辱的。没关系,这将是一次很好的学习经历。我为此付出了很多努力,以提供带有详尽评论的完整实现。我建议你仔细阅读细节,直到你完全理解它们的目的。

首先,修复你的飞机等级。由于您需要创建多个实例,因此静态成员将不起作用。如果您不明白为什么,请花一些时间来复习您的 OOP 基础知识。

列表节点应设计为存储最少的数据。在你的情况下,看起来你大部分时间都在那里。每个节点都有特定的航班数据以及对列表中下一项的引用。这就是你所需要的。

没有所有多余的东西,这就是它的样子:

public class Aircraft  {
    public String name;
    public String type;
    public int speed;
    public int alt;
    Aircraft next;

    public Aircraft (String n, String t, int s, int a) {
        name = n;
        type = t;
        speed = s;
        alt = a;
        next = null;
    }
}

看起来不错。可以安全地假设它内置了所有必要的功能。

如果需要,请随时添加以下内容:

  • 设置名称()
  • 获取名称()
  • 设置类型()
  • 获取类型()
  • 设置速度()
  • 获取速度()
  • 设置Alt()
  • 获取Alt()

注意:这些仅在未设置为静态时才有效。除非您打算在每次调用时将被更改的Aircraft实例作为参数之一传递。相信我,使用实例方法要容易得多。

变化:

  • 我删除了Aircraft()构造函数。至少,您需要使用至少一个航班号(或其他一些唯一标识符)来初始化一个Aircraft节点,否则您以后将无法在列表中找到该 Aircraft。

  • removeName()没用。由于各个节点只知道列表中的下一项,因此它们无法删除自己。如果您使用双向链表,其中每个节点都存储对一个节点和下一个节点的引用,那么这是可能的,但实际上没有必要。add()remove()* 方法也是如此。添加/删除在 **ATControl类中处理。

  • 也不需要getNext()setNext()。由于ATControl用于维护列表的状态(例如大小、容量等),因此您不会希望通过 getter/setter 公开访问nextCraft 。

现在对于 ATControl:

public class ATControl {
    private Aircraft head; // stores the start of the chain
    private Aircraft tail; // stores the end of the chain
    private int size; // stores the length of the chain

    public ATControl() {
        // ♫ "Started from the bottom now we're herre' ♫
        // Seriously, the list should start with nothing
        head = null;
        tail = null;
        size = 0;
    }

    public void addFlight(String flight, String plane, int speed, int alt) {
        // TODO: Implement this
    }

    public void removeFlight(String name) {
        // TODO: Implement this 
    }

    public void displayFlight(String name) {
        // TODO: Use a foreach loop to find and display a flight
    }

    public void displayAll() {
        // TODO: Use a foreach loop to display the flights here
    }
}

变化:

  • 我删除了main* 成员,因为我不知道它在这里是如何工作的。无论哪种方式,要使用它,您都需要创建一个新的 **ATControl实例。

  • 我删除了内联变量声明,因为必须在构造函数中设置实例成员。

  • 头部和尾部被初始化空,因为还没有添加任何飞机

  • 我删除了飞机成员,因为它永远不会被使用。

  • 除非您只希望创建一个ATControl实例,否则您也不应该将headtail设置得太静态。如果它们中的任何一个被除 ATControl 之外的任何东西更改,它将搞砸列表的内部状态,因此它们应该设置为私有。

  • 我删除了大小限制,因为没有必要进行这项工作。如果需要,您可以稍后再添加。

  • 我取消Nodes()addNodes()有两个原因。首先,它都违反了 SRP(单一责任原则),因为它们负责创建节点和节点集合。第二——我假设这是一个错误,但是——您将航班号作为您想要创建的节点数传递。例如,如果航班号为 1457,您将向列表中添加 1457 个空节点。

  • 我将 addToList() 重命名为addFlight ()以保持一致。为了保持一致性,我还将showFlight()重命名为displayFlight()。为了简单起见并使这个类不仅仅对命令行输入有用,我还删除了用户输入部分。


我知道我知道!我是一个无情的屠夫,但现在代码可以开始构建必要的功能了。

第一件事。如果您不知道如何让一个类可迭代(即作为一个 foreach 循环工作),您很快就会发现。我需要向ATControl添加更多内容,但这会很有趣。

public class ATControl implements Iterable {
    private Aircraft head;
    private Aircraft tail;
    private int size;

    public ATControl() {
        head = null;
        tail = null;
        size = 0;
    }

    public void addFlight(String flight, String plane, int speed, int alt) {
        // if the list is not currently empty
        if (!isEmpty()) {
            // store a reference to the last Aircraft in the list
            Aircraft prev = tail;
            // create a new aircraft and add it to the end of the list  
            tail = new Aircraft(flight, plane, speed, alt);
            // link the old tail to the new tail
            prev.next = tail;
        }
        // an empty list needs to be handled a little differently
        else {
            // notice, with no tail there's no tail to update
            tail = new Aircraft(flight, plane, speed, alt);
            // also, since there's only one item the head and tail are the same
            head = tail;
        }
        size++;
    }

    // The hard part. Lots of nasty edge cases.
    // Creating one of these from scratch will make your head hurt.
    // Note: Setting variables to null marks them for the garbage collector.
    // SideNote: With a doubly-linked list you can do removals within a foreach loop
    public void removeFlight(String flight) {
        Node prev = head;
        Node curr = head;
        // crawl the list looking for a match
        while (curr.next != null || curr == tail) {
            if (curr.flight.equals(flight)) {
                // if there is only one item left, null everything
                if (size == 1) { head = null; tail = null; }
                // reset the head to start at the second Aircraft
                else if (curr.equals(head)) { head = head.next; }
                // reset the tail to end at the 2nd-to-last Aircraft
                else if (curr.equals(tail)) { tail = prev; tail.next = null; }
                // if it's in the middle, re-connect the broken links on either end
                else { prev.next = curr.next; }
                size--;
                break;
            }
            prev = curr;
            curr = prev.next;
        }
    }

    public boolean isEmpty() {
        return size == 0; // only returns true if size is 0

    // The fun part. The following are necessary to make the list iterable
    // Like magic, this class will now be callable as a foreach loop
    public Iterator<Aircraft> iterator() { return new ATCIterator(); }

    // This iterator code can be reused on any linked-list implementation
    // Keep this handy in case you need to implement Iterable in the future
    private class ATCIterator implements Iterator<Aircraft> {
        private Aircraft current = head;

        public Aircraft next() {
            if (!hasNext()) { throw new NoSuchElementException(); }
            Aircraft aircraft = current;
            current = current.next;
            return aircraft;
        }

        public boolean hasNext() { return current != null; }

        // inline removals require a doubly linked list. To reconnect the break 
        // in the chain the node has to be aware of both the previous and next nodes.
        public void remove() { throw new UnsupportedOperationException(); }
    }

    // lets put that foreach loop functionality to good use now.

    // Bonus: use this to retrieve the matching Aircraft instance
    // Once you have a reference to the Aircraft instance you can do things like
    // get/set it's internal values.
    public aircraft getFlight(String flight) {
        for (Aircraft aircraft : this)
            if (this.flight == flight) {
                return this;
    }


    // displays the flight number of the first match
    public void displayFlight(String flight) {
        for (Aircraft aircraft : this)
            if (this.flight == flight) {
                System.out.printf("Flight: " + flight);
                // Note: you can access the Aircraft details here via the 'this' keyword
                return;
    }

    // crawls the whole list and displays the flight number of every aircraft
    public void displayAll() {
        for (Aircraft aircraft : this)
            System.out.printf("Flight: " + flight);
            // Note: you can access the flight details here via the 'this' keyword
    }
}

所以,你有一堵代码墙,里面有很多注释要咀嚼。是时候讨论一些理论了。

是什么让 LinkedList 成为 LinkedList 呢?

它实际上只是一堆随机放置在堆上并通过引用(或 C 人群的指针)链接在一起的对象实例。

将 LinkedList 想象为Samba Line

桑巴线

资料来源:旅行之眼博客

注意:双向链表是一样的,只是行可以改变方向。

每个人都紧紧抓住前面的人,却看不到后面的人。添加到列表就像将一个人添加到队列的前面。从技术上讲,我编写的 LinkedList 以相反的方向工作,将添加添加到前面并从尾部删除删除,但概念是相同的。

从列表中获取/删除一个项目就像添加一个冰柱。第一次击中从链条中取出,并通过重新连接断裂的末端来修复断裂。

使用 LinkedList 的好处是它可以根据需要变大或变小。您可以随意添加/删除节点。

缺点是,与数组不同,如果不先遍历链接链,就无法从列表中获取项目。此外,当列表变得非常大时,所有这些类实例和引用的开销开始变得昂贵。

在性能方面,添加项目需要 O(1)(即恒定时间)。O(N)(即线性时间)从列表中获取/删除项目。而且,根据列表是单/双和/或跳转链接,存在显着的内存开销。

还有其他数据结构,如 ArrayLists、HashMaps 等,它们对于像您这样的用例具有更好的性能或内存特性,但它们的编写/管理更加复杂。

无需工作即可获得高级数据结构的所有神奇优点的最简单方法是包装和扩展现有实现。例如,您可以创建一个在内部使用 ArrayList 进行数据存储的类。您甚至可以使用我上面演示的方法使其可迭代。除了为任何通用类型编写之外,它可以自定义为使用您的飞机数据类型。

注意:如果您想学习如何编写数据结构,我建议您在线(或以其他方式)参加 Algorithms I 课程。

于 2014-02-24T09:02:42.127 回答
0

这是回复者在说列表时所指内容的链接。这是一个解释列表的链接http://www.algolist.net/Data_structures/Singly-linked_list/Traversal 。但是,我不确定这在 java 中是否具有代表性。您编写的代码看起来不是在排序,而是在列表末尾添加所有飞机。因此列表没有排序。当您使 temp.next = tail 使列表中的最后一架飞机指向自身而不是 null 时。但是您不是在检查空值,而是在计算列表中的飞机数量。我发布了一个 java 示例,其中你有一个节点类,下一个节点,你应该添加节点尾部,因为你的代码正在使用它。

于 2012-08-01T04:09:48.750 回答
0

公共类节点{

   public int item;
   public Node next;
   public Node tail;


   Node() {                 
      item = 0; 
      next = null; 
       tail = null ;    
   } 

   Add Node(node tail, node new) {

      tail.next = new;
        tail.tail = new
        new.tail =null

   }

};

我希望我没有让事情变得更糟。祝你好运。

飞机类可以扩展节点类。看看java中的childfactory类。它将为您提供将在节点类中使用的方法类型的示例。重新考虑你的课程。也许 remove Airplane 将是节点类中的一个方法,如删除节点。任何在节点上工作的东西,例如插入或添加新、删除和排序都可以添加到节点类中。然后,您可以在添加更多类时重用此类。

http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html

于 2012-08-01T02:14:34.450 回答