P1 | P2 | P3 | P4 | P5 | P6 | |
---|---|---|---|---|---|---|
Readable | 9 | 3 | 0 | 0 | 2 | 32 |
Maintainable | 6 | 3 | 2 | 1 | 2 | 28 |
public class Node { public String data; public Node next; }
String[] names = {"Alice", "Bob", "Carol", "Doug"}; Node head = new Node(); head.data = names[0]; Node current = head; for (int i = 1; i < names.length; i++) { current.next = new Node(); current = current.next; current.data = names[i]; current.next = null; //not really necessary } //at this point, head points to the start of the list for (Node n = head; n != null; n = n.next) { System.out.print(n.data + " "); } System.out.println();
//weird contrived example Node one; one = new Node(); Node two = new Node(); Node three = new Node(); one.next = two; three.next = two; one.data = "Albert"; three.data = one.data; two.data = "Bianca"; three.data = "Calvin"; Node head = three; for (Node n = head; n != null; n = n.next) { System.out.println(n.data); }
Calvin Bianca
public class Node { private String data; private Node next; public Node(String data, Node next) { this.data = data; this.next = next; } public Node(String data) { this(data, null); } public String getData() { return data; } public void setData(String data) { this.data = data; } public Node getNext() { return next; } public void setNext(Node next) { this.next = next; } }
String[] names = {"Alice", "Bob", "Carol", "Doug"}; Node head = new Node(names[0]); Node current = head; for (int i = 1; i < names.length; i++) { current.setNext(new Node(names[i])); current = current.getNext(); } //at this point, head points to the start of the list for (Node n = head; n != null; n = n.getNext()) { System.out.print(n.getData() + " "); } System.out.println();
Although Node is encapsulated, resulting linked list structure is not.
//another strange example Node head = new Node("Albert"); Node sub = new Node("Bianca", head); head = sub; head = new Node("Calvin", head); head = new Node("Dale"); head.setNext(sub); for (Node n = head; n != null; n = n.getNext()) { System.out.println(n.getData()); }
Dale Bianca Albert
Instance variables:
private Node top;
Constructor:
public Stack() { this.top = null; }
public void push(String item) { this.top = new Node(item, top); }
public String peek() { if (this.top == null) { throw new IllegalStateException("Can't peek() into empty stack."); } return this.top.getData(); }
public String pop() { if (this.top == null) { throw new IllegalStateException("Can't pop() from empty stack."); } String data = this.top.getData(); this.top = this.top.getNext(); return data; }
public int size() { int size = 0; Node curr = this.top; while (curr != null) { size++; curr = curr.getNext(); } return size; }
public int size() { int size = 0; Node curr = this.top; while (curr != null) { size++; curr = curr.getNext(); } return size; }
public int size() {
int size = 0;
for (Node curr = this.top; curr != null; curr = curr.getNext()) {
size++;
}
return size;
}
Is this clearer? Maybe, maybe not.
public int size() { int size; Node curr; for (size = 0, curr = this.top; curr != null; size++, curr = curr.getNext()); return size; }
Amusing to move all code out of the loop body, but this is not clearer.
Now with efficient size tracking, so all operations O(1)
public class Stack { private Node top; private int size; public Stack() { this.top = null; this.size = 0; } public void push(String item) { this.top = new Node(item, top); this.size++; } public String peek() { if (this.top == null) { throw new IllegalStateException("Can't peek() into empty stack."); } return this.top.getData(); } public String pop() { if (this.top == null) { throw new IllegalStateException("Can't pop() from empty stack."); } String data = this.top.getData(); this.top = this.top.getNext(); this.size--; return data; } public int size() { return this.size; } }
Nodes and Stack only work with String:
public class Node { private String data; private Node next; //...
public class Node<E> {
public class Node<E> { private E data; private Node<E> next; public Node(E data, Node<E> next) { this.data = data; this.next = next; } public Node(E data) { this(data, null); } public E getData() { return data; } public void setData(E data) { this.data = data; } public Node<E> getNext() { return next; } public void setNext(Node<E> next) { this.next = next; } }
Specify the element type of each Node ("String Node" vs "Integer Node").
String[] names = {"Alice", "Bob", "Carol", "Doug"}; Node<String> head = new Node<String>(names[0]); Node<String> current = head; for (int i = 1; i < names.length; i++) { current.setNext(new Node<String>(names[i])); current = current.getNext(); } //at this point, head points to the start of the list for (Node<String> n = head; n != null; n = n.getNext()) { System.out.print(n.getData() + " "); } System.out.println();
public class Stack<E> { private Node<E> top; private int size; public Stack() { this.top = null; this.size = 0; } public void push(E item) { this.top = new Node<E>(item, top); this.size++; } public E peek() { if (this.top == null) { throw new IllegalStateException("Can't peek() into empty stack."); } return this.top.getData(); } public E pop() { if (this.top == null) { throw new IllegalStateException("Can't pop() from empty stack."); } E data = this.top.getData(); this.top = this.top.getNext(); this.size--; return data; } public int size() { return this.size; } }
Stack<String> s = new Stack<String>(); System.out.println(s.size()); //0 s.push("Alice"); s.push("Bob"); s.push("Carol"); System.out.println(s.size()); //3 System.out.println(s.peek()); //Carol System.out.println(s.pop()); //Carol s.pop(); System.out.println(s.peek()); //Alice System.out.println(s.size()); //1
But now can also do this:
Stack<Integer> s = new Stack<Integer>(); s.push(3); s.push(12); System.out.println(s.pop());
Cool! Stack will work with any type (object, not primitive, but can use wrapper classes).
If you want to master the more advanced aspects of Java, I enjoyed: