任务:给定一个具有偶数个元素且参考头指向第一个节点的圆形链表,编写方法splitHalf
将圆形链表分为两个半圆形。即CLL(5,34,14,25)变为CLL(5,34)和CLL(14,25)。
我尝试用Java尝试,但是扩展了给我的实现。看来我的驱动程序代码没有给我我想要的结果。我当前splitHalf
的实现可能看起来很尴尬,因为最初的问题只是编写一种对返回类型没有任何要求的算法,并且我尝试在线修改返回类型为void的算法,因此我的splitHalf
只是完成拆分后即可打印。
我期待
List is: 1, 2, 1.
List is: 2, 1, 2.
List is: 3, 4, 3.
List is: 4, 3, 4.
但是我得到了
List is: 2, 2, 2.
List is: 1, 1, 1.
List is: 4, 4, 4.
List is: 3, 3, 3.
有人可以告诉我splitHalf
中的CircularLinkedList
怎么了吗?这是我的代码。
import java.util.*;
class Main {
public static void main(String [] args) {
CircularLinkedList<Integer> lst = CircularLinkedList.of(1,2,3,4);
lst.splitHalf(lst.head);
}
}
class CircularLinkedList <E> extends TailedLinkedList <E> {
public void addFirst (E item) {
super.addFirst ( item );
tail.next = head;
}
public void addLast (E item ) {
super.addLast ( item );
tail.next = head;
}
public E removeAfter (ListNode <E> current) throws NoSuchElementException {
E temp = super.removeAfter (current);
// up till here no problem as long as it is not the following cases:
// case 1. removing both head and tail (but not done correctly by parent)
if ( num_nodes == 0 ) { // can't test for head==null here
head = tail = null;
return temp;
}
// tail and head are not null now
// case 2a. removing head (because current==null)
if (current == null) {
System.out.println("case 2a");
tail.next = head;
return temp;
}
// case 2b. removing head (because current==tail)
if ( tail.next != head) {
System.out.println("case 2b");
head = tail.next;
return temp;
}
// case 3. removing tail (and not head, because current.next==tail)
if (current.next == head) {
tail = current;
return temp;
}
return temp;
}
public E removeFirst ( ) throws NoSuchElementException {
return removeAfter ( null );
}
// the one in ExtendedLinkedList can't be used due to infinite loop
public E remove (E item) throws NoSuchElementException {
if (head == null) throw new NoSuchElementException("can't find item");
ListNode <E> n = head;
ListNode <E> prev = null;
for (int i=0; i < num_nodes; i++, prev=n, n=n.next)
if (n.element.equals(item))
return removeAfter (prev);
throw new NoSuchElementException ("can't find item to remove");
}
// the one in BasicLinkedList can't be used as it would go into infinite loop
public boolean contains (E item) throws NoSuchElementException {
if ( head == null ) return false;
ListNode <E> n = head;
for (int i=0; i < num_nodes; i++) {
if (n.element.equals(item)) { return true; }
n = n.next;
}
return false;
}
/*
*Alternative method to printing instead of the infinite loop printing that is inherited
*/
public void truncatedPrint () throws NoSuchElementException {
if (head == null)
throw new NoSuchElementException ("Nothing to print...");
Iterator <E> itr = iterator();
System.out.print ("List is: " + itr.next() );
for (int i=0;i< this.size();i++) {//just print the head again to be sure that this is circular
System.out.print ( ", " + itr.next() );
}
System.out.println(".");
}
public static <E> CircularLinkedList<E> of(E ... values) {
CircularLinkedList<E> lst = new CircularLinkedList<>();
for (int i=values.length-1;i> -1; i--) {
lst.addFirst(values[i]);
}
return lst;
}
void splitHalf(ListNode<Integer> head) {
ListNode<Integer> slow_ptr = head;
ListNode<Integer> fast_ptr = head.next;
if (head == null) {
return;
}
//move the pointers to correct place
while (fast_ptr.next != head
&& fast_ptr.next.next != head) {
fast_ptr = fast_ptr.next.next;
slow_ptr = slow_ptr.next;
}
//the slow pointer is currently the previous node of tne head for 2nd half
ListNode<Integer> head2 = slow_ptr.next;
ListNode<Integer> head1 = head;
slow_ptr.next = head1;
fast_ptr.next = head2;
ListNode.printFromNode(head1,3);
ListNode.printFromNode(slow_ptr,3);
ListNode.printFromNode(head2,3);
ListNode.printFromNode(fast_ptr,3);
}
}
class TailedLinkedList <E> extends ExtendedLinkedList <E> {
protected ListNode <E> tail = null;
public ListNode <E> getTail() {
return tail;
}
public void addFirst (E item ) {
super.addFirst ( item );
if (num_nodes == 1)
tail = head;
}
public void addLast (E item) {
if (head != null) {
tail.next = new ListNode <E> ( item );
tail = tail.next;
num_nodes++;
} else {
tail = new ListNode <E> ( item );
head = tail;
num_nodes++;
}
}
public void addAfter (ListNode <E> current, E item) {
super.addAfter (current, item);
if (current != null) {
if (current == tail) // can "if (current.next.next == null)" work too ?
tail = current.next;
} else {
if (tail == null) tail = head;
}
}
// we need to look through all deletion methods....
public E removeAfter (ListNode <E> current) throws NoSuchElementException {
E temp = super.removeAfter(current);
if (current != null) {
if (current.next == null) tail = current;
} else // removing head
if (head == null) tail = null;
return temp;
}
public E removeFirst ( ) throws NoSuchElementException {
return removeAfter( null );
}
// Okay to use remove from ExtendedLinkedList
// public E remove (E item) throws NoSuchElementException {
}
class ExtendedLinkedList <E> extends BasicLinkedList <E> {
// not in API Class LinkedList
public ListNode <E> getFirstPtr ()
{ return head; }
// not in API Class LinkedList
public void addAfter (ListNode <E> current, E item) {
if (current != null) {
current.next = new ListNode <E> (item, current.next);
num_nodes++;
} else {
head = new ListNode <E> (item, head);
num_nodes++;
}
}
// not in API Class LinkedList
public E removeAfter (ListNode <E> current) throws NoSuchElementException {
E temp;
if (current != null) {
if (current.next != null) {
temp = current.next.element;
current.next = current.next.next;
num_nodes --;
return temp;
} else throw new NoSuchElementException("No next node to remove");
} else { // if current is null, assume we want to remove head
if (head != null) {
temp = head.element;
head = head.next;
num_nodes --;
return temp;
} else throw new NoSuchElementException("No next node to remove");
}
}
public E remove (E item) throws NoSuchElementException {
if (head == null) throw new NoSuchElementException ("can't find item to remove");
// besides the following, can also use iterator in BasicLinkedList.java
for (ListNode <E> n=head, prev=null; n != null; prev=n, n=n.next)
if (n.getElement().equals(item) )
return removeAfter (prev);
throw new NoSuchElementException ("can't find item to remove");
}
}
class BasicLinkedList <E> implements LinkedListInterface <E> {
protected ListNode <E> head = null;
protected int num_nodes = 0;
public boolean isEmpty()
{ return (num_nodes == 0); }
public int size( )
{ return num_nodes; }
public E getFirst ( ) throws NoSuchElementException {
if (head == null)
throw new NoSuchElementException("can't get from an empty list");
else return head.element;
}
public boolean contains (E item) {
for (ListNode <E> n = head; n!= null; n=n.next)
if (n.getElement().equals(item)) return true;
return false;
}
public void addFirst (E item) {
head = new ListNode <E> (item, head);
num_nodes ++;
}
public E removeFirst ( ) throws NoSuchElementException {
ListNode <E> ln;
if (head == null)
throw new NoSuchElementException ("can't remove from an empty list");
else {
ln = head;
head = head.next;
num_nodes --;
return ln.element;
}
}
public void print2 ( ) throws NoSuchElementException {
if (head == null)
throw new NoSuchElementException ("Nothing to print...");
ListNode <E> ln = head;
System.out.print ("List is: " + ln.element);
for (int i=1; i < num_nodes; i++) {
ln = ln.next;
System.out.print (", " + ln.element );
}
System.out.println(".");
}
public void print () throws NoSuchElementException {
if (head == null)
throw new NoSuchElementException ("Nothing to print...");
Iterator <E> itr = iterator();
System.out.print ("List is: " + itr.next() );
while (itr.hasNext())
System.out.print ( ", " + itr.next() );
System.out.println(".");
}
public Iterator<E> iterator() {
return new LinkedListIterator();
}
/*
*Private class in a class which looks like a method,
*I thought at most property allowed
*/
private class LinkedListIterator implements Iterator<E> {
private ListNode<E> current = head;
public boolean hasNext(){ return current != null;}
public void remove() { throw new UnsupportedOperationException(); }
public E next() {
if ( !hasNext()) {
throw new NoSuchElementException();
}
E element = current.element;
current = current.next;
return element;
}
}
/*make just for int for now
*rmber static must upfront declare first
*/
public static <E> BasicLinkedList<E> of(E ... values) {
BasicLinkedList<E> lst = new BasicLinkedList<>();
for (int i=values.length-1;i> -1; i--) {
lst.addFirst(values[i]);
}
return lst;
}
}
interface LinkedListInterface <E> {
public boolean isEmpty( );
public int size ( );
public E getFirst () throws NoSuchElementException;
public boolean contains (E item);
public void addFirst (E item);
public E removeFirst ( ) throws NoSuchElementException;
public void print ();
// ....etc....
// ....etc....
}
class ListNode <E> {
protected E element;
protected ListNode <E> next;
/* constructors */
public ListNode (E item) {
element = item;
next = null;
}
public ListNode (E item, ListNode <E> n) {
element = item;
next=n;
}
/* get the next ListNode */
public ListNode <E> getNext ( ) {
return this.next;
}
/* get the element of the ListNode */
public E getElement ( ) {
return this.element;
}
/*
*My own setter of the right neighbour of the current node,
*Without the concept of leftware traversion in the factory method
*/
public void setNext(ListNode<E> item) {
this.next = item;
}
/*
*Prints from a single node, without knowing the list entity
*Might be null and null cache wont know of this method, so make it static better
*Some cases to know more about
*Locate the correct node first, then print the printable element, this is a checklist
*I would prefer using their toString then using a getElement then put to print?
*Added in extra count, anyway there isn't a printFromNode
*/
public static <E> void printFromNode (ListNode<E> head, int count) throws NoSuchElementException {
if (head == null) {
throw new NoSuchElementException ("Nothing to print...");
}
ListNode<E> ptr = head;
System.out.print ("List is: " + ptr.next.getElement());
count--;
while (count>0 && ptr.next!=null) {
System.out.print ( ", " + ptr.next.getElement());
count--;
}
System.out.println(".");
}
}