• Tidak ada hasil yang ditemukan

Example: Palindrome

Dalam dokumen Pelajari tentang Advanced topics in Java (Halaman 98-101)

Linked Lists

3.11 Example: Palindrome

Consider the problem of determining whether a given string is a palindrome (the same when spelled forward or backward). The following are examples of palindromes (ignoring case, punctuation, and spaces):

civic Racecar

Madam, I'm Adam.

A man, a plan, a canal, Panama.

If all the letters were of the same case (upper or lower) and the string (word, say) contained no spaces or punctuation marks, we could solve the problem as follows:

compare the first and last letters

if they are different, the string is not a palindrome

if they are the same, compare the second and second to last letters if they are different, the string is not a palindrome

if they are the same, compare the third and third to last letters

We continue until we find a nonmatching pair (and it’s not a palindrome) or there are no more pairs to compare (and it is a palindrome).

This method is efficient, but it requires us to be able to access any letter in the word directly. This is possible if the word is stored in an array and we use a subscript to access any letter. However, if the letters of the word are stored in a linked list, we cannot use this method since we can access the letters only sequentially.

To illustrate how linked lists may be manipulated, we will use linked lists to solve the problem using the following idea:

1. Store the original phrase in a linked list, one character per node.

2. Create another list containing the letters only of the phrase, all converted to lowercase;

call this list1.

3. Reverse list1 to get list2.

4. Compare list1 with list2, node by node, until we get a mismatch (the phrase is not a palindrome) or we come to the end of the lists (the phrase is a palindrome).

Consider the phrase Damn Mad!; this will be stored as follows:

D head

a m n M a d !

Step 2 will convert it to this:

Step 3 will reverse this list to get the following:

Comparing list1 and list2 will reveal that Damn Mad! is a palindrome.

We will write a program that prompts the user to type a phrase and tells her whether it is a palindrome. It then prompts for another phrase. To stop, the user must press the Enter key. The following is a sample run:

Type a phrase. (To stop, press "Enter" only): Damn Mad!

is a palindrome

Type a phrase. (To stop, press "Enter" only): So Many Dynamos!

is a palindrome

Type a phrase. (To stop, press "Enter" only): Rise to vote, sir.

is a palindrome

Type a phrase. (To stop, press "Enter" only): Thermostat is not a palindrome

Type a phrase. (To stop, press "Enter" only): A Toyota’s a Toyota.

is a palindrome

Type a phrase. (To stop, press "Enter" only):

Previously, we worked with a linked list of integers. But, now, we need a linked list of characters. If we did things right, we should need to make changes in the NodeData class only. We should not have to change anything in the LinkedList class, and we won’t. Here is what NodeData should look like:

public class NodeData { char ch;

public NodeData(char c) { ch = c;

}

public char getData() {return ch;}

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

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

return 1;

}

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

}

} //end class NodeData d

list1

a m n m a d

d list2

a m n m a d

We have added an accessor, getData, to return the value in the only data field, ch. The other changes essentially involve changing int to char.

We will write a function, getPhrase, which will read the data and store the characters of the phrase in a linked list, one character per node. The function returns the newly created list. This function must build the linked list in the order in which the characters are typed by the user—each new character is added at the end of the list.

The function achieves this by first reading the entire phrase into a String variable using nextLine. Then, starting at the last character and going backward, it inserts each new character at the head of the linked list. (We could also start at the first character and add each new character at the tail of the list, but this requires more work.) Here is the function:

public static LinkedList getPhrase(Scanner in) { LinkedList phrase = new LinkedList();

String str = in.nextLine();

for (int h = str.length() - 1; h >= 0; h--) phrase.addHead(new NodeData(str.charAt(h)));

return phrase;

} //end getPhrase

Next, we write a function, lettersLower, which, given a linked list of characters, creates another list containing the letters only, all converted to lowercase. As each letter is encountered, it is converted to lowercase and added to the tail of the new list using addTail. Here is lettersLower:

public static LinkedList lettersLower(LinkedList phrase) { LinkedList word = new LinkedList();

while (!phrase.empty()) {

char ch = phrase.getHeadData().getData();

if (Character.isLetter(ch)) word.addTail(new NodeData(Character.toLowerCase(ch)));

phrase.deleteHead();

}

return word;

} //end lettersLower

The expression phrase.getHeadData() returns the data field (of type NodeData) of the first node in the list. The accessor, getData, in the NodeData class returns the character stored in the node.

We now have everything we need to write Program P3.5, which solves the palindrome problem. It assumes that the NodeData and LinkedList classes are declared public and stored in separate files.

Program P3.5

import java.util.*;

public class P3_5Palindrome {

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

System.out.printf("Type a phrase. (To stop, press 'Enter' only): ");

LinkedList aPhrase = getPhrase(in);

while (!aPhrase.empty()) {

LinkedList w1 = lettersLower(aPhrase);

System.out.printf("Converted to: ");

w1.printList();

LinkedList w2 = w1.copyList();

w2.reverseList();

if (w1.equals(w2)) System.out.printf("is a palindrome\n");

else System.out.printf("is not a palindrome\n");

System.out.printf("Type a phrase. (To stop, press 'Enter' only): ");

aPhrase = getPhrase(in);

}

} //end main

public static LinkedList getPhrase(Scanner in) { LinkedList phrase = new LinkedList();

String str = in.nextLine();

for (int h = str.length() - 1; h >= 0; h--) phrase.addHead(new NodeData(str.charAt(h)));

return phrase;

}

public static LinkedList lettersLower(LinkedList phrase) { LinkedList word = new LinkedList();

while (!phrase.empty()) {

char ch = phrase.getHeadData().getData();

if (Character.isLetter(ch)) word.addTail(new NodeData(Character.toLowerCase(ch)));

phrase.deleteHead();

}

return word;

}

} //end class P3_5Palindrome

Note

The solution presented was used mainly to show how linked lists can be manipulated. The problem can be

solved more efficiently using character arrays or strings where we would have direct access to any character of the

given phrase. For instance, we would be able to compare the first and last letters directly. Even in the solution presented

here, we could clean up the phrase as it is being input by retaining letters only and converting them to lowercase. As an

exercise, write a program to solve the problem using arrays.

Dalam dokumen Pelajari tentang Advanced topics in Java (Halaman 98-101)