帮助仅使用节点创建Java链接列表

时间:2012-08-01 01:06:45

标签: java data-structures linked-list

现在用Java工作了一段时间。建议我为我的程序使用链接列表或数组列表,这非常有意义。但是,教授说我们必须使用我们自己的链接列表来利用节点。尽管在课堂上进行了一些研究和询问,但使用Nodes让我非常困惑。我确信这是我想念的简单事情,但我现在完全失去了。这是存储List的类(我认为)。它的标题是飞机,因为我们正在创建一个列表来存储多架飞机以及与它们相关的一些细节(飞行名称,速度,高度,飞机类型)。我有一个用户与之交互的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: ");

}
}

5 个答案:

答案 0 :(得分:2)

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

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

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

答案 1 :(得分:1)

我认为你非常接近 - 但很难确切地说出你的ATControl课程究竟发生了什么。通常,链接列表上的添加方法需要一个节点(在您的情况下是一个飞机),而不是一个数字。

链表的关键是每个节点都有一个指向列表中下一个节点的指针。在你的飞机课程中,你有:飞机接下来,它将作为指针。

我建议在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
}

答案 2 :(得分:1)

除非你非常牢固地掌握OOP和引用类型,否则尝试编写LinkedList实现是受虐狂的一种做法。

以下是漫长的,可能是痛苦/羞辱。没关系,这将是一次很好的学习经历。我正在为此付出很多努力来提供完整的实施,并进行彻底的评论。我建议你仔细阅读细节,直到你完全理解他们的目的。

首先,修复 Aircraft 课程。由于您需要创建多个实例,因此静态成员无法工作。如果你不明白为什么,请花一些时间来了解你的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;
    }
}

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

如果您愿意,请随意添加以下内容:

  • 的setName()
  • 的getName()
  • 的setType()
  • 的getType()
  • setSpeed()
  • getSpeed()
  • setAlt()
  • getAlt()

注意:这些只有在未设置为静态时才有效。除非您计划每次调用时将 Aircraft 实例更改为其中一个参数。相信我,使用实例方法要容易得多。

<强>的变化:

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

  • removeName()无用。由于各个节点只知道列表中的下一个项目,因此无法自行删除。如果您使用双链接列表,其中每个节点都存储对之前的 next 节点的引用,那么它将是可能的,但实际上并不需要。 add() remove()*方法也是如此。添加/删除在** ATControl 类中处理。

  • getNext() setNext()也不太需要。由于 ATControl 用于维护列表的状态(除了大小,容量等),您不希望通过getter / setter公开访问 nextCraft 。< / p>

现在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
    }
}

<强>的变化:

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

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

  • head tail 初始化为null,因为尚未添加 Aircraft

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

  • 除非您只想创建一个 ATControl 实例,否则您不应将 head tail 设置为过于静态。如果他们中的任何一个被ATControl之外的任何东西改变了,它就会搞砸列表的内部状态,所以它们应该设置为私有状态。

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

  • 由于两个原因,我砍掉了节点() 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

Samba Line

来源:The Traveling Eye Blog

注意:双重链接列表是相同的,除了该行可以改变方向。

每个人都在抓住他们面前的人,但他们无法看到谁在他们身后。添加到列表就像将一个人添加到行的前面。从技术上讲,我写的LinkedList工作方向相反,前面添加了添加,尾部删除了删除,但概念是相同的。

从列表中取出/删除项目就像添加一个限制杆。第一次击中被从链条中取出,并通过重新连接休息的末端来修复中断。

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

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

在性能方面,它需要O(1)(即恒定时间)来添加项目。 O(N)(即线性时间)从列表中获取/删除项目。并且,根据列表是单/双和/或跳转链接,还有一个值得注意的内存开销。

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

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

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

答案 3 :(得分:0)

public class Node {

   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类。它将为您提供将在节点类中使用的方法类型的示例。重新思考你的课程。也许删除Airplane将是节点类中的一个方法,如删除节点。可以将任何在节点上工作的内容(例如insert或add new,delete和sort)添加到节点类中。然后,您可以在添加更多类时重用此类。

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

答案 4 :(得分:0)

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