| 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: