Sorting Custom Linked List in Java - java

I have created my own linked list implementation that stores a first name and a last name. Now I am trying to sort the list of names alphabetically by the last name, which I am having trouble doing. I have read about possibly using collections.sort but I am not sure how I can modify my class so I can use collections.sort or if that is even a good way to go about it or not. Below is what I have done so far. If anyone could help me with this it would be greatly appreciated. What I want to accomplish is that when I print it will print Joe Rogers, Bill Thomas, Greg West, which would mean it was sorted by last name.
Edit: Thanks everyone for your quick responses, I really appreciate it.
class Test {
public static void main(String[] args)
{
LinkedList l = new LinkedList();
l.insert("Greg", "West");
l.insert("Joe", "Rogers");
l.insert("Bill", "Thomas");
l.print();
Collections.sort(l) // I am unable to get this to work
}
public static class myLink {
public myLink next;
public String first;
public String last;
public myLink(String first, String last)
{
this.first = first;
this.last = last;
}
public void print()
{
System.out.printf("%s %s\n",first,last);
}
}
public static class LinkedList {
private myLink linkedList;
public LinkedList()
{
linkedList = null;
}
public void insert(String first, String last)
{
myLink li = new myLink(first, last);
li.next = linkedList;
linkedList = li;
}
public void print()
{
myLink c = linkedList;
while(c != null)
{
c.print();
c = c.next;
}
}
}
}

LinkedList will work for you. You only need your Person class, and a customised Comparator as in below example.
public class Person {
String first;
String last;
public Person(String f, String l) {
this.first = f;
this.last = l;
}
}
public class LinkExample {
public static void main(String[] args) {
LinkedList<Person> pList = new LinkedList<Person>();
pList.add(new Person("AFirst","ZLast"));
pList.add(new Person("BFirst","BLast"));
Collections.sort(pList, new Comparator<Person>() {
public int compare(Person p1, Person p2) {
return p1.last.compareTo(p2.last);
}
});
System.out.println(pList.pollFirst().last);
System.out.println(pList.pollFirst().last);
}
}

I have tried using Java's linked list, but the add method only lets you use a single string
No, you can add your class as well. Simply implements Comparable interface add put your logic in overridden compareTo() method.
Use Collections.sort() to sort the list.
sample code:
public static void main(String[] args) {
LinkedList l = new LinkedList();
l.add(new MyLink("Greg", "West"));
l.add(new MyLink("Joe", "Rogers"));
l.add(new MyLink("Bill", "Thomas"));
Collections.sort(l);
for(MyLink link:l){
link.print();
}
}
public static class MyLink implements Comparable<MyLink>{
public MyLink next;
public String first;
public String last;
public MyLink(String first, String last) {
this.first = first;
this.last = last;
}
public void print() {
System.out.printf("%s %s\n", first, last);
}
#Override
public int compareTo(MyLink o) {
int result = this.last.compareTo(o.last);
if(result==0){
result = this.first.compareTo(o.first);
}
return result;
}
}
output:
Joe Rogers
Bill Thomas
Greg West
You can achieve it without implementing Comparable interface.
Simply use Collections.sort(List,Comparator) method.
sample code:
Collections.sort(l,new Comparator<MyLink>(){
#Override
public int compare(MyLink o1, MyLink o2) {
int result = o1.last.compareTo(o2.last);
if(result==0){
result=o1.first.compareTo(o2.first);
}
return result;
}
});
Note:
Never use build in class's name for your class that might sometime create confusion
Respect Java Naming convention.

I'd create a Person bean object which:
contains the firstname and surname, and
implements Comparable to sort on the surname
Then all you have to do is put all your Person objects in an ArrayList, and use Collections.sort() to get them in the right order.

You can have your class myLink implement Comparable interface. Then override compareTo() method as per your requirement.Then you can sort using Collections.sort(collection);
For more info read the documentation.
Also take care of Java naming conventions. myLink should be MyLink and so on...
This will sort the Collection of myLink . But if you want to sort your custom LinkedList class I would suggest create a method sort() in class LinkedList. In this method create a List of all your myLink instances (You have reference to the head). Then call Collections.sort() here and return Sorted Collection.

Related

TreeSet CompareTo not giving desirable result

I am trying to create a set of all letters in all the words in a dictionary.
I am using a TreeSet for that as I have to do lot's of compare operations.
public class main {
public static void main(String[] args) {
Set<String> lines = new TreeSet<>();
lines.add("ba");
DictAwareSolver myGuesser = new DictAwareSolver(lines);
myGuesser.makeGuess();
}
}
This is my class which is operating on the set
package solver;
import sun.reflect.generics.tree.Tree;
import java.util.*;
import java.lang.System;
public class DictAwareSolver extends HangmanSolver
{
private Set<String> dict;
TreeSet<Node> myTree = new TreeSet<>();
//getters
public Set<String> getDict() {
return dict;
}
// methods
public DictAwareSolver(Set<String> dictionary) {
this.dict = dictionary;
// Implement me!
} // end of DictAwareSolver()
#Override
public void newGame(int[] wordLengths, int maxIncorrectGuesses)
{
// Implement me!
} // end of newGame()
#Override
public char makeGuess() {
Set<String> guessDict = getDict();
Iterator dictItr = guessDict.iterator();
while (dictItr.hasNext())
{
String word = (String) dictItr.next();
for (int i = 0; i<word.length(); i++)
{
Node temp = new Node(word.charAt(i));
myTree.add(temp);
}
}
Iterator treeItr = myTree.iterator();
while (treeItr.hasNext())
{
Node n = (Node) treeItr.next();
System.out.println(n.getLetter() + "-->"+n.getFrequency());
}
// TODO: This is a placeholder, replace with appropriate return value.
return '\0';
} // end of makeGuess()
#Override
public void guessFeedback(char c, Boolean bGuess, ArrayList< ArrayList<Integer> > lPositions)
{
// Implement me!
} // end of guessFeedback()
} // end of class DictAwareSolver
class Node implements Comparable<Node>{
private char letter;
private int frequency;
public Node(char letter)
{
this.letter = letter;
this.frequency = 1;
}
public void countIncrementer()
{
int newCount = getFrequency()+1;
setFrequency(newCount);
}
// getters
public char getLetter() {
return letter;
}
public int getFrequency() {
return frequency;
}
// setters
public void setFrequency(int frequency) {
this.frequency = frequency;
}
#Override
public int compareTo(Node o) {
if (getLetter() == o.letter)
{
o.countIncrementer();
return 0;
}
else if (getLetter() > o.getLetter())
{
return 1;
}
else
{
return -1;
}
}
}
When I am running this whatever I am adding 1st is giving a count of 2. As in this case output is
a-->1
b-->2
but I am expecting
a-->1
b-->1
It will be really helpful if you can point out what is the problem. From what I can think of it should be something in my o.countIncrementer(); in my compareTo method. I am new to java.
The code is making the assumption that the TreeSet will only call the comparator against an equal element if one already exists in the set, and if it does such a comparison, it will only do it exactly once. However, this is not how TreeSet is implemented. Looking at the API documentation for TreeSet, there are no guarantees as to how the comparisons will occur or with what frequency. Since this is not a documented part of the API, the authors of TreeSet are free to implement this functionality in any reasonable manner they wish, so long as it meets the documented API. In fact, they are also allowed to change how it's implemented between versions (e.g. Java 6 & Java 7), or between different implementations (e.g. Oracle vs. IBM).
In short, if the documentation does not guarantee a behavior, your code should not rely on that behavior.
To go into the specific behavior you're seeing, the first element added to a TreeSet (in the versions of Java you're using) is compared against itself. While this is perhaps surprising, it is not disallowed by the API. There may or may not be a good reason for this (I believe the check was added in Java 7 to force a NullPointerException to be thrown when a null is added as the first element to a TreeSet that disallows nulls per this bug). However, in the end, the reason for the check shouldn't matter to users of the API, since it's not disallowed in the API.
public static void main(String[] args) {
System.out.printf("Java vendor & version: %s %s\n", System.getProperty("java.vendor"), Runtime.version());
TreeSet<Character> set = new TreeSet<>(new LoggingComparator<>());
set.add('a');
}
private static class LoggingComparator<T extends Comparable<? super T>> implements Comparator<T> {
#Override
public int compare(T o1, T o2) {
System.out.println(o1 + " <=> " + o2);
return o1.compareTo(o2);
}
}
Java vendor & version: Oracle Corporation 11.0.4+10-LTS
a <=> a

Generalized List as a parameter for a method

Say I have a simple class like this:
public class BasicObject {
private String name;
public BasicObject (String str) {
name = str;
}
public String getName () {
return name;
}
}
then I have some simple method in the main class like this:
private static int findInList (____ list, String str) {
for (int i = 0; i < list.size(); i++) {
if (list.get(i).getName().equalsIgnoreCase(str)) {
return i;
}
}
return -1;
}
It would work if I put List<BasicObject> on the blank for the parameter list, but what if I have other objects? Can I generalize the list so this would work with other objects besides BasicObject? If so, how can I get the type of the objects in the list?
Edit: What if I have another class from an imported package that I can still put in a list but I don't want to change what it implements? Is there a way to have a generalized findInList that includes those too? Or do I have to just make another method for that? I'm fine with just making another method, but I'm curious if this way is possible.
You can use an interface structure such as this
Doing so provides a common call structure, so it is predictable what can be called from the implementations
public interface IShape {
String getName();
}
public class Square implements IShape {
private String name = "Square";
#Override
public String getName() {
return name;
}
}
public class Circle implements IShape {
private String name = "Circle";
#Override
public String getName() {
return name;
}
}
public static void main(String[] args){
List<IShape> list = new ArrayList<>();
list.add(new Square());
list.add(new Circle());
list.add(new Circle());
list.add(new Square());
list.add(new IShape() {
#Override
public String getName() {
return "Triangle";
}
});
for(IShape test : list){
System.out.println(test.getName());
}
}
this produces an output like this
Square
Circle
Circle
Square
Triangle
as answer to edit
Yes, but requires reflection, if help is needed on this, please open a new question after proberly trying to solve the issue yourself.
Have you tried checking generics? It is what you're looking for, your method signature should look like below:
public <T> List<T> findInList (Class<T> list, String str) {}
This will work if all objects have common parent (BasicObject or any other class which have getName() method).
private static int findInList (List<? extends BasicObject> list, String str) {
for (int i = 0; i < list.size(); i++) {
if (list.get(i).getName().equalsIgnoreCase(str)) {
return i;
}
}
return -1;
}
Your code relies on the list having an element type with a getName method that is visible to the compiler. Another way is to use lambdas. For example,
public interface Named {
String getName();
}
public class UseNamed<T extends Named> {
public int findIndex(List<T> nameds, String search) {
for (int len = nameds.size(), ix = 0; ix < len; ++ix) {
final Named named = names.get(ix);
if (search.equalsIgnoreCase(named.getName())) {
return ix;
}
}
return -1;
}
One approach with lambdas is to pass a comparer to findIndex:
public <T, K> int findIndex(List<T> stuff, K search,
BiFunction<T, K, Boolean> compares) {...}
and call it with
List<Named> stuff = ...;
String search = ...;
int index = findIndex(stuff, search,
(named, s) -> s.equalsIgnoreCase(named.getName()));

"String cannot be converted to PubliclyCloneable" Java Issue

So I am trying to add a few strings to a Doubly Linked list but I keep getting the error that String cannot be converted to PubliclyCloneable (an interface that extends Cloneable, use for the purposes of creating a clone() and copy constructor, a la my textbook's explanation). Here is what my demo code looks like:
public static void main(String[] args)
{
DoublyLinkedList list1 = new DoublyLinkedList();
DoublyLinkedList.DoublyLinkedIterator i = list1.iterator();
String pittsburgh1 = new String("Penguins");
String pittsburgh2 = new String("Pirates");
String pittsburgh3 = new String("Steelers");
list1.addToStart(pittsburgh1);
list1.addToStart(pittsburgh2);
list1.addToStart(pittsburgh3);
System.out.println("List contains:");
i.restart();
while (i.hasNext())
System.out.println(i.next());
System.out.println("");
Here is the beginning part of the class DoublyLinkedList:
public class DoublyLinkedList<T extends PubliclyCloneable> implements PubliclyCloneable
{
private class TwoWayNode<T>
{
private T data;
private TwoWayNode<T> next;
private TwoWayNode<T> prev;
public TwoWayNode()
{
data = null;
next = null;
prev = null;
}
public TwoWayNode(T newData, TwoWayNode<T> prevNode, TwoWayNode<T> nextNode)
{
data = newData;
next = nextNode;
prev = prevNode;
}
}
Here is the method that is causing the compiler error:
public void addToStart(T itemData)
{
TwoWayNode<T> newHead = new TwoWayNode(itemData, null, head);
if (head != null)
{
head.prev = newHead;
}
head = newHead;
}
And here is the interface that I am using:
public interface PubliclyCloneable extends Cloneable
{
public Object clone();
}
So there is probably something that I am overlooking here, but is what I am trying to accomplish even possible? Is there some sort of typecast or type assignment I can do to add those three strings to my List?
Your addToStart method accepts an argument of type T, where T is defined by the class as T extends PubliclyCloneable.
Since java.lang.String does not implement PubliclyCloneable, it cannot be an argument type for your DoublyLinkedList. If you want a main function to test your class, I'd implement a simple-stupid PubliclyClonableString class::
public class PubliclyClonableString implements PubliclyClonable {
private String s;
public PubliclyClonableString (String s) {
this.s = s;
}
#Override
public String clone() {
return s; // OK, since Strings are immutable
}
// getter, setter, etc.
}
You're trying to add Strings to a list that you have declared will hold PubliclyCloneable. Either put PubliclyCloneable objects in it or declare that it will hold Strings.
Since DoublyLinkedList requires a class which extends PubliclyCloneable, you'll have to make your custom string class:
public class CloneableString implements PubliclyCloneable {
private String str;
public CloneableString(String str) {
this.str = str;
}
public String getString() {
return str;
}
#Override
public Object clone();
return new CloneableString(str);
}
}

How would i compare two objects in custom tree set implementation?

I need to compare two objects in insert method off the tree set. But i am unable to fathom out where and how to implement Comparable or Comparator. My code looks as follows:
This is my Node creation for the binary tree.
Node.java
public class Node {
private Object data;
private Node left, right;
//initial case when a Node of a binary tree gets created. both left and right subtrees point to null
public Node (){
left = right = null;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public Node getLeft() {
return left;
}
public void setLeft(Node left) {
this.left = left;
}
public Node getRight() {
return right;
}
public void setRight(Node right) {
this.right = right;
}
}
This is my MyBinaryTree class where i need to implement insert method:
MyBinaryTree.java
public class MyBinaryTree implements Comparable<Node> {
Node root;
public MyBinaryTree(){
root = null;
}
void insert(Object x){
Node newrec = new Node(); //Node constructor gets called and sets up a root node with empty
//subtrees
newrec.setData(x);
if(root == null){
root = newrec;
}
else{
Node a,b;
a = b = root;
while(a!=null){
b=a;
if( ( newrec.getData() ).compareTo( a.getData() ) ) {
i am stuck here! how would i compare these objects using Comparable?
}
}
}
}
void inorder(Node root){
}
#Override
public int compareTo(Node o) {
// TODO Auto-generated method stub
int i = (o.)
return 0;
}
}
You need to be able to compare, not just nodes, but the data contained in those nodes. That means that your Node either needs to be limited to taking objects that are Comparable, or your tree needs to take a Comparator that it can use to compare them.
If you really want to support both, then when the time comes to do the comparison, if a Comparator has been provided, use its compare method, otherwise cast the data to Comparable<? super E> where E is the type of Node data (see below), and then use its compareTo method.
That brings me to the next point. Your Node class should probably not simply contain Object as its data, but instead be declared as Node<E> implements Comparable<Node<E>>, and then your tree can be declared as MyBinaryTree<E>. I would also change the constructor for Node to take the data as a parameter, rather than calling the setter immediately after creating one. There is no reason you would ever want to create a Node with no data.
I would strongly suggest looking through the source code for some of the generic collections in the java.util package, which comes with the JDK. In particular, I referred to the source of TreeMap.java to see how they handled both Comparable and non-Comparable elements, since the class isn't declared in such a way as to require the elements to be Comparable. (If they aren't, and there is no Comparator, a ClassCastException would occur where they try to cast the object to Comparable<? super K>.) Seeing how they have implemented similar code will be a great help to you. You may also want to review Java generics.
Please refer below code
package com.example.treeset;
import java.util.Comparator;
import java.util.TreeSet;
public class MyCompUser {
public static void main(String a[]){
//By using name comparator (String comparison)
TreeSet<Empl> nameComp = new TreeSet<Empl>(new MyNameComp());
nameComp.add(new Empl("Ram",3000));
nameComp.add(new Empl("John",6000));
nameComp.add(new Empl("Crish",2000));
nameComp.add(new Empl("Tom",2400));
for(Empl e:nameComp){
System.out.println(e);
}
System.out.println("===========================");
//By using salary comparator (int comparison)
TreeSet<Empl> salComp = new TreeSet<Empl>(new MySalaryComp());
salComp.add(new Empl("Ram",3000));
salComp.add(new Empl("John",6000));
salComp.add(new Empl("Crish",2000));
salComp.add(new Empl("Tom",2400));
for(Empl e:salComp){
System.out.println(e);
}
}
}
class MyNameComp implements Comparator<Empl>{
#Override
public int compare(Empl e1, Empl e2) {
return e1.getName().compareTo(e2.getName());
}
}
class MySalaryComp implements Comparator<Empl>{
#Override
public int compare(Empl e1, Empl e2) {
if(e1.getSalary() > e2.getSalary()){
return 1;
} else {
return -1;
}
}
}
class Empl{
private String name;
private int salary;
public Empl(String n, int s){
this.name = n;
this.salary = s;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
public String toString(){
return "Name: "+this.name+"-- Salary: "+this.salary;
}
}

How to sort ArrayList<myobject> on the basis of myobject's properties

I want to sort some objects which are in an ArrayList on the basis of the objects properties.
the object has:
public class Minterm
{
String minTerm;
char flagTick;
String minTermDerive;
int groupNo;
String adjGroup;
static int MaxLiterals;
then i have this in the main method:
ArrayList<Minterm> column =new ArrayList<Minterm>();
then i add some objects of type Minterm in the list. but at the end i want to organise them and sort them on the member variable groupNo(Ascending order).
i searched and came up with the comparable and comparator interfaces that i tried but didnt succeed. is there any other method to do this? or am i doing the comparator implemnting wrong.
EDIT :
Following is the code i wrote for Comparator. Please confirm if it will sort in ascending?
package backEnd;
import java.util.Comparator;
public class Comp implements Comparator<Minterm>
{
#Override
public int compare(Minterm a, Minterm b)
{
return a.getgroupOne().compareTo(b.getgroupOne());
}
}
i run it as:
Collections.sort(column , new Comp());
seems to be working fine. but i dont have a sound understanding of it.
Please confirm if it will sort in ascending?
You should let Minterm implement Comparable<MinTerm> or write a custom Comparator for MinTerm and then use Collections.sort.
Using a comparator it would look like this:
Collections.sort(column, new Comparator<Minterm>() {
#Override
public int compare(Minterm o1, Minterm o2) {
return Integer.valueOf(o1.groupNo).compareTo(o2.groupNo);
}
});
Regarding your edit:
Yes. that sorts Minterms based on the groups in ascending order.
Collections.sort() and the Comparator interface are precisely the right tool for this job.
Something along the following lines should do it (untested):
Collections.sort(column, new Comparator<Minterm>() {
public int compare(Minterm o1, Minterm o2) {
return Integer.valueOf(o1.groupNo).compareTo(o2.groupNo);
}
});
Two ways, using Collections.sort(..):
make your object implement Comparable. Involves changing the original class, which may not be possible
supply custom Comparator. It takes instances of your object and compares them. Doesn't require a change to the class.
Either way, make sure you conform to the interfaces' contracts.
Here is the sample code (for more examples refer http://java2novice.com/java-collections-and-util/arraylist/sort-comparator/ ):
public class MyArrayListSort {
public static void main(String a[]){
List<Empl> list = new ArrayList<Empl>();
list.add(new Empl("Ram",3000));
list.add(new Empl("John",6000));
list.add(new Empl("Crish",2000));
list.add(new Empl("Tom",2400));
Collections.sort(list,new MySalaryComp());
System.out.println("Sorted list entries: ");
for(Empl e:list){
System.out.println(e);
}
}
}
class MySalaryComp implements Comparator<Empl> {
#Override
public int compare(Empl e1, Empl e2) {
if(e1.getSalary() < e2.getSalary()){
return 1;
} else {
return -1;
}
}
}
class Empl{
private String name;
private int salary;
public Empl(String n, int s){
this.name = n;
this.salary = s;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
public String toString(){
return "Name: "+this.name+"-- Salary: "+this.salary;
}
}

Categories