Java - 自定义单一链接列表,删除具有特定值的所有元素

时间:2013-03-24 00:11:35

标签: java algorithm optimization class linked-list

我在java中创建了一个自定义LinkedList,这在某个地图和&之间是一个交叉点。一个列表。我只是做了这个练习来学习,我知道HashMap是一个更好的&更快的实施。我为LinkedList实现了delete方法,但是对于哪种方法是写入方法的最佳方法有点困惑:deleteAll基本上删除了特定元素的所有出现。

代码:

public class LinkedListMain
{
    public static void main(String[] args)
    {
        LinkedList linkedList = new LinkedList();

        System.out.println("isEmpty: " + linkedList.isEmpty());

        linkedList.insert("abc", 34);
        linkedList.insert("pqr", 44);
        linkedList.insert("xyz", 54);
        linkedList.insert("asd", 64);
        linkedList.insert("abc", 74);

        linkedList.print();

/*      System.out.println("delete: " + linkedList.delete("abc"));
        System.out.println("delete: " + linkedList.delete("pqr"));
        System.out.println("delete: " + linkedList.delete("xyz"));
        System.out.println("delete: " + linkedList.delete("asd"));
*/
        System.out.println("deleteAll: " + linkedList.deleteAll("abc"));
        System.out.println("isEmpty: " + linkedList.isEmpty());
    }
}

class LinkedList
{
    private ListNode first;
    private ListNode last;

    public LinkedList()
    {
        first = null;
        last = first;
    }

    public void insert(String d1, int d2)
    {
        ListNode node = new ListNode(d1, d2);

        if(first == null)
        {
            node.next = null;
            first = node;
            last = node;
        }

        else
        {
            last.next = node;
            node.next = null;
            last = node;
        }
    }

    public String deleteAll(String str)
    {
        return "To Be Implemented";
    }

    public String delete(String str)
    {
        ListNode slow = first;
        ListNode fast = first;

        int count = 0;

        while(fast != null)
        {
            if(count > 1)
            {
                slow = slow.next;
            }

            if(count <= 1)
            {
                count++;
            }

            if(fast.getVal()==str)
            {
                if(fast == first)
                {
                    first = first.next;
                }

                else
                {
                    if(fast.next != null)
                    {
                        slow.next = fast.next;
                    }

                    else
                    {
                        slow.next = null;
                    }
                }

                fast = null;
                return str;     // fast.getVal()
            }

            fast = fast.next;
        }

        return "not found";
    }

    public void print()
    {
        ListNode currentNode = first;

        while(currentNode != null)
        {
            currentNode.print();
            currentNode = currentNode.next;
        }
    }

    public boolean isEmpty()
    {
//      return ( ((first==null) ? (true) : (false)) && ((last==null) ? (true) : (false)));
        return (first==null) ? (true) : (false);
    }
}

class ListNode
{
    private String data1;
    private int data2;

    public ListNode next;

    public ListNode(String d1, int d2)
    {
        data1 = d1;
        data2 = d2;
    }

    public String getVal()
    {
        return data1;
    }

//  public void printMe(ListNode node)
    public void print()
    {
        System.out.println("data1: [" + data1 + "], data2: [" + data2 + "]");
    }
}

我有3个与此示例相关的问题:

  1. 理想的deleteAll函数应该重复使用我的删除功能吗?我应该更改我的删除功能以适应这个吗?
  2. isEmpty函数是否应该首先比较第一个&amp;最后两个都为空?如果last应该与null比较,那么我应该如何更改我的删除&amp; deleteAll函数用于实现此功能。我尝试使用当前的删除功能执行此操作,但遇到了一些问题。
  3. 一般来说,这段代码可以显着优化吗?不是在“如果你需要完美的链表,使用收藏集”的意义上,如果可能的话,只是询问如何更准确地优化这个单链表?

1 个答案:

答案 0 :(得分:1)

deleteAll()之前的节点传递给节点删除方法可能会非常舒服。如果delete()除了显而易见的指针操作之外还要做任何事情,那么可以将这个动作考虑在内。

/** 
 Deletes all nodes that contain target_string. 
 Returns the number of nodes deleted.
*/
public int deleteAll(String target_string) {
  int deleted_nodes_cnt = 0;
  ...
  if (prev_node.next.getVal().equals(target_string)) { // not ==
    deleteNextNode(prev_node); 
    prev_node = prev_node.next; 
    deleted_nodes_cnt += 1;
  }
  ...
  return deleted_nodes_cnt;
}

/** Delete the node after prev_node; prev_node.next != null */
private void deleteNextNode(Node prev_node) {
  Node dead_node = prev_node.next;
  prev_node.next = prev_node.next.next;
  dead_node.afterDelete(); // any custom cleanup, if required
}

public boolean delete(String target_string) {
   ... 

  if (prev_node.next.getVal().equals(target_string)) { // looks familiar?
    deleteNextNode(prev_node);
    return true; 
  }
  ...
  return false;
}

您可能会注意到delete()deleteAll()使用相同的列表迭代逻辑,这也可以很好地计算出来。

/**
 Scan nodes, starting from this.
 Returns node X such that X.next.value equals target_string, or null. 
*/
private Node findNodeBeforeMatching(String target_string) {
  Node prev_node = this;
  while (prev_node.next != null) {
    if (prev_node.next.getVal().equals(target_string)) return prev_node;
    else prev_node = prev_node.next;
  }
  return null;
}

要有效地使用此方法,您需要将LinkedList(基本上是“list head keeper”)作为Node的子类,或者将它们作为公共类的子类。更好的是,让它们实现允许getNext()deleteNext()的相同界面。或者,您可以从每个操作返回Node,但这当然与Collection接口不兼容。

旧的,不正确的文字:deleteAll()应该调用单个delete()方法,除非这些方法可以在后代类中做一些特殊的事情。原因是这样的deleteAll()是O(1),以恒定时间运行,而遍历列表到delete()每个节点是O(n)。 AFAICT last实例变量仅用于加速将附加元素添加到列表末尾(尽管insert()对它做了奇怪的事情)。因此isEmpty()应该只检查first。如果first == null,方法可以 assert last == null。我假设first == nulllast != null表示我们的簿记错误,我们的数据已损坏,我们无法继续。 WRT优化,我看不到你的拜占庭delete()应该如何工作。在你的情况下,我不认为有两个指针可以加快速度。运行具有不同“速度”的两个指针是一种已知的检测周期的方法,但我不知道它在这里是如何适用的。

如果您希望加速排序数据,请阅读skip list或使用树。在未分类的数据上,一个简单的顺序扫描是你最好的选择。

对我来说,整个LinkedList类应该只有一半,因为它在逻辑上很简单。

ListNodeLinkedListinsert()中被不必要地紧密耦合,这应该是IMHO接受一个实例,而不是构建它。更好的是,ListNodeLinkedList应该是一样的,就像在经典实现中一样。

获取Wirth's book on data structures and algorithms,它非常平易近人。 (当你完全理解它的时候,试着继续使用Knuth的书,如果你真的很勇敢,请用Okasaki的书。)