• Tidak ada hasil yang ditemukan

A Linked List Class

Dalam dokumen Pelajari tentang Advanced topics in Java (Halaman 88-95)

Linked Lists

3.8 A Linked List Class

Node np, curr, prev;

np = new Node(n);

prev = null;

curr = top;

while (curr != null && n > curr.num) { prev = curr;

curr = curr.next;

}

np.next = curr;

if (prev == null) return np; //top of list is now the new node prev.next = np;

return top; //the top of the list has not changed } //end addInPlace

public static void printList(Node top) {

while (top != null) { //as long as there's a node System.out.printf("%d ", top.num);

top = top.next; //go on to the next node }

System.out.printf("\n");

} //end printList } //end class BuildList3 class Node {

int num;

Node next;

public Node(int n) { num = n;

next = null;

}

} //end class Node

When run, Program P3.3 builds a sorted linked list from the numbers provided and then prints the numbers in the order that they appear in the list. The following shows some sample output:

Enter some integers ending with 0 9 1 8 2 7 3 6 4 5 0

1 2 3 4 5 6 7 8 9

The first question to answer is, “What defines a linked list?” That’s easy. It’s the (object) variable, essentially a pointer, which points to the first node in the list. So, our class will begin as follows:

public class LinkedList { Node head = null;

. .

} //end class LinkedList

We will use head as our “top of list” variable. Java will initialize head to null when we use a statement like the following, but we do so explicitly to draw attention to its initial value:

LinkedList LL = new LinkedList();

How do we define Node? Well, it depends on the kind of items (the “data”) that we want to store in the list.

If we want a list of integers, we can use this:

class Node { int num;

Node next;

}

If we want a list of characters, we can use this:

class Node { char ch;

Node next;

}

And if we want a list of parts, we can use this:

class Node { Part part;

Node next;

}

As you can see, we would need to change the definition of Node each time we wanted a different kind of linked list. But we would also need to change a method if its code depends on the kind of item in the list. Consider, for example, a method that adds a new node at the head of a list of integers.

public void addHead(int n) {

Node p = new Node(n); //assume Node has the appropriate constructor p.next = head;

head = p;

}

This can be used, for instance, as follows (LL is a LinkedList):

LL.addHead(25);

This will add a node containing 25 at the head of the list, LL.

But if we need a list of characters, we would need to change the heading to this:

public void addHead(char c) and, for a list of Part objects, to this:

public void addHead(Part p)

If there are many methods in the class, these changes could become quite tedious every time we need to change the kind of data stored in our list.

We will use an approach that will minimize the changes required in LinkedList.

Let’s define the class Node as follows:

class Node { NodeData data;

Node next;

public Node(NodeData nd) { data = nd;

next = null;

}

} //end class Node

We write the class in terms of an unspecified, as yet, data type, NodeData. There are two fields, data and next.

Without knowing anything more about NodeData, we can write addHead as follows:

public void addHead(NodeData nd) { Node p = new Node(nd);

p.next = head;

head = p;

}

A class (TestList, say) that wants to use LinkedList must provide a definition of NodeData that is available to LinkedList. Suppose we want a linked list of integers. We can define NodeData as follows (we will explain the need for toString shortly):

public class NodeData { int num;

public NodeData(int n) { num = n;

}

public String toString() { return num + " ";

//" " needed to convert num to a string; may also use "" (empty string) }

} //end class NodeData

And we can build a linked list in reverse order with code such as the following:

LinkedList LL = new LinkedList();

System.out.printf("Enter some integers ending with 0\n");

int n = in.nextInt();

while (n != 0) {

LL.addHead(new NodeData(n)); //NodeData argument required n = in.nextInt();

}

Note that since addHead requires a NodeData argument, we must create a NodeData object with the integer n;

this object is passed to addHead.

How can we print the items in a list? Presumably, we would like a method (printList, say) in the LinkedList class, which does the job. But since LinkedList does not know what NodeData might contain (and it could vary from one run to the next), how can it print the data in a node?

The trick is to let NodeData print itself using the toString method. Here is one way to write printList:

public void printList() { Node curr = head;

while (curr != null) {

System.out.printf("%s", curr.data); //invokes curr.data.toString() curr = curr.next;

}

System.out.printf("\n");

} //end printList

Recall that curr.data is a NodeData object. Since we use it in a context where a string is required, Java will look in the NodeData class for a toString method. Since it finds one, it will use it to print curr.data. The printf statement could also have been written as follows where we call toString explicitly:

System.out.printf("%s ", curr.data.toString());

If LL is a LinkedList, the list can be printed with this statement:

LL.printList();

So far, our LinkedList class consists of the following:

public class LinkedList { Node head = null;

public void addHead(NodeData nd) { Node p = new Node(nd);

p.next = head;

head = p;

}

public void printList() { Node curr = head;

while (curr != null) {

System.out.printf("%s", curr.data); //invokes curr.data.toString() curr = curr.next;

}

System.out.printf("\n");

} //end printList } //end class LinkedList

We could add a method to check whether a linked list is empty.

public boolean empty() { return head == null;

}

If LL is a LinkedList, we can use empty as follows:

while (!LL.empty()) { ...

Now suppose we want to add a method that will build a linked list in “sorted order.” Again, since LinkedList does not know what NodeData might contain, how do we define “sorted order” in LinkedList? Once more, the solution is to let NodeData tell us when one NodeData item is less than, equal to, or greater than another NodeData item.

We can do this by writing an instance method (we’ll call it compareTo) in NodeData. Here it is:

public int compareTo(NodeData nd) { if (this.num == nd.num) return 0;

if (this.num < nd.num) return -1;

return 1;

}

Here, we use the Java keyword this for the first time. If a and b are two NodeData objects, remember that we can call the method with a.compareTo(b). In the method, this refers to the object used to call it. Thus, this.num refers to a.num. We note that the method will work just the same without this because num, by itself, does refer to a.num.

Since the NodeData class we are using has one integer field, num, compareTo reduces to comparing two integers.

The expression a.compareTo(b) returns 0 if a.num is equal to b.num, -1 if a.num is less than b.num, and 1 if a.num is greater than b.num.

Using compareTo, we can write addInPlace as follows:

public void addInPlace(NodeData nd) { Node np, curr, prev;

np = new Node(nd);

prev = null;

curr = head;

while (curr != null && nd.compareTo(curr.data) > 0) { //new value is bigger prev = curr;

curr = curr.next;

}

np.next = curr;

if (prev == null) head = np;

else prev.next = np;

} //end addInPlace

If LL is a LinkedList, we can use it as follows:

LL.addInPlace(new NodeData(25));

This will create a Node with a NodeData object containing 25 and insert this node in the list so that the list is in ascending order.

Program P3.4 reads integers, builds a linked list in ascending order, and prints the sorted list. You will observe that we have dropped the word public from the classes NodeData, Node, and LinkedList. This is merely to allow us to store the entire program in one file, which must be called LinkedListTest.java since the name of the public class is LinkedListTest. Recall that Java requires that a file contain only one public class. We will elaborate on this in Section 3.9.

Program P3.4

import java.util.*;

public class LinkedListTest {

public static void main(String[] args) { Scanner in = new Scanner(System.in);

LinkedList LL = new LinkedList();

System.out.printf("Enter some integers ending with 0\n");

int n = in.nextInt();

while (n != 0) {

LL.addInPlace(new NodeData(n));

n = in.nextInt();

}

LL.printList();

} //end main } //end LinkedListTest class NodeData { int num;

public NodeData(int n) { num = n;

}

public int compareTo(NodeData nd) { if (this.num == nd.num) return 0;

if (this.num < nd.num) return -1;

return 1;

} //end compareTo

public String toString() { return num + " ";

//" " needed to convert num to a string; may also use "" (empty string) }

} //end class NodeData class Node {

NodeData data;

Node next;

public Node(NodeData nd) { data = nd;

next = null;

}

} //end class Node class LinkedList { Node head = null;

public boolean empty() { return head == null;

}

public void addHead(NodeData nd) { Node p = new Node(nd);

p.next = head;

head = p;

}

public void addInPlace(NodeData nd) { Node np, curr, prev;

np = new Node(nd);

prev = null;

curr = head;

while (curr != null && nd.compareTo(curr.data) > 0) { //new value is bigger prev = curr;

curr = curr.next;

}

np.next = curr;

if (prev == null) head = np;

else prev.next = np;

} //end addInPlace public void printList() { Node curr = head;

while (curr != null) {

System.out.printf("%s", curr.data); //invokes curr.data.toString() curr = curr.next;

}

System.out.printf("\n");

} //end printList } //end class LinkedList

The following is a sample run of Program P3.4.

Enter some integers ending with 0 9 1 8 2 7 3 6 4 5 0

1 2 3 4 5 6 7 8 9

Dalam dokumen Pelajari tentang Advanced topics in Java (Halaman 88-95)