"Recursive" listToString()-method in linked lists - java

Currently visiting a power class due to preparations for the Java exam, we basically came up to a question:
class Node{ //List node
String text;
Node next;
}
class Stringbuilder{
...
void append(String s) //attaches s
String toString() //returns the fully built String
}
public static String listToString(Node first){
//TO DO
}
Our task is to define listToString. We did an iterative method that is definitely working, but I was curious about this recursive alternative:
public static String listToString(Node first){
StringBuilder sb = new StringBuilder();
if(first == null) return "";
String result = first.text;
return result + sb.append(first.next.text).toString();
}
So the question is: Can this work?

There is nothing recursive in the listToString method you posted. It has to call itself to be recursive.
public static String listToString(Node first)
{
if(first == null) return "";
String result = first.text;
return result + " " + listToString(first.next);
}

Related

toString() for a List Stack

i have a class for List, Node, and Stack.
The classes List, Node are all done, now i want to finish my Stack.class, which uses my List.class.
Now i am in my main method and i want to try out my push/pop methods, but don't know how to output them as strings.
I did this in my List.class, but don't know how to recreate it for the Stack.class.
Can someone help me? Thanks.
public class Stack {
private List list;
public Stack() {
list = new List();
}
public class List{
public String toString() {
Node temp = head;
String string = "";
while (temp != null && temp.getNext() != null) {
string = string + temp.getElement() + ", ";
temp = temp.getNext();
}
if (temp != null) {
string = string + temp.getElement() + ".";
}
return string;
}
In your Stack class, you could invoke list.toString(). Something like
public String toString() {
return String.format("Stack: %s", list.toString());
}
you have to "concatenate" the 2 toString() method.
So you have to create a new toString() in your Stack class.
public class Stack {
private List list;
public Stack() {
list = new List();
}
public String toString()
{
String myreturn = "//Anything you need" + list.toString();
return myreturn;
}}
You can handle each element in the list:
For example, if you need get list values by comma separate:
public String toString() {
return list.stream()
.map(Objects::toString)
.collect(Collectors.joining(","));
}
Or you need also modify each value:
public String toString() {
return list.stream()
.map(p -> "[" + p.toString() + "]")
.collect(Collectors.joining(","));
}

How to print BinaryTree in Java?

public class BinaryNode<T> {
protected T data;
protected BinaryNode<T> left;
protected BinaryNode<T> right;
public BinaryNode(T element) {
if (element == null)
throw new IllegalArgumentException();
this.data = element;
left = null;
right = null;
}
public int height() {
int leftH = -1, rightH = -1;
if (left != null)
leftH = left.height();
if (right != null)
rightH = right.height();
return Math.max(leftH, rightH) + 1;
}
public int size() {
int leftS = 0, rightS = 0;
if (left != null)
leftS = left.size();
if (right != null)
rightS = right.size();
return leftS + rightS + 1;
}
private String spaces(int count){
String spaces="";
while(count>0){
spaces=spaces+" ";
count=count-1;
}
return spaces;
}
public String toString(){
String str="";
if(left!=null)
str=str+spaces(left.height())+left.toString(); //left
str=str+spaces(left.height()-1)+data.toString()+"\n";//root
if(right!=null)
str=str+spaces(right.height())+right.toString();//right
return str;
}
}
I need to build toString function in BinaryNode class. The method works so that if we print the string it returns we will get one print line per vertex in the tree. In this row, 2*d spaces will appear, where d is the depth of the vertex in the tree and then the information on the vertex will be printed (in the same row).
For example for the following BinarySearchTree (The examples in BinarySearchTree so it will be easier to understand how it needs to print):
BinarySearchTree t4 = new BinarySearchTree(c);
t4.insert(8);
t4.insert(7);
t4.insert(6);
t4.insert(5);
t4.insert(4);
t4.insert(3);
t4.insert(2);
t4.insert(1);
System.out.println("----------t4:----------\n" + t4);
toString need to print:
----------t4:----------
1
2
3
4
5
6
7
8
I wrote above the code that I create but it's doesn't working, the problem is that I know why it doesn't working but I don't know how to fix it.
Basically, I don't know to do it.
Appreciate any help.
Got the solution for those who need it:
private String spaces(int count){
String spaces="";
while(count>0){
spaces=spaces+" ";
count=count-1;
}
return spaces;
}
private String toString(int depth){
String str="";
if(left!=null)
{
str=str+left.toString(depth+1);
}
str=str+spaces(depth)+data.toString()+"\n";
if(right!=null)
{
str=str+right.toString(depth+1);
}
return str;
}
private String toString(String str){
if(left!=null)
str=str+left.toString(" ");
str=str+data.toString()+"\n";
if(right!=null)
str=str+right.toString(" ");
return str;
}

How do I print an Object of MyList?

Any time I try to print a MyList object I get 'User#' some hex number.
Can someone help me out with a printing function or a way to print in the main? I heard of trying to Override the toString function, but I couldn't seem to get that to work and am not sure if thats the correct thing to do.
public class MyList {
private ListElement head, tail; //Forward declaration
void add(Object value) {
if (tail != null) {
tail.next = new ListElement(value);
tail = tail.next;
}
else {
head = tail = new ListElement(value);
}
}
Object remove()
{
assert head != null; // don't remove on empty list
Object result = head.value;
head = head.next;
if (head == null) { //was that the last?
tail = null;
}
return result;
}
//Nested class needed only in the implementation of MyList
private class ListElement {
ListElement(Object value) {this.value = value;}
Object value;
ListElement next; //defaults to null as desired
}
public static void main(String[] args) {
myList anInstance = new myList();
String someValue = "A list element";
anInstance.add(someValue);
String anotherValue = "Another value";
anInstance.add(anotherValue);
}
}
The override I tried went something like this:
#Override
public String toString() {
return String.format(this.head);
}
}
You state:
The override I tried went something like this:
#Override
public String toString() {
return String.format(this.head);
}
}
That's a start, now instead of just printing the head, use a while loop to iterate through the entire list, and create a new String that contains the information from all the elements. Then return that String.
i.e.,
#Override
public String toString() {
ListElement tail = this.tail;
// or you might need to start at the head element depending on which way
// you will iterate.
String returnString = "";
// use a while loop here to go through your list
// and add pertinent info from each element to the returnString
return returnString;
}
}
Note that if you were wanting to be super-efficient, you'd use a StringBuilder to do your concatenation, however for your application, this is likely over-kill and not necessary.
Note 2: Hopefully ListElement has a toString() method, and if so, use it inside of your while loop to get each element's info.
Next iteration:
#Override
public String toString() {
String returnString = "";
ListElement currentElement = this.tail;
while (currentElement != null) {
returnString += // *** get toString() info from currentElement
currentElement = // **** reset currentElement to next element
}
return returnString;
}
}
The default toString() method prints the memory address of the object (that Hex number you're seeing).
If you want something different, you need to:
#Override
public String toString()
{
//do stuff to build a string that describes your object
//return that string you just built
}
This code is an untested implementation of the toString method. Try it out.
#Override
public String toString()
{
String myString = "";
ListElement currentElement = head;
while (currentElement.next != null)
{
if (myString.length > 0)
{
myString += ",";
}
myString += currentElement.value.toString();
currentElement = currentElement.next;
}
return myString;
}

Sorting and comparing XML from Java

I was given XML and schema files. My goal was to output all data from the XML (without duplicates) and order this list by the date of birth. Currently I got all data printed out (with duplicates) and I don't know what to do next. I've tried different things, but unsuccessfully.
HashSet will depend on the Node.equals() method to determine equality, and you're adding distinct nodes, albeit with the same underlying text. From the doc:
adds the specified element e to this set if this set contains no
element e2 such that (e==null ? e2==null : e.equals(e2))
I would extract the underlying text (String) from the Node, and a HashSet<String> will determine uniqueness correctly.
EDIT
After reading the post again I realised I need to remove dups too so:
You can use a TreeSet to impose unqiueness and sort by DOB - I presume that a person with the same first name, surname and date of birth is the same person.
First I would wrap your Node in a class that implements Comparable and that also does the getting of all those properties you have. The wrapper needs to implement Comparable as the TreeSet uses this method to decide whether elements are different (a.compareTo(b) != 0) and also how to order them.
public static final class NodeWrapper implements Comparable<NodeWrapper> {
private static final SimpleDateFormat DOB_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
private final Element element;
private final Date dob;
private final String firstName;
private final String surName;
private final String sex;
public NodeWrapper(final Node node) {
this.element = (Element) node;
try {
this.dob = DOB_FORMAT.parse(initDateOfBirth());
} catch (ParseException ex) {
throw new RuntimeException("Failed to parse dob", ex);
}
this.firstName = initFirstName();
this.surName = initSurnameName();
this.sex = initSex();
}
private String initFirstName() {
return getNodeValue("firstname");
}
private String initSurnameName() {
return getNodeValue("surname");
}
private String initDateOfBirth() {
return getNodeValue("dateofbirth");
}
private String initSex() {
return getNodeValue("sex");
}
private String getNodeValue(final String name) {
return element.getElementsByTagName(name).item(0).getTextContent();
}
public Node getNode() {
return element;
}
Date getDob() {
return dob;
}
public String getFirstName() {
return firstName;
}
public String getSurName() {
return surName;
}
public String getDateOfBirth() {
return DOB_FORMAT.format(dob);
}
public String getSex() {
return sex;
}
public int compareTo(NodeWrapper o) {
int c;
c = getDob().compareTo(o.getDob());
if (c != 0) {
return c;
}
c = getSurName().compareTo(o.getSurName());
if (c != 0) {
return c;
}
return getFirstName().compareTo(o.getFirstName());
}
#Override
public int hashCode() {
int hash = 5;
hash = 47 * hash + (this.dob != null ? this.dob.hashCode() : 0);
hash = 47 * hash + (this.firstName != null ? this.firstName.hashCode() : 0);
hash = 47 * hash + (this.surName != null ? this.surName.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final NodeWrapper other = (NodeWrapper) obj;
if (this.dob != other.dob && (this.dob == null || !this.dob.equals(other.dob))) {
return false;
}
if ((this.firstName == null) ? (other.firstName != null) : !this.firstName.equals(other.firstName)) {
return false;
}
if ((this.surName == null) ? (other.surName != null) : !this.surName.equals(other.surName)) {
return false;
}
return true;
}
#Override
public String toString() {
return "FirstName: " + getFirstName() + ". Surname: " + getSurName() + ". DOB: " + getDateOfBirth() + ". Sex: " + getSex() + ".";
}
}
So if the date of birth, surname and firstname are all equal we assume it is the same person - we return 0. It is good practice, if using compareTo in this way to make it consistent with equals so that if a.compareTo(b)==0 then a.equals(b), I have added the required equals and hashCode methods as well.
Now you can use a TreeSet in your code which will automatically sort and guarantee unqiueness:
final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new File("file.xml"));
final Set<NodeWrapper> inimesteList = new TreeSet<NodeWrapper>();
final NodeList isa = doc.getElementsByTagName("isa");
for (int i = 0; i < isa.getLength(); i++) {
inimesteList.add(new NodeWrapper(isa.item(i)));
}
final NodeList ema = doc.getElementsByTagName("ema");
for (int i = 0; i < ema.getLength(); i++) {
inimesteList.add(new NodeWrapper(ema.item(i)));
}
final NodeList isik = doc.getElementsByTagName("isik");
for (int i = 0; i < isik.getLength(); i++) {
inimesteList.add(new NodeWrapper(isik.item(i)));
}
System.out.println();
System.out.println("Total: " + inimesteList.size());
for (final NodeWrapper nw : inimesteList) {
System.out.println(nw);
}
I have also added a toString method and used that to print the nodes - this makes the code much cleaner.
The Document approach, while seeming simpler than JAXB, is riddled with this sort of tedium. As you already have a schema I would strongly recommend that you make the move to xjc and JAXB unmarshalling - this will make this sort of stuff hundereds of times easier.
Its better to create a Java Bean (POJO) with the single node details. Override equals() and hashcode() in the same. Store all the Node data into the List of Bean. Then use LinkedHashSet to remove duplicates. Implement Comparable or use Comparator and Collections.sort() to sort the same.
Extend or encapsulate Node in another class and override equals() and hashcode() in the same. Store all the Nodes into the List of new class instance. Then use LinkedHashSet to remove duplicates. Implement Comparable or use Comparator and Collections.sort() to sort the same.

How to recursively concatenate a list of string elements

I am looking at examples getting ready for an exam, and frankly, I am not very good with either recursion or lists, but particularly lists.
A node class is given, it will hold strings (not generic) write a recursive java function called concat that takes a node representing the head of a linked list and returns a string representing the concatenation of all the elements of the list if the list is empty the string should be as well.
Any help would be appreciated.
(The following is what I had type before I asked the question:)
public static String FindConcat(Node head) {
String s = "";
if(head == null) return s;
else if(head.next = null) {
s += head.data;
return s;
}
else {
}
}
Thanks for the repsonses.
In this case what recursion is finding the base case and how to "devide" the data down to this base case. So first define your "base case".
Base case: argument to the function is null
Till you get the the base case, append the text of the node and skip the first element
This is your method:
public static String FindConcat(Node head) {
if (head == null)
return ""; // base case
// devide it down (run recursive FindConcat on the _next_ node)
return head.data + FindConcat(head.next);
}
This simple example will print hello this is a linked list:
public class Test {
// this is a very basic Node class
static class Node {
String text;
Node next;
public Node(String text) {
this.text = text;
}
// used for building the list
public Node add(String text) {
next = new Node(text);
return next;
}
}
// this is the recursive method concat
public static String concat(Node node) {
if (node == null)
return "";
return node.text + " " + concat(node.next);
}
public static void main(String[] args) {
// build the list
Node head = new Node("hello");
head.add("this").add("is").add("a").add("linked").add("list");
// print the result of concat
System.out.println(concat(head));
}
}
If your node is null, return an empty string.
Otherwise, get the string, make a recursive call (to get the concatenated result for the rest of the nodes), and append that to the string and return the result.
since this sounds like homework, i'll make a suggestion.
start by writing the method that will work if the list only has one element (ie there is no next node). use that as the basis for your recursive call.
Recursive traversal of a linked list generally looks like seeing if you're at the end of the list (the reference you got was null), and if you're not, doing something to a recursive call upon the next element of the list, and if you are, doing the base case thing. Assuming that nodes look like this from the outside:
public class Node{
public Node getNext();
public String toString();
}
...your method looks like this (inside the class you're using to run this out of):
public String concatList(Node head){
if(head == null){
return ""; //empty list is a null pointer: return empty string
}
return head.toString() + concatList(head.getNext());
}
The end of the list, or no list at all, looks the same- a null pointer- and returns the blank string, as specified; everything else takes the current node and concatenates it to the list created by getting the concatenated version of the entire remainder of the string.
Be careful: if something's corrupted your list so it's actually a loop, this has no checks for that and will run forever until it runs out of stack memory, unless Java correctly detects the loop optimization of this recursive function and it will simply run forever.
Here is a very complete example:
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
public class RecurisveLinkedListExample
{
public static String concat(final Node node)
{
if (node == null)
{
return "";
}
else
{
return node.getData() + concat(node.getNext());
}
}
public static void main(String[] args)
{
final List<String> input = Arrays.asList("A", "B", "C", "D");
final Node head = new Node(null, input.get(0));
Node previous = head;
for (int i = 1; i < input.size(); i++)
{
previous = previous.addNext(input.get(i));
}
System.out.println(concat(head));
}
public static class Node
{
private final UUID id;
private final Node previous;
private final String data;
private Node next;
public Node(final Node previous, final String data)
{
this.previous = previous;
this.data = data;
this.next = null;
this.id = UUID.randomUUID();
}
public Node getPrevious()
{
return previous;
}
public String getData()
{
return data;
}
public Node addNext(final String data)
{
this.next = new Node(this, data);
return this.next;
}
public Node getNext()
{
return next;
}
#Override
public String toString()
{
return String.format("%s:%s:%s",
this.previous == null ? "HEAD" : this.previous.id,
this.data,
this.next == null ? "TAIL" : this.next.id);
}
}
}

Categories