对象的通用链表 (Java)

3
我对Java很新,在大学里这是我第二次使用它. 刚开始学期,我制作了一个简单的类,用于表示年龄、类型和名称的僵尸。稍后,我创建了一个整数链表。现在,我需要创建一个通用的链表来容纳这些“僵尸”。我还必须制作一个菜单,允许我添加、删除、计数和显示“僵尸”。我已经盯着这个问题看了几个小时,查阅了我的书籍并在网上寻找答案。我可以添加和显示这些“僵尸”,但在列表中对它们进行计数并尝试删除它们会简单地告诉我没有符合我输入的参数。换句话说,我比较“僵尸”的方法可能有问题。以下是我的代码。虽然我知道这是要看的300行代码......但我已经没有任何想法了。

Zombie.java

public class Zombie
{
private String zAge;
private String zType;
private String zName;

public Zombie(String zA, String zT, String zN)
{
    zAge = zA;
    zType = zT;
    zName = zN;
}

public void setZAge(String zA)
{
    zAge = zA;
}

public void setZType(String zT)
{
    zType = zT;
}

public void setZName(String zN)
{
    zName = zN;
}

public String getZAge()
{
    return zAge;
}

public String getZType()
{
    return zType;
}

public String getZName()
{
    return zName;
}

public boolean equals(Zombie zomb)
{
    if(zomb.getZAge() == zAge && zomb.getZType() == zType && zomb.getZName() == zName)
        return true;
    else
        return false;
}
}

LinkedBag.java

public class LinkedBag<E>
{
//Head node and number of nodes in bag
private Node<E> head;
private int manyNodes;

//Constructor
public LinkedBag()
{
    head = null;
    manyNodes = 0;
}

//Returns the number of nodes in the bag
public int getSize()
{
    return manyNodes;
}

//Returns the node that is at the head of the linked list
public Node<E> getListStart()
{
    return head;
}

//Adds a node to the beginning of the list
public void add(E element)
{
    head = new Node<E>(element,head);       //Creates a new node pointing to the head and sets the head of the linked bag to the new Node
    manyNodes++;        //Increments Node counter
}

//Counts the number of times Node [target] occurs within the bag
public int countOccurences(E target)
{
    int count = 0;      //Initializes incrementable counter

    if(head==null)      //Checks if bag is empty and returns null if bag is empty
        return 0;

    if(head.getData().equals(target))       //Checks if the head of the linked list is [target]
        count++;            //Increments counter

    Node<E> cursor = head;      //Sets temporary Node [cursor] to the same value and pointer as head

    while(cursor.getLink() != null)     //Loops until the next Node contains no value
    {
        if(cursor.getLink().getData().equals(target))           //Checks if the value of the next Node is [target]
            count++;                //Increments counter

        cursor=cursor.getLink();            //Cursor continues down linked list
    }

    return count;       //Returns incremented int [count], number of occurences of [target]
}

//Checks if Node [target] exists within the bag
public boolean exists(E target)
{
    if(head.getData().equals(target))       //Checks if the head of the linked list is [target]
        return true;

    Node<E> cursor = head;      //Sets temporary Node [cursor] to the same value and pointer as head

    while(cursor.getLink() != null)     //Loops until the next Node contains no value
    {
            if(cursor.getData().equals(target))     //Checks if current Node is [target] and returns true if true
                return true;

            cursor=cursor.getLink();        //Cursor continues down linked list
    }
            return false;       //Returns false if cursor goes through entire linked list and [target] isn't found
}

//Checks if Node [target] exists within the bag and removes the first occurence of it
public boolean remove(E target)
{       
    if(head==null)          //Returns false if bag is empty
        return false;

    if(head.getData().equals(target))   //If the head Node's data is [target]
    {
        head = head.getLink();      //Make the next Node the head
        manyNodes--;            //Decrements Node counter
        return true;            //Returns true, found [target]
    }

    Node<E> cursor = head;          //Sets temporary Node [cursor] to the same value and pointer as head

    while(cursor.getLink() != null)     //Loops until the next Node contains no value
    {
        cursor = cursor.getLink();      //Cursor continues down linked list

        if(cursor.getLink().getData().equals(target))   //If the next node's data is [target]
        {
            cursor.setLink(cursor.getLink().getLink());     //Sets current Node's link to the next Node's link, by passing the next Node
            manyNodes--;            //Decrements Node counter
            return true;            //Returns true, found [target]
        }
    }
    return false;           //Returns false, [target] not found
}
}

Node.java

public class Node<E>
{
private E data;
private Node<E> link;


public Node(E initialData, Node<E> initialLink)
{
    data = initialData;
    link = initialLink;
}

public E getData()
{
    return data;
}

public Node<E> getLink ()
{
    return link;
}

public void setData(E element)
{
    data = element;
}

public void setLink(Node<E> newLink)
{
    link = newLink;
}
}

这是用户与之交互的菜单文件

ZombiesProj2.java
import java.util.Scanner;

public class ZombiesProj2
{
public static void main(String[] args) throws InterruptedException
{
    LinkedBag<Zombie> zBag = new LinkedBag<Zombie>();       //Linked bag to hold Zombie Objects
    String choice = "";

    Scanner input = new Scanner(System.in);

    while(!choice.equalsIgnoreCase("x"))
    {   
        //Menu
        System.out.println("\nSac de Zombi\n");
        System.out.println("S - Display size of bag");
        System.out.println("A - Add 'Zombie' to bag");
        System.out.println("R - Remove 'Zombie' from bag");
        System.out.println("F - Find 'Zombie' in bag");
        System.out.println("D - Display contents of bag");
        System.out.println("X - Exit");
        System.out.print("Enter Selection: ");

        //Input and Output
        choice = input.nextLine();

        if(choice.equalsIgnoreCase("s"))
        {
            System.out.println("\nSize = " + zBag.getSize() + "\n");
        }
        else if(choice.equalsIgnoreCase("a"))       //adds zombie
        {
            String zAge;
            String zType;
            String zName;

            System.out.print("How many years has this zombie ROAMED THE EARTH: ");
            zAge = input.nextLine();
            System.out.print("What type of zombie is it: ");
            zType = input.nextLine();
            System.out.print("What would you like to name this zombie: ");
            zName = input.nextLine();

            Zombie newZomb = new Zombie(zAge,zType,zName);
            zBag.add(newZomb);
        }
        else if(choice.equalsIgnoreCase("r"))       //removes zombie
        {
            String zAge;
            String zType;
            String zName;

            System.out.print("How many years has this zombie ROAMED THE EARTH: ");
            zAge = input.nextLine();
            System.out.print("What type of zombie is it: ");
            zType = input.nextLine();
            System.out.print("What is the name of the zombie: ");
            zName = input.nextLine();

            Zombie rZomb = new Zombie(zAge,zType,zName);

            zBag.remove(rZomb);
        }
        else if(choice.equalsIgnoreCase("f"))       //counts number of matching zombies
        {
            String zAge;
            String zType;
            String zName;

            System.out.print("How many years has this zombie ROAMED THE EARTH: ");
            zAge = input.nextLine();
            System.out.print("What type of zombie is it: ");

            zType = input.nextLine();
            System.out.print("What is the name of the zombie: ");
            zName = input.nextLine();

            Zombie fZomb = new Zombie(zAge,zType,zName);

            System.out.println("The " + zAge + " year old zombie type " + zType + " named " + zName + " occurs " + zBag.countOccurences(fZomb)+ " time(s)");
        }
        else if(choice.equalsIgnoreCase("d"))       //displays entire zombie 'bag'
        {
            Node cursor = zBag.getListStart();
            Zombie dZomb;
            while(cursor !=null)
            {
                dZomb = (Zombie)cursor.getData();
                System.out.print("[Zombie "+dZomb.getZAge()+" "+dZomb.getZType()+" "+dZomb.getZName()+"],");
                cursor = cursor.getLink();
            }
        }
        else if(!choice.equalsIgnoreCase("x"))  
        {
            System.out.println("Error: Invalid Entry");
        }
    }
}
}

更新了equals和hashCode方法

public boolean equals(Object obj)
{
    if(obj==null)
        return false;
    if(obj==this)
        return true;
    if(obj.getClass() != getClass())
        return false;

    Zombie zomb = (Zombie)obj;
    if(zomb.getZAge().equals(zAge) && zomb.getZType().equals(zType) && zomb.getZName().equals(zName))
        return true;
    else
        return false;
}

public int hashCode() { return 0; }
2个回答

3

我知道因为你正在学习编程,所以你正在编写自己的链表而不是使用Java的LinkedList。然而,你错过了一些重要的事情。

  1. 你的equals方法应该有与Object Zombie.equals(Object)相同的签名。并且,它应该首先检查参数是否为Zombie,如果不是,则返回false
  2. 每当你编写一个equals方法时,你必须同时编写一个hashCode方法。详细信息请查看大多数示例。
  3. 永远不要使用字符串的等号运算符。总是使用equals方法。将zomb.getZAge() == zAge替换为zomb.getZAge().equals(zAge)
  4. 为什么zAge是一个String?你可以让它成为某种类型的数字。
  5. 在你的类中无需到处放置“Z”。它已经在Zombie中了;你的读者知道。在工作中,我有一些同事坚持在所有变量中重复类名。

这不是好的代码。

public class Document {
    private Long documentId;
    private String documentName;
    private String documentAuthor;
    private Date documentPublicationDate;
    // 10 more instance variables.
    // Constructors, accessors, other code.
}

然后他们将Document类型的变量命名为documentAdocumentB等等。多么无聊、重复和冗余。


  1. 已注意,正在更改。
  2. 我会查一下。
  3. 已注意,正在更改。
  4. 处理用户输入十而不是10的情况。由于我不会用它进行任何算术运算等,因此能够处理这两种情况会更加简单。
  5. 嘿,非常注意到了。
- Nicholas Kadaeux
我按照你的建议更改了我的equals方法,看起来问题已经解决了。不幸的是,我通过简单地使用public int hashCode() { return 0; } 来“临时修补”hashCode方法。通过快速搜索,我发现这是一个低效(但兼容!)的解决方案。我将在我的主要帖子中编辑更新后的equals方法,以供其他遇到此问题的人参考。 - Nicholas Kadaeux

0

1) 为什么要将包含节点计数的变量命名为“manyNodes”,而不是“nodeCount”?如果你问一个随机的程序员,一个名为“manyNodes”的变量包含什么,你认为他们能猜到吗?如果你问一个随机的程序员,变量nodeCount包含什么,你认为这个随机的程序员甚至能猜到nodeCount的类型吗?那么“manyNodes”的类型呢?

2) 试试这样做:

public void add(Node<E> element)
{
    if (head == null) {
        head = element;
    }
    else {
        tail.nextNode = element;
    }

    tail = element;
    nodeCount++;        //Increments Node counter
}


public class Node<E>
{
    private E data;
    private Node<E> nextNode;
}


public class LinkedBag<E>
{

    private Node<E> head;
    private Node<E> tail;
    private int nodeCount;   
}

//Constructor
public LinkedBag()
{
    head = tail = null;
    nodeCount = 0;
}

  1. 已经注意到了...
  2. 改变我添加节点的方式会对比它们有帮助吗?
- Nicholas Kadaeux
你需要在你的Node类中定义一个方法,以确定何时两个节点被视为相等。你应该很快意识到nextNode实例变量不会起作用。 - 7stud
我在Zombie类中完成了这个操作,因为每当比较节点时,.getData返回存储在节点中的Zombie。在Zombie.java底部是我对equals()的重写。 - Nicholas Kadaeux
有两种方法可以解决这个问题:你可以搜索你的链表,找到.data等于其他Zombie的节点。或者,你可以搜索你的链表,找到与给定节点相等的节点。只有在后一种情况下,你需要在Node类中实现一个比较方法。 - 7stud
我还是新手。所以,如果我创建一个新节点(不连接到任何东西,只用于比较),其中包含我正在搜索的元素(E),并将其与列表中的每个节点进行比较,那么它将正常工作吗?编辑:刚看到你的第三次编辑...所以无论如何我仍然在比较节点内的数据。 - Nicholas Kadaeux

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接