如何在Java中实现链表?

如何在Java中实现链表?,java,pointers,linked-list,Java,Pointers,Linked List,我试图在Java中实现一个简单的哈希表,它使用链表来解决冲突,这在C中很容易做到,但我不知道如何在Java中实现,因为你不能使用指针 首先,我知道这些结构已经用Java实现了,我不打算使用它,只是在这里进行培训 所以我创建了一个元素,它是一个字符串和指向下一个元素的指针: public class Element{ private String s; private Element next; public Element(String s){

我试图在Java中实现一个简单的哈希表,它使用链表来解决冲突,这在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 + "] => ";
        }
    }
当然,我的哈希表有一个元素数组来存储数据:

public class CustomHashTable {
    private Element[] data;
我的问题是:

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

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


谢谢

如果您想编写自己的,首先让它实现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.
}
包装清单;
公共类节点
{
私人T值;
私有节点prev;
私有节点下一步;
//你把剩下的加起来。
}

出于您的目的,这里Java的引用与C的指针没有区别。事实上,C语言中指针的主要问题(或好处,取决于你问谁)不是它们能指向什么,而是你能用它们做数学运算

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

e.setNext(new Element(s));
而不是

e = new Element(s);
(这只会让变量
e
指向一个新元素,但不会改变旧元素上的任何内容)


完成了。

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

Element e = this.data[index];
while (e.getNext() != null) {
    e = e.getNext();
}
然后
e
引用列表末尾的元素。创建一个新元素,并将其设置为下一个元素:

Element newElement = new Element(s);
e.setNext(newElement);
<>效率,我敦促你考虑双链接节点和列表类型,它知道列表的头和尾。区分整个列表(知道头、尾,可能还有计数)和列表中的节点(知道下一个、上一个,可能还有它所属的列表)。

递归解决方案:

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));
}

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;
}
}
私有静态类条目{
E元素;
进入下一步;
入境前;
条目(E元素、下一条条目、上一条条目){
this.element=元素;
this.next=next;
this.previous=先前;
}
}
LinkedList构造函数:

public LinkedList() {
    header.next = header.previous = header;
}

public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
公共链接列表(){
header.next=header.previous=header;
}

public LinkedList(collection)如果他只是暂时练习一下,我想引入接口和Java的集合框架还为时过早。我认为引入接口并不为时过早。如果没有其他内容,它将澄清什么是“列表”意思是说。这就是我要做的,但这里的重点是我希望能够只使用数组来实现它,这样我就可以看到所有的机制。使用数组实现并不排除列表接口。如何实现是你的事情;将实现隐藏在列表接口后面,你可以随心所欲,只要你遵守合同t列表接口为客户端提供了什么。-1我否决了这一点,因为他在问题中说他只是在练习。我还认为在这一点上不使用
java.util.List
接口没有害处。在我看来,重构这个laster以使用java
List
接口是一个很好的做法。你也没有“我根本懒得回答他的问题。你真的试过运行你的示例代码吗?因为不管怎么说,Java引用与C指针是一样的。一旦你了解了这一点,你就可以涉猎泛型了!@Anon:它们适用于这个示例,但不适用于所有示例。除了你的示例
add()
方法将失败,因为您没有跟踪列表的尾部,也没有将新的
元素
分配给尾部…@Joey-它们不等价的地方是:(1)数组名不是指针,(2)您不能从整数强制转换指针,以及(3)您不能将指针强制转换为任意类型。您不需要任何这些功能来实现链表,或者就这一点而言,大多数实际应用程序都不需要这些功能。Java在您确实需要这些功能时提供了解决方法。我认为在这种特殊情况下,单链表是合理的。OP正在制作一个哈希表,因此列表应该包含n只有几个节点。略微提高的效率可能不会超过额外的内存消耗。@Ishtar:可能,是的。事实上,他仍然可以维护一个带有指向head和tail的链接的列表,但仍然只能使每个节点向前移动。
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;
}
}
public LinkedList() {
    header.next = header.previous = header;
}

public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
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;
}
//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;
        }
    }
}