letter = letter.toLowerCase();However, this is not feasible. Why not? letter is of type char, which is a primitive. It is not an object and thus cannot have methods to act on. Refer to the reading on the distinction between primitives and references.
public static char toLowerCase(char ch)There are two types of methods: static (class) methods or instance methods. As the names should make clear, one type operates on the class level, while another operates at the instance level. A class method cannot access instance variables--it can only access class variables (those declared with the static keyword), whereas an instance method (those NOT declared with the static keyword) can access both. Why? Class variables are shared among all instances in the class.
To use a class method, the method call must be preceded by the class name similar to how calls to instance methods must be preceded by the particular instance. Thus, to turn a character to lowercase, the proper code is:
letter = Character.toLowerCase(letter);
Long ago, some organization made the American Standard Code for Information Interchange (ASCII) that defines this mapping. Java actually uses Unicode, which is a superset of ASCII. In this course, we will only be interested in ASCII. The first thing to note from the table is that the letters are all sequential--at least all the uppercase letters and all the lowercase letters. In the assignment, you are asked to put counts of letters in an array of length 26. Since the letters are all in order, it is really easy to find which bin belongs to which letter. If you had a lowercase letter, you can find the bin it belongs to with the following code:
letter - 'a'How does this work? If letter was an a, then
'a' - 'a' == 0because 97 - 97 = 0. Thus, letter belongs in the bin with index 0. Look at the ASCII table to see if you can see where the 97 came from. Similarly, if letter was a b, then
'b' - 'a' == 1because 98 - 97 = 1.
If we have the bin number, how can we convert back to a char? Is it sufficient to add 'a', i.e., ('a' + x), where x is the bin number?
Not quite, because Java will convert the 'a' to 97 and then add that to x, resulting in an integer. To get the char, you have to cast that number into a character via:
(char)('a' + x)If x were 4, then the resulting character would be 'e', which is the fifth character of the alphabet. We will talk more about casting later when we talk about inheritance.
if ((letter >= 97) && (letter <= 122)) { // do something }That is bad style, because it requires you to remember that 97 is the ASCII equivalent of 'a' and that 122 is the equivalent of 'z'. A much better way would be to let Java do the work for you:
if ((letter >= 'a') && (letter <= 'z')) { // do something }In fact, we do NOT want to see the first version! You have been warned!
Another way would be to take advantage of the API:
if (Character.isLetter(letter)) { // do something }then you don't even have to convert the character to lowercase first.
public class ListNode { public int data; public ListNode next; }There are two things of interest here. First, the data fields are public. This is actually not the way one would implement nodes in the "real" world. The "right" way to do this would be to have ListNode be an inner class to the LinkedIntList class (or whatever class is using it), thus the outside world cannot see it. However, that's beyond the scope of this course, so we'll be satisfied with this way. Second, ListNode has a variable, next, that refers to the class itself. How is this possible? If you recall, all variables with object types are actually pointers to objects of that type. It is merely an address to a ListNode object. The compiler only checks that everything that is assigned to next is a ListNode.
ListNode list;The variable list is not itself a node. It's a variable that is capable of referring to a node. We don't have an actual node until we call new:
ListNode list = new ListNode();This constructs a new node and tells Java to have the variable list refer to it:
+------+------+ +---+ | data | next | list | +-+---> | | | +---+ +------+------+What do we want to do with this node? We want to store 3 in its data field (list.data) and we want its next field to point to a new node:
list.data = 3; list.next = new ListNode();which leads us to this situation:
+------+------+ +------+------+ +---+ | data | next | | data | next | list | +-+---> | 3 | +--+---> | | | +---+ +------+------+ +------+------+Notice that the result of the call on new is not stored in list; it is stored in list.next. Now we want to assign the second node's data field (list.next.data) to the value 7 and assign the second node's next field to refer to a third node:
list.next.data = 7; list.next.next = new ListNode();which leads us to this situation:
+------+------+ +------+------+ +------+------+ +---+ | data | next | | data | next | | data | next | list | +-+---> | 3 | +--+---> | 7 | +--+---> | | | +---+ +------+------+ +------+------+ +------+------+Finally, we want to set the data field of this third node to 12 (list.next.next.data) and we want to set its next field to null. The keyword null is a Java word that means "no object" (what i referred to in lecture as "nothingness"). This provides a "terminator" for the linked list (a special value that indicates that we are at the end of the list). So we'd execute these statements:
list.next.next.data = 12; list.next.next.next = null;which leaves us in this situation:
+------+------+ +------+------+ +------+------+ +---+ | data | next | | data | next | | data | next | list | +-+---> | 3 | +--+---> | 7 | +--+---> | 12 | / | +---+ +------+------+ +------+------+ +------+------+We draw a diagonal line through the last next field as a way to indicate that it's value is null. Once we've set up this list, we can print its value as follows:
System.out.println(list.data + " " + list.next.data + " " + list.next.next.data);Obviously this is a very tedious way to manipulate a list. It's much better to write code that involves loops to manipulate lists. But it takes a while to get used to this idea, so we're first going to practice how to do some raw list operations without a loop. In section, we will go over 10 different exercises that involve list operations. Each will have a "before" picture and an "after" picture. The challenge is to write code that gets you from the one state to the other state. As an example, suppose that you have two variables of type ListNode called p and q and that you have the following situation:
+------+------+ +------+------+ +---+ | data | next | | data | next | p | +-+---> | 2 | +--+---> | 4 | / | +---+ +------+------+ +------+------+ +------+------+ +------+------+ +---+ | data | next | | data | next | q | +-+---> | 3 | +--+---> | 9 | / | +---+ +------+------+ +------+------+and you want to get to this situation:
+------+------+ +------+------+ +------+------+ +---+ | data | next | | data | next | | data | next | p | +-+---> | 2 | +--+---> | 4 | +--+---> | 3 | / | +---+ +------+------+ +------+------+ +------+------+ +------+------+ +---+ | data | next | q | +-+---> | 9 | / | +---+ +------+------+How do we do it? First, think about how many variables of type ListNode there are. Some would say two (p and q). Others would say four (p, q and the two non-null links). But in fact, there are six different variables of type ListNode.
1 2 3 +------+------+ +------+------+ +---+ | data | next | | data | next | p | +-+---> | 2 | +--+---> | 4 | / | +---+ +------+------+ +------+------+ 4 5 6 +------+------+ +------+------+ +---+ | data | next | | data | next | q | +-+---> | 3 | +--+---> | 9 | / | +---+ +------+------+ +------+------+Which of these variables has to change in value? The answer is that the boxes numbered 3, 4 and 5 have to be changed. If we change them appropriately, we'll be done. But care must be taken: order can be important. For example, we eventually want box 5 to be set to null, but we don't want to start with that:
q.next = null;If we do that, we'll lose track of our reference to the node with 9 in it. Of the three values, the one that is safe to change is box 3 because it's currently null. So we begin by setting it to point to the node with 3 in it:
p.next.next = q;Now that we've used the value of box 4 to reset box 3, we can reset box 4. It's supposed to point to the node that has 9 in it. We can do this by "leap frogging" over the current node it's pointing to:
q = q.next;Now we just have to reset box 5. But we can no longer refer to box 5 as q.next because we've changed q. Now, we have to refer to it this way:
p.next.next.next = null;Putting these three lines together, we see the code that is needed to get from the initial state to the final state:
p.next.next = q; q = q.next; p.next.next.next = null;Obviously this can be very confusing. It is essential that you draw pictures to keep track of what is pointing where and what is going on when this code executes. It's the only way to master linked list code.