This is really bad, though, and it's a pain for users to use, so we can improve it.
Improving the IntNode
In order to start fixing our IntNode let's build a new class that uses it, SLList.
publicclassSLList {privateIntNode first;publicSLList(int x) { first =newIntNode(x,null) }}
Because we want to hide IntNode from anyone using the SLList class, we have made it private, making it inaccessible to the outside.
It's somewhat better, since there's no more need to, when creating a linked list, specify a null, e.g. new IntNode(6, null).
Let's implement getters and setters for the first item in the list. We'll also nest the IntNode class inside of our SLList. Java supports nested classes!
publicclassSLList {privateIntNode first;/* We moved our IntNode class to the same file as this one.*/privatestaticclassIntNode{privateint item;privateIntList next;publicIntList(int item,IntList next){this.item= item;this.next= next; } }publicSLList(int x) { first =newIntNode(x,null) }/* Add a number to the front of the list*/publicvoidaddFirst(int x) { first =newIntNode(x, first); }/*Get the first item in the list.*/publicintgetFirst() {returnfirst.item; }}
Since there's no need for anything outside of SLList to manipulate an IntNode, we are free to make it private. Since it never uses anything outside of its own class, we can also make it static.
Now there's no more need for users, when constructing lists, to nest a bunch of new IntNode() calls, and they can just use the addFirst method if they want to extend the list.
This is Better
This is Cringe
SLList L = new SLList(3);
IntNode L = new IntNode(9, new IntNode(6, new IntNode(3, null)))
L.addFirst(6);
L.addFirst(9);
Improving the SLList
Now that we've got our basic SLList structure down, we can improve it further by adding more methods for the user.
publicclassSLList {privateIntNode first;/* Keep track of the size of the list so we don't have to compute it each time we want it*/privateint size =1;privatestaticclassIntNode{publicint item;publicIntList next;publicIntList(int item,IntList next){this.item= item;this.next= next; } }publicSLList(int x) { first =newIntNode(x,null); }publicvoidaddFirst(int x) { first =newIntNode(x, first);/*Increment the size of the list by one*/ size +=1; }publicintgetFirst() {returnfirst.item; }/* Adds an item to the end of the list, rather than the beginning.*/publicvoidaddLast(int x) {IntNode temp = first;while (temp.next!=null) { temp =temp.next }temp.rest=newIntNode(x,null);/*Increment the size of the list by one*/ size +=1; }/* Instead of recursively computing the size each time we want it, we just have a getter for the variable. */publicintsize() {return size; }}
The Empty List
Let's add another constructor so that we can account for having an empty SLList.
publicSLList() { first =null; size =0;}
This works fine for everything but `addLast`, because in that method, we try to access the .next of first, which is not going to work because it is null. Let's see how we can fix that.
We can fix the above with a special case, but special cases are cringe. It's better for everything to work in one consistent way.
Sentinel Node
Instead of using a special case, we can represent the empty list using a sentinel node, a special node that is always there.
publicclassSLList {/* The first item of this list is at sentinel.next*/privateIntNode sentinel;privateint size =1;privatestaticclassIntNode{publicint item;publicIntList next;publicIntList(int item,IntList next){this.item= item;this.next= next; } }publicSLList(int x) { sentinel =newIntNode(69,null);sentinel.next=newIntNode(x,null) }/*Our new constructor for an empty list — 69 is a dummy and will never be accessed.*/publicSLList() { size =0; sentinel =newIntNode(69,null); }publicvoidaddFirst(int x) {sentinel.next=newIntNode(x,sentinel.next); size +=1; }publicintgetFirst() {returnsentinel.next.item; }publicvoidaddLast(int x) {/* Temp will never be null! Thus our problem is solved */IntNode temp = sentinel;while (temp.next!=null) { temp =temp.next }temp.next=newIntNode(x,null); size +=1; }publicintsize() {return size; }}
Because we rewrote our code in this way, we have the following invariants in mind!
The first item in the linked list will always be at sentinel.next.
In the addLast method, temp will never be null.
We don't have to write special cases for null anymore.