【问题标题】:How to implement a Linked List in Java? [duplicate]如何在 Java 中实现链表? [复制]
【发布时间】:2011-06-07 22:10:26
【问题描述】:

我正在尝试在 Java 中实现一个简单的 HashTable,它使用链表来解决冲突,这在 C 中很容易做到,但我不知道如何在 Java 中做到这一点,因为你不能使用指针...

首先,我知道这些结构已经用 Java 实现了,我不打算使用它,只是在这里培训......

所以我创建了一个元素,它是一个字符串和一个指向下一个元素的指针:

public class Element{
        private String s;
        private Element next;

        public Element(String s){
            this.s = s;
            this.next = null;
        }

        public void setNext(Element e){
            this.next = e;
        }

        public String getString(){
            return this.s;
        }

        public Element getNext(){
            return this.next;
        }

        @Override
        public String toString() {
            return "[" + s + "] => ";
        }
    }

当然,我的 HashTable 有一个 Element 数组来存储数据:

public class CustomHashTable {
    private Element[] data;

这是我的问题:

例如,我想实现一个在链表末尾添加元素的方法(我知道在链表开头插入元素会更简单、更高效,但同样,这只是用于培训目的)。没有指针我该怎么做?

这是我的代码(如果 e 是指针,它可以工作......):

public void add(String s){
        int index = hash(s) % data.length;
        System.out.println("Adding at index: " + index);
        Element e = this.data[index];
        while(e != null){
            e = e.getNext();
        }
        e = new Element(s);
    }

谢谢!

【问题讨论】:

  • 您是否真的尝试过运行您的示例代码?因为对于所有意图,Java 引用与 C 指针相同。
  • 一旦你搞定了这个,你就可以涉足泛型了!
  • @Anon:他们是为了这个例子,但不是全部。
  • 除非您的示例 add() 方法将失败,因为您没有跟踪列表的尾部,并且没有将新的 Element 分配给尾部...
  • @Joey - 它们不等价的地方是(1)数组名称不是指针,(2)你不能将指针转换为整数,以及(3)你不能将指针强制转换为任意类型。您不需要任何这些功能来实现链接列表,或者就此而言,大多数现实世界的应用程序。当您确实需要这些功能时,Java 会提供变通方法。

标签: java pointers linked-list


【解决方案1】:
public void add(String s){
    int index = hash(s) % data.length;
    System.out.println("Adding at index: " + index);
    Element curr = new Element(s);
    Element e = this.data[index];
    if (e == null) {
       this.data[index] = curr;
       return;
    }
    while(e.getNext() != null){
        e = e.getNext();
    }
    e.setNext(curr);
}

【讨论】:

    【解决方案2】:

    出于您的目的,Java 的引用与 C 的指针的使用没有区别。事实上,指针在 C 中的主要问题(或好处,取决于你问谁)不是它们可以指向 指向某物,而是你可以用它们做数学运算。

    仅出于指向目的,您可以在此处执行相同操作:

    e.setNext(new Element(s));
    

    而不是

    e = new Element(s);
    

    (这只会让变量e 指向一个新元素,但不会改变旧元素的任何内容)。

    你就完成了。

    【讨论】:

      【解决方案3】:

      如果你想自己写,首先让它实现 java.util.List 接口。

      如果您可以使用库类,请使用 java.util.LinkedList。

      现在有人向我指出你正在“练习”,所以一些好的建议可能会被某些人认为是禁区,但你应该注意泛型。我建议阅读它们并将它们构建到您的元素(节点?)和列表实现中。泛型就是以这种方式与集合一起使用而诞生的。我会从这里开始:

      package list;
      
      public class Node<T>
      {
          private T value;
          private Node<T> prev;
          private Node<T> next;
          // You add the rest.
      }
      

      【讨论】:

      • 如果他只是暂时练习,我想现在引入接口和Java的集合框架还为时过早。
      • 我认为现在引入界面还为时过早。如果不出意外,它将阐明“列表”的含义。
      • 这就是我要做的,但这里的重点是我希望能够只使用数组来实现它,所以我可以看到所有的机制。
      • 用数组实现不排除List接口。你如何实施是你的事;把实现隐藏在 List 接口后面,你可以为所欲为,只要你遵守 List 接口为客户提供的契约。
      • -1 正如他在他正在练习的问题中所说的那样,我投了反对票。我也认为此时不使用java.util.List 接口并没有什么坏处。在我看来,将这个 laster 重构为使用 java List 接口是一个很好的做法。你也根本懒得回答他的问题。
      【解决方案4】:

      在方法结束时重新分配局部变量不会改变任何事情。你需要这样的东西:

      Element e = this.data[index];
      while (e.getNext() != null) {
          e = e.getNext();
      }
      

      那么e指的是列表末尾的元素。创建一个新元素,并将其设置为下一个:

      Element newElement = new Element(s);
      e.setNext(newElement);
      

      为了提高效率,我建议您考虑双链接节点和知道列表的头部和尾部的列表类型。区分整个列表(知道头、尾,可能还有计数)和列表中的节点(知道下一个、上一个以及可能属于哪个列表)。

      【讨论】:

      • 我认为单链表在这种特殊情况下是合理的。 OP 正在制作一个哈希表,因此列表应该只包含几个节点。轻微的效率提升可能不会超过额外的内存消耗。
      • @Ishtar:可能,是的。事实上,他仍然可以维护一个带有指向头和尾的链接的列表,但仍然使每个节点都只转发。
      【解决方案5】:

      递归解决方案:

      public class Element{
        /* ... */
        public void addTail(Element e){
          if (next == null)
            next = e; //we are at the end, add it
          else
            next.addTail(e);//let the next node take responsibility
        }
      }
      
      public void add(String s){
      
        int index = hash(s) % data.length;
        System.out.println("Adding at index: " + index);
        Element e = this.data[index];
        e.addTail(new Element(s));
      }
      

      【讨论】:

        【解决方案6】:

        Java 中的 LinkedList 是这样工作的:

        有一个这样的静态类:

        private static class Entry<E> {
        E element;
        Entry<E> next;
        Entry<E> previous;
        Entry(E element, Entry<E> next, Entry<E> previous) {
            this.element = element;
            this.next = next;
            this.previous = previous;
        }
        }
        

        LinkedList 构造函数:

        public LinkedList() {
            header.next = header.previous = header;
        }
        
        public LinkedList(Collection<? extends E> c) {
        this();
        addAll(c);
        }
        

        addAll 方法:

        public boolean addAll(Collection<? extends E> c) {
            return addAll(size, c);
        }
        

        你应该在这里检查:

        private transient Entry<E> header = new Entry<E>(null, null, null);
        private transient int size = 0;
        
        private Entry<E> addBefore(E e, Entry<E> entry) {
        Entry<E> newEntry = new Entry<E>(e, entry, entry.previous);
        newEntry.previous.next = newEntry;
        newEntry.next.previous = newEntry;
        size++;
        modCount++;
        return newEntry;
        }
        
        private E remove(Entry<E> e) {
        if (e == header)
            throw new NoSuchElementException();
        
            E result = e.element;
        e.previous.next = e.next;
        e.next.previous = e.previous;
            e.next = e.previous = null;
            e.element = null;
        size--;
        modCount++;
            return result;
        }
        
        private Entry<E> addBefore(E e, Entry<E> entry) {
        Entry<E> newEntry = new Entry<E>(e, entry, entry.previous);
        newEntry.previous.next = newEntry;
        newEntry.next.previous = newEntry;
        size++;
        modCount++;
        return newEntry;
        }
        
        public boolean add(E e) {
        addBefore(e, header);
            return true;
        }
        

        【讨论】:

          【解决方案7】:
          //Single linked list implementation
          
          public class Nodes {
          
              int data;
              Nodes next = null;
          
              public Nodes(int data) {
                  this.data = data;
              }
          }
          
          
          public class Lists {
          
              static Nodes first = null;
          
              public static void insertBegin(int data) {
                  Nodes temp = new Nodes(data);
                  if(first == null) {
                      first = temp;
                  }
                  else {
                      temp.next = first;
                      first = temp;           
                  }
              }
          
              public static void insertEnd(int data) {
                  Nodes temp = new Nodes(data);
                  if(first == null) {
                      first = temp;
                  }
                  else{
                      Nodes n = first;
                      while(n.next != null) {
                          n = n.next;
                      }
                      n.next = temp;
                  }
              }
          
              public static void insertPos(int pos, int data) {
                  Nodes temp = new Nodes(data);
                  if(first == null) {
                      System.out.println("List empty. Cannot insert");
                  }
                  else {
                      Nodes n = first;
                      while(n.data != pos && n.next != null) {
                          n = n.next;
                      }
                      if(n.data != pos){
                          System.out.println("Position not found");
                      }
                      else {
                          temp.next = n.next;
                          n.next = temp;
                      }
                  }
              }
          
              public static void deleteBegin() {
                  if(first == null) {
                      System.out.println("List empty. Cannot delete");
                  }
                  else {
                      first = first.next;
                  }       
              }
          
          
              public static void deleteEnd() {
                  if(first == null) {
                      System.out.println("List empty. Cannot delete");
                  }
                  else {
                      Nodes n = first;
                      while(n.next.next != null) {
                          n = n.next;
                      }
                      n.next = n.next.next;
                  }
              }
          
              public static void deletePos(int pos) {
                  if(first == null) {
                      System.out.println("List empty. Cannot delete");
                  }
                  else {
                      Nodes n = first;
                      while(n.next.data != pos && n.next.next != null) {
                          n = n.next;
                      }
                      if(n.next.data != pos) {
                          System.out.println("Element not found. Deletion failed");
                      }
                      else{
                          n.next = n.next.next;
                      }
                  }
              }
          
              public static void printAll() {
                  System.out.println("Elements in link list");
                  Nodes n = first;
                  while(n != null) {
                      System.out.print(n.data + "->");
                      n = n.next;
                  }
              }
          }
          

          【讨论】:

            猜你喜欢
            • 2014-05-23
            • 2016-09-11
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-12-15
            • 2020-05-05
            • 2012-12-05
            • 1970-01-01
            相关资源
            最近更新 更多