Inserting into sorted linked list - Java - java

I need to maintain a sorted data structure from which items can be deleted and added. For that I decided to choose a linked list. Each data item contains a letter and some numbers such as these:
A1480, A1488, B1297, C3119
These need to be maintained in order. I have written code for it which first finds the position into the already sorted linked list where the new item needs to be added and then adds the item to its correct position, therefore maintaining the sorted linked list. It works but some items are misplaced and I am not sure how to fix my code. I do know that there is something wrong with the last loop but i am not sure what it is.
public static void main(String[] args) {
list = new LinkedList<String>();
add("C3138");
add("C3119");
add("A1488");
add("A1480");
add("A1517");
add("B1297");
add("C2597");
add("B1356");
add("C9000");
add("C3517");
add("C3729");
add("C1729");
add("B1729");
}
public static void add(String value) {
// Integer value form the string passed into the method
int valueInt = getInt(value);
// If linked list is empty, add value and return from method
if (list.size() == 0) {
list.add(value);
return;
}
// Compare this item to be added to the first item
int firstNode = getInt(list.get(0));
if (list.get(0).charAt(0) > value.charAt(0)
|| (list.get(0).charAt(0) == value.charAt(0) && firstNode > valueInt)){
list.add(0, value);
return;
}
// Compare this item to the last item
int lastNode = getInt(list.get(list.size() - 1));
if (list.get(list.size() - 1).charAt(0) < value.charAt(0) ||
(list.get(list.size() - 1).charAt(0) == value.charAt(0) && lastNode < valueInt)) {
list.add(list.size(), value);
return;
}
// add the inbetween items
int i = 1;
int tempInt = getInt(list.get(i));
while ((list.get(i).charAt(0) < value.charAt(0)
|| ((list.get(i).charAt(0) == value.charAt(0)) && (valueInt < tempInt)) && i < list.size())) {
tempInt = getInt(list.get(i));
i++;
}
list.add(i, value);
}
public static int getInt(String item) {
return Integer.parseInt(item.replaceAll("\\D", ""));
}
This code below gives me output of:
[A1480, A1517, A1488, B1729, B1297, B1356, C1729, C3729, C3517, C2597,
C3119, C3138, C9000]
and as you can see that some values in between start and finish are misplaced but start and end values are correct. Please help

Try doing this :: Change your last while condition to this::
(list.get(i).charAt(0) < value.charAt(0) || ((list.get(i).charAt(0) == value.charAt(0)) && (valueInt > tempInt)) && i < list.size())
What you are currently doing is that you are incrementing your i unless you hit a value of tempInt which is smaller than varInt, which is why A1517 gets inserted before A1488.
You shall increment your i until the value of tempInt is smaller than `varInt so that you reach the largest position the current element could achieve. I hope I could make it clear.
The working code Ideone link :: http://ideone.com/ZafWEO
Further, it would be better to check the value to i before accessing the linkedlist items. So, the condition shall look like this ::
(i < list.size() && (list.get(i).charAt(0) < value.charAt(0) || ((list.get(i).charAt(0) == value.charAt(0)) && (valueInt > tempInt)))

Take a look at Why is there no SortedList in Java?
If your values are unique, you can just use TreeSet. Generally, if you want a sorted collection, you probably don't want to start with LinkedList.

Why don't you use Comparable?
Scroll to bottom to see the class implemented Comparable
This is answer to your question:
private static LinkedList<SuperRosie> list;
public static void main(String[] args) {
// TODO Auto-generated method stub
list = new LinkedList<SuperRosie>();
add("C3138");
add("C3119");
add("A1488");
add("A1480");
add("A1517");
add("B1297");
add("C2597");
add("B1356");
add("C9000");
add("C3517");
add("C3729");
add("C1729");
add("B1729");
for (int i = 0; i < list.size(); i++)
System.out.println(list.get(i).getValue());
}
private static void add(String value) {
SuperRosie myNewRs = new SuperRosie(value);
int listSize = list.size();
// If linked list is empty, add value and return from method
if (listSize == 0) {
list.add(myNewRs);
return;
}
// Compare this item to be added to the first item
SuperRosie element = list.getFirst();
if (myNewRs.compareTo(element) <= 0) {
list.addFirst(myNewRs);
return;
}else{
if(listSize == 1){
list.addLast(myNewRs);
return;
}
}
// Compare this item to the last item
element = list.getLast();
if (myNewRs.compareTo(element) >= 0) {
list.addLast(myNewRs);
return;
}else{
if(listSize == 1){
list.addFirst(myNewRs);
return;
}
}
// add the inbetween items
int compare = 0;
for (int i = 1; i < listSize; i++) {
element = list.get(i);
compare = myNewRs.compareTo(element);
if (compare <= 0) {
list.add(i, myNewRs);
break;
}
}
}
Example to Sort comparable Linked List:
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
LinkedList<SuperRosie> list = new LinkedList<SuperRosie>();
list.add(new SuperRosie("C3138"));
list.add(new SuperRosie("C3119"));
list.add(new SuperRosie("A1488"));
list.add(new SuperRosie("A1480"));
list.add(new SuperRosie("A1517"));
list.add(new SuperRosie("B1297"));
list.add(new SuperRosie("C2597"));
list.add(new SuperRosie("B1356"));
list.add(new SuperRosie("C9000"));
list.add(new SuperRosie("C3517"));
list.add(new SuperRosie("C3729"));
list.add(new SuperRosie("C1729"));
list.add(new SuperRosie("B1729"));
Collections.sort(list);
for(SuperRosie rs : list)
System.out.println(rs.getValue());
}
}
And SuperRosie.java class implements from Comparable
public class SuperRosie implements Comparable<SuperRosie> {
private String value;
public SuperRosie(String value) {
this.value = value;
}
public String getValue() {
return value;
}
#Override
public int compareTo(SuperRosie arg0) {
int compareFirst = this.value.charAt(0) - arg0.value.charAt(0);
return compareFirst == 0 ? (Integer.parseInt(this.value.replaceAll(
"\\D", "")) - Integer
.parseInt(arg0.value.replaceAll("\\D", ""))) : compareFirst;
}
public static Comparator<SuperRosie> FruitNameComparator = new Comparator<SuperRosie>() {
public int compare(SuperRosie rosie1, SuperRosie rosie2) {
String rosieValue1 = rosie1.value.toUpperCase();
String rosieValue2 = rosie2.value.toUpperCase();
// ascending order
return rosieValue1.compareTo(rosieValue2);
// descending order
//return rosieValue2.compareTo(rosieValue1);
}
};
}

According to the performance problems, I suggest another performance solution.
private static LinkedList<String> list;
public static void main(String[] args) {
list = new LinkedList<>();
add("C3138");
add("C3119");
add("A1488");
add("A1480");
add("A1517");
add("B1297");
add("C2597");
add("B1356");
add("C9000");
add("C3517");
add("C3729");
add("C1729");
add("B1729");
for (int i = 0; i < list.size(); i++)
System.out.println(list.get(i));
}
private static void add(String value){
// don't check empty array, check to add in the first, last element.
// Each case, it works but when array has more than 1 element,
// so the above check are useless, run will cost memory, steps,....
// So don't, please do just the following
int insertIndex = 0;
for(String element : list){
if(compare(value, element) <= 0){ // or whatever compare way you want
break;
}else{
insertIndex+=1;
}
}
list.add(insertIndex, value);
}
private static int compare(String value1, String value2){
int compareFirst = value1.charAt(0) - value2.charAt(0);
return compareFirst == 0 ? (Integer.parseInt(value1.replaceAll(
"\\D", "")) - Integer
.parseInt(value2.replaceAll("\\D", ""))) : compareFirst;
}

Related

Sort an ArrayList of String where the String contains numeric values in java [duplicate]

This question already has answers here:
How to determine if a List is sorted in Java?
(14 answers)
Closed 6 years ago.
Code as follows
public static void main(String[] args) {
ArrayList<String> arrayList=new ArrayList<String>();
arrayList.add("1001");
arrayList.add("999");
String val="";
boolean unsorted=true;
if (val.contains("isAscending")) {
for (int i = 0; i < arrayList.size() - 1; i++) {
if (arrayList.get(i).toLowerCase().compareTo(arrayList.get(i + 1).toLowerCase()) <= 0) {
unsorted = false;
System.out.println(unsorted);
} else {
break;
}
}
} else {
for (int i = 0; i < arrayList.size() - 1; i++) {
if (arrayList.get(i).toLowerCase().compareTo(arrayList.get(i + 1).toLowerCase()) >= 0) {
unsorted = false;
System.out.println(unsorted+" "+"descending");
} else {
break;
}
}
}
}
the above program works correctly but the problem is when I replace
the arraylist with the below arraylist it doesn't work
arrayList.add("22");
arrayList.add("8");
I meant to say that if the first index is followed by a 1 digit number it fails
the same repeats here
arrayList.add("1001");
arrayList.add("1000");
for this the above code works
arrayList.add("1001");
arrayList.add("999");
for this it fails
The requirement is to verify if an arraylist is in sorted order or not no need to sort the arraylist
If you want to find out if your list be sorted, you can use a custom comparator to sort your ArrayList using the actual integers which are represented by the strings. Then, you can compare this sorted list against the original one.
Collections.sort(arrayList, new Comparator<String>() {
#Override
public int compare(String s1, String s2) {
try {
// try to compare the two values as integers, if possible
Integer val1 = Integer.valueOf(s1);
Integer val2 = Integer.valueOf(s2);
return val1.compareTo(val2);
}
catch (NumberFormatException e) {
// fall back to sort them as strings
return s1.compareTo(s2);
}
}
});
As #ajb mentioned, it might be simpler to just assume that every string can be converted to an integer, and to deal with the exception elsewhere. In this case we can use:
Collections.sort(arrayList, new Comparator<String>() {
#Override
public int compare(String s1, String s2) {
return Integer.valueOf(s1).compareTo(Integer.valueOf(s2));
}
});
The method trys to parse the Strings into Integer, if that´s successfull it compares the numbers, if not it compares the Strings.
public class Test {
public static void main(String[] args) {
ArrayList<String> arrayList = new ArrayList<String>();
arrayList.add("1");
arrayList.add("999");
arrayList.add("1001");
boolean isAsc = true;
boolean isSorted = true;
for (int i = 0; i < arrayList.size() -1; i++) {
int a, b;
boolean numbs;
try {
int a = Integer.parseInt(arrayList.get(i));
int b = Integer.parseInt(arrayList.get(i + 1));
if ((isAsc && a > b) || (!isAsc && a < b)) {
isSorted = false;
break;
}
} catch (NumberFormatException) {
if ((isAsc && arrayList.get(i).toLowerCase().compareTo(arrayList.get(i + 1).toLowerCase() > 0) || (arrayList.get(i).toLowerCase().compareTo(arrayList.get(i + 1).toLowerCase() < 0)) {
isSorted = false;
break;
}
}
}
if (isSorted) {
System.out.println("List is sorted !");
} else {
System.out.println("List is not sorted !");
}
}
}
Hope I could help

Given two Linked Lists, find the index where one list is sublist of another

Recently I took part in a java coding challenge in my college and was asked this problem which I found difficult to implement.
Problem was to implement a method detect that given two LinkedList, return the index where second list is sublist of first.
detect((1,2,3),(2,3)) should return 1
The node structure to the list was
LinkedListNode {
String val;
LinkedListNode *next;
}
and the method signature
static int detect(LinkedListNode list, LinkedListNode sublist)
What would be the basic algorithm to approach this problem. I am a newbie to data structures.
I believe Collections.indexOfSubList implements this. You can look at it's implementation.
Basically:
ListIterator<?> si = source.listIterator();
nextCand:
for (int candidate = 0; candidate <= maxCandidate; candidate++) {
ListIterator<?> ti = target.listIterator();
for (int i=0; i<targetSize; i++) {
if (!eq(ti.next(), si.next())) {
// Back up source iterator to next candidate
for (int j=0; j<i; j++)
si.previous();
continue nextCand;
}
}
return candidate;
}
The basic idea is to traverse the second list and for every index in this list check for equality in first list for consecutive elements. The following algorithm will work for you:
public static void main(String[] args) {
List<Integer> list1 = new LinkedList<Integer>();
list1.add(1);
list1.add(2);
list1.add(3);
list1.add(4);
list1.add(5);
list1.add(6);
List<Integer> list2 = new LinkedList<Integer>();
list2.add(2);
list2.add(3);
boolean contains = true;
int currIndex = 0;
int i = 0,j = 0;
for(;j<list2.size();j++) {
int e2 = list2.get(j);
for(i=currIndex;i<list1.size();i++) {
if(e2 == list1.get(i)) {
break;
}
}
if(i == list1.size()) {
contains = false;
break;
}
currIndex++;
if( contains && (currIndex == list2.size()) ) {
System.out.println("Index is: " + (i-j));
}
}
}
This prints Index is: 1 as expected.
static int detect(LinkedListNode list, LinkedListNode sublist) {
int counter = 0;
int index = -1;
LinkedListNode sub = sublist;
do {
if (list.val == sub.val) {
if (index == -1)
index = counter;
if (sub.next != null) {
sub = sub.next;
if (sub.next == null) {
return index;
}
}
} else {
index = -1;
sub = sublist;
}
list = list.next;
counter++;
} while (list.next != null);
return index;
}
Since, the value is String here :-
static int find(LinkedListNode list, LinkedListNode sublist) {
String listString = convertLinkedListToString(list);
String sublistString = convertLinkedListToString(sublist);
return listString.indexOf(sublistString);
}
private static String convertLinkedListToString(LinkedListNode list) {
String listAsString = "";
while(list != null) {
listAsString = listAsString + list.val;
list = list.next;
}
return listAsString;
}

Sorting an ArrayList so that certain numbers go first, and the order is otherwise preserved

public static ArrayList<ArrayList<HSSFCell>> newTogether(ArrayList<ArrayList<HSSFCell>> sheetData) {
ArrayList<ArrayList<HSSFCell>> temporary = new ArrayList<ArrayList<HSSFCell>>();
for(int i = 0; i < sheetData.size(); i++) {
ArrayList<HSSFCell> list = sheetData.get(i);
if (list.get(3).getCellType() == Cell.CELL_TYPE_NUMERIC) {
if(Integer.parseInt(list.get(3).getStringCellValue()) > 100) {
temporary.add(list);
sheetData.remove(i);
i--;
}
}
}
for(int i = 0; i < sheetData.size(); i++) {
ArrayList<HSSFCell> list = sheetData.get(i);
temporary.add(list);
}
return temporary;
}
What I am trying to do with my code is have the 2D ArrayList take out any numbers greater than 100 and put them in the beginning of the ArrayList, while preserving the order of the remaining elements. However, this code just returns an ArrayList in the original order, and if I add a println to either if, I get nothing. Could someone point out what it is I'm doing wrong?
Have you tried putting a println in front of the first if to check what getStringCellValue() returns?
btw. since Collections.sort is guaranteed to be stable according to the API documentation, you could use that. Should be faster than your way of doing it.
That could look like this
private static boolean biggerThan100(ArrayList<HSSFCell> list) {
return list.get(3).getCellType() == Cell.CELL_TYPE_NUMERIC &&
(Integer.parseInt(list.get(3).getStringCellValue()) > 100);
}
public static ArrayList<ArrayList<HSSFCell>> newTogether(ArrayList<ArrayList<HSSFCell>> sheetData) {
ArrayList<ArrayList<HSSFCell>> temp = new ArrayList<>(sheetData);
Collections.sort(temp, new Comparator<ArrayList<HSSFCell>>() {
public int compare(ArrayList<HSSFCell> a, ArrayList<HSSFCell> b) {
if(biggerThan100(a) && !biggerThan100(b)) return -1;
else if(biggerThan100(b) && !biggerThan100(a)) return 1;
else return 0;
}
});
return temp;
}

Grouping Duplicates From a Sorted ArrayList into Another ArrayList

(Full disclosure: this is for some homework I can't seem to figure out.)
The task: Identify duplicates in a list and add them to another ArrayList to be printed out.
Specifications: I am NOT allowed to use any collection other than an ArrayList, so I can't use something like a Set. It seems like every answer on StackOverflow recommends use of a Set, which is why I decided to ask this question.
What I've attempted so far:
public static void deleteDuplicates(List<String> list)
{
int pointer = 1;
List<String> duplicates = new ArrayList<String>();
for (int i = 0; i < list.size() - 1; i++) {
if (list.get(i).equals(list.get(pointer))) {
duplicates.add(list.get(i));
if (pointer == 1) {
duplicates.add(list.get(pointer));
} else if ((pointer + 1) == list.size() - 1) {
duplicates.add(list.get(pointer));
}
pointer++;
} else {
display(duplicates);
duplicates = new ArrayList<String>();
pointer++;
}
}
}
The test data:
List<String> duplicated = new ArrayList<String>();
duplicated.add("3");
duplicated.add("3");
duplicated.add("30");
duplicated.add("46");
duplicated.add("46");
What's not working: When the size of the list is an odd number, the duplicates report correctly. When the size of the list is an even number, only the first two duplicates are reported.
The problem with your approach was the loop exits before it do the if-else check for last element. On the last iteration the if condition satisfies and it adds to duplicates but it wont enter the for loop again to goto the else part. So it does'nt get dispalyed. Try
public static void deleteDuplicates(List<String> list)
{
int pointer = 1;
List<String> duplicates = new ArrayList<String>();
for (int i = 0; i < list.size() - 1; i++) {
if (list.get(i).equals(list.get(pointer))) {
duplicates.add(list.get(i));
if (pointer == 1) {
duplicates.add(list.get(pointer));
} else if ((pointer + 1) == list.size() - 1) {
duplicates.add(list.get(pointer));
}
pointer++;
} else if(duplicates.size() > 0) {
display(duplicates);
duplicates.clear();
pointer++;
}
}
if(duplicates.size() > 0){
display(duplicates);
}
}
Although Syam S answer is right but this will work for unsorted array too:
public static void deleteDuplicates(List<String> list)
{
List<String> duplicates = new ArrayList<String>();
for (int j = 0; j < list.size() - 2; j++) {
int pointer = j;
for (int i = j+1; i < list.size() - 1; i++) {
if (list.get(i).equals(list.get(j))) {
duplicates.add(list.get(i));
duplicates.add(list.get(j));
}
if(duplicates.size() > 0){
System.out.println(duplicates);
duplicates.clear();
}
}
}
}
you can see the working version in Ideone
Try this:
Extending the ArrayList
1)
boolean result = false;
if(!contains(object))
result= super.add(object);
return result;
OR
2)
ArrayList<String> myList = new ArrayList<String>()
{
#Override
public boolean add(String object)
{
boolean present = false;
boolean result = false;
for(int i=0;i<size();i++)
{
if(object.equals(get(i)))
{
present = true;
break;
}
}
if(!present)
result= super.add(object);
return result;
}
};
myList.add("1");
myList.add("2");
myList.add("3");
myList.add("1");
myList.add("2");
myList.add("3");
myList.add("1");
myList.add("1");
System.out.println(myList);

My queue fails to display when I remove then add an item

I modified a program which creates a Queue and then add or remove items to it.
The problem in my code is that after I remove one item, and then add an item it goes into infinite loop and I'm not sure how to prevent it from happening.
My goal is to modify display() method only.
This is how I display Queue:
public void display()
{
int i = front;
do {
if (maxSize == nItems)
{
if (i == size())
i = 0;
System.out.print(queArray[i++] + " ");
}
else if (maxSize < nItems)
{
System.out.print("Too many queue items!");
break;
}
else
maxSize = nItems;
}
while (i != rear + 1 && !isEmpty());
}
This is how I add and remove items:
public void insert(long j) // put item at rear of queue
{
if(rear == maxSize-1) // deal with wraparound
rear = -1;
queArray[++rear] = j; // increment rear and insert
nItems++; // one more item
}
public long remove() // take item from front of queue
{
long temp = queArray[front++]; // get value and incr front
if(front == maxSize) // deal with wraparound
front = 0;
nItems--; // one less item
return temp;
}
Here is the source code for the same.
import java.util.Arrays;
public class Queue {
private int enqueueIndex;// Separate index to ensure enqueue happens at the end
private int dequeueIndex;// Separate index to ensure dequeue happens at the
// start
private int[] items;
private int count;
// Lazy to add javadocs please provide
public Queue(int size) {
enqueueIndex = 0;
dequeueIndex = 0;
items = new int[size];
}
// Lazy to add javadocs please provide
public void enqueue(int newNumber) {
if (count == items.length)
throw new IllegalStateException();
items[enqueueIndex] = newNumber;
enqueueIndex = ++enqueueIndex == items.length ? 0 : enqueueIndex;
++count;
}
// Lazy to add javadocs please provide
public int dequeue() {
if (count == 0)
throw new IllegalStateException();
int item = items[dequeueIndex];
items[dequeueIndex] = 0;
dequeueIndex = ++dequeueIndex == items.length ? 0 : dequeueIndex;
--count;
return item;
}
#Override
public String toString() {
return Arrays.toString(items);
}
}

Categories

Resources