Determining if graph is acyclic for Toplogical Sort - java

I have successfully implemented a topological sorting algorithm, but I'm having trouble figuring out when to throw an exception when the inputted graph is not acyclic. Within the algorithm is there a way to check for this using the in-degree? Or something else for that matter?
public static List<String> topologicalSort(Graph graph) {
if(graph.getDirected() == false)
throw new UnsupportedOperationException();
Queue<Vertex> queue = new LinkedList<Vertex>();
HashMap<String, Vertex> tempMap = graph.getVertices();
for(Vertex vertex : tempMap.values()) {
if(vertex.getInDegree() == 0)
queue.add(vertex);
}
if(queue.isEmpty())
throw new UnsupportedOperationException();
ArrayList<String> returnList = new ArrayList<String>();
while(!queue.isEmpty()) {
Vertex tempVert = queue.poll();
returnList.add(tempVert.getName());
tempVert.setVisited(true);
for(Edge edge : tempVert.getEdges()) {
if(edge.getOtherVertex().getVisited() == true)
throw new UnsupportedOperationException();
edge.getOtherVertex().setVisited(true);
edge.getOtherVertex().decInDegree();
if(edge.getOtherVertex().getInDegree() == 0)
queue.add(edge.getOtherVertex());
}
}
return returnList;
}

If the input is a graph with a a cycle, then you'll reach the point in the algorithm where you haven't added all the Nodes to the output, but haven't any further elements in the queue either (you can't add any node in the cycle to the queue because of the cyclic relationship).
I.e. check returnList.size() == graph.nodeCount() after the while loop (true means acyclic input, false means input had a cycle).
graph.nodeCount() should be the number of nodes in the graph at the beginning of the method.

You can use Tarjan SCC to find all the strongly connected component in the directed graph, if there is a component has size > 1 (more than one node in that component), so there is a cycle in that component.
You can stop as soon as the algorithm found a strongly connected component with size greater than 1.

Related

Breadth-first search from one node to another

I'm implementing my own graph class, and I'm currently making my own BFS-search method. Right now it traverses all vertices from one root vertex.
public List<T> breadthFirstSearch(T start, T end) {
List<T> visited = new ArrayList<T>();
Queue<T> path = new LinkedList<T>();
visited.add(start);
path.add(start);
while (!path.isEmpty()){
T currentNode = path.poll();
for (Edge<T> edge: graphRep.get(currentNode)) {
if (!visited.contains(edge.node)) {
visited.add(edge.node);
path.add(edge.node);
}
}
}
System.out.println(visited);
return visited;
}
What I want to do is to find the path from vertex start to vertex end, but right now it finds the path between the start to all nodes. How do I change my code so that it only finds the path between the start to end?
There are several mistakes in your solution:
you not checking whether you find the target node;
case, when it is not possible to reach the end from the start node, is not covered in your solution;
the list visited will contain all a sequence of visited nodes, but not a path from the start node to end node;
method contains() costs O(n) for a list, you definitely have to use a HashSet for that purpose;
ArrayDeque will perform better than LinkedList (technically it's not a mistake but rather a strong recommendation).
So to fix your code you need to add a check whether the node to which points the current edge is equal to the end node and a boolean flag to break out from the loop (there's no need to do farther iterations).
In the code below HashMap paths is used for two purposes:
to track the parent node for each visited node in order to restore the path from start to end;
to check whether a new node is already visited.
Method getPath() will either return list nodes that represents a direct path from start to end an empty list if the path doesn't exist.
public List<T> breadthFirstSearch(T start, T end) {
Map<T, T> paths = new HashMap<>();
Queue<T> queue = new ArrayDeque<>();
queue.add(start);
paths.put(start, null);
boolean isFound = false;
while (!isFound && !queue.isEmpty()) {
T currentNode = queue.remove();
for (Edge<T> edge : graphRep.get(currentNode)) {
if (paths.containsKey(edge.node)) {
continue;
}
paths.put(edge.node, currentNode);
// end node was found
if (edge.node.equals(end)) {
isFound = true;
break;
}
}
}
return getPath(start, end, paths);
}
public List<T> getPath(T start, T end, Map<T, T> paths) {
List<T> path = new ArrayList<T>();
T current = end;
path.add(current);
while (current != start && current != null) { // if there's no path from start to end current eventually will become null
path.add(paths.get(current));
current = paths.get(current);
}
System.out.println(path);
Collections.reverse(path);
return current != null ? path : Collections.emptyList();
}

Implementing a BFS-search method for a graph

I'm implementing my own graph class. My undirected graph is represented by a map which maps every node to a list storing the edges it has.
private Map<T, List<Edge<T>>> graphRep = new HashMap<>();
private static class Edge<T> {
int cost;
T node;
public Edge(T n, int w) {
node = n;
cost = w;
}
I have already created a recursive depth-first traversal method for my graph which utilizes a map to store the path between the start node to the search node. It does by mapping every node the next node on the path between the start node to end node.
#Override
public List<T> depthFirstSearch(T start, T end) {
Set<T> visited = new HashSet<T>();
Map<T,T> path = new HashMap<>();
recursiveDFS(start, end, visited,path);
List<T> myList = new ArrayList<T>();
T current = end;
myList.add(current);
while (current != start) {
myList.add(path.get(current));
current = path.get(current);
}
System.out.println(path);
System.out.println(myList);
Collections.reverse(myList);
return myList;
}
private void recursiveDFS (T node, T end, Set<T> visited, Map<T, T> path) {
// uppdatera path och visited
visited.add(node);
for (Edge<T> e : graphRep.get(node)) {
if (e.node == end) {
path.put(e.node, node);
return;
}
if (!visited.contains(e.node)){
path.put(e.node, node);
recursiveDFS(e.node, end, visited, path);
}
}
}
I believe I can utilize essentially the same code for the breadth-first search as with the depth-first search, only that the instead of traversing the nodes by depth I traverse them by breadth, and that's where I'm stuck. I'm completely lost on how to do that.
#Override
public List<T> breadthFirstSearch(T start, T end) {
Set<T> visited = new HashSet<T>();
Map<T,T> path = new HashMap<>();
recursiveBFS(start, end, visited,path);
List<T> myList = new ArrayList<T>();
T current = end;
myList.add(current);
while (current != start) {
myList.add(path.get(current));
current = path.get(current);
}
System.out.println(path);
System.out.println(myList);
Collections.reverse(myList);
return myList;
}
public void recursiveBFS (T node, T end, Set<T> visited, Map<T, T> path) {
visited.add(node);
for (Edge<T> e : graphRep.get(node)) {
if (e.node == end) {
path.put(e.node, node);
return;
}
if (!visited.contains(node)) {
//Here's where I'm stuck. I have no idea how to traverse the graph by breadth
}
}
}
How do I complete my breadth-first traversal method?
BFS requires a container that will allow to retrieve nodes in the order they were visited. It can't be achieved with a Map. You need a Queue for that purpose (take a look carefully at the description of this algorithm).
Note that although BFS could be implemented recursively, the iterative approach is way better for this task.
Firstly, you need to create a queue and add a starting node into it. Then the queue will be passed as an argument to the recursiveBFS().
At each call of the recursiveBFS() a node at the beginning of the queue will be removed. If the queue is empty that will mean that the start-node and end-node are not connected.
That is how recursive implementation might look like:
public List<T> breadthFirstSearch(T start, T end) {
Map<T, T> paths = new HashMap<>();
Queue<T> queue = new ArrayDeque<>();
queue.add(start);
recursiveBFS(end, new HashSet<>(), queue, paths);
return getPath(start, end, paths);
}
public void recursiveBFS(T end, Set<T> visited, Queue<T> queue, Map<T, T> paths) {
if (queue.isEmpty()) { // start-node and end-node are not connected
return;
}
T parentNode = queue.remove();
visited.add(parentNode);
for (Edge<T> edge : graphRep.get(parentNode)) { // avoid one-letter variables like "e" instead of edge
if (visited.contains(parentNode)) {
continue;
}
paths.put(edge.node, parentNode);
// end node was found
if (edge.node.equals(end)) { // don't compare object with "=="
return;
}
recursiveBFS(end, visited, queue, paths); // this line was missing
}
}
In order to make this solution adhere to the Single responsibility principle I extracted the logic for restoring the path from the start-node to end-node from the breadthFirstSearch() into the separate method.
public List<T> getPath(T start, T end, Map<T, T> paths) {
List<T> path = new ArrayList<T>();
T current = end;
path.add(current);
while (current != start && current != null) { // if there's no path from start to end current eventually will become null
path.add(paths.get(current));
current = paths.get(current);
}
System.out.println(path);
Collections.reverse(path);
return current != null ? path : Collections.emptyList();
}
Recommendations:
The most important I want to point out is the overall design of your graph. While traversing the graph you heavily rely on the Map<T, List<Edge<T>>> graphRep, edges are helpless without it. You might consider refining your graph so that its elements will be more self-contained. Firstly, in my opinion, the edge of a graph has to have two references because by definition it is meant to represent a connection between two vertices of the graph. And if you add a Vertex class to your graph then will contain reference a collection of edges then you can implement graph traversal algorithms using only edges and vertexes without a need to fall back on graphRep.
don't compare object with ==, use equals() method instead.
avoid one-letter variables like e.
don't name like myList, but try to come up with the name that explains the purpose of this variable (like path).
Update
Below is an iterative implementation of BFS:
public List<T> breadthFirstSearch(T start, T end) {
Map<T, T> paths = new HashMap<>();
Set<T> visited = new HashSet<>();
Queue<T> queue = new ArrayDeque<>();
queue.add(start);
visited.add(start);
boolean isFound = false;
while (!isFound && !queue.isEmpty()) {
T parentNode = queue.remove();
for (Edge<T> edge : graphRep.get(parentNode)) {
if (!visited.add(edge.node)) {
continue;
}
paths.put(edge.node, parentNode);
// end node was found
if (edge.node.equals(end)) {
isFound = true;
break;
}
}
}
return getPath(start, end, paths);
}
An iterative solution would be cleaner if you take into account recommendation above. And since for BFS as well as for DFS we don't need any information specific to edges (because vertex (node) can store data about adjusent vertexes) these algorithms could be implemented using vertecies only.

Remove extra edge from BST

I have a BST which looks like below. How can I remove extra edge not needed from BST?
1->2, 1->3, 2->4, 2->5, 3->5
Should remove either 2->5 or 3->5
void BFS(int s)
{
// Mark all the vertices as not visited(By default
// set as false)
boolean visited[] = new boolean[V];
// Create a queue for BFS
LinkedList<Integer> queue = new LinkedList<Integer>();
// Mark the current node as visited and enqueue it
visited[s]=true;
queue.add(s);
while (queue.size() != 0)
{
// Dequeue a vertex from queue and print it
s = queue.poll();
System.out.print(s+" ");
// Get all adjacent vertices of the dequeued vertex s
// If a adjacent has not been visited, then mark it
// visited and enqueue it
Iterator<Integer> i = adj[s].listIterator();
while (i.hasNext())
{
int n = i.next();
if (!visited[n])
{
visited[n] = true;
queue.add(n);
}
}
}
}
What you have is not a tree, it's a Directed Acyclic Graph (DAG):
The algorithm you are looking for is a Spanning Tree Algorithm. One of the simplest ways to find it is to run through your graph depth-first, and mark graph nodes as you find them. If an edge takes you to a node that you have already seen, remove the edge and continue. Once you are done with the depth-first walk, the remaining graph is a tree.
What you want to implement is a self balancing binary tree. An AVL tree is one such. The Wiki page has some well commented pseudo code which should't be terribly difficult to implement in Java.
A web search will reveal plenty of examples.
// **Assuming we are maintaining a isVisited flag inside tree node. We can implement this in separate array but for simplicity I assumed it to be inside the node.**
boolean removeBadEdge(Node root) {
if (root == null)
return false;
if (root.left != null && root.left.isVisited)
{
root.left = null; // Removing the bad edge
return true;
}
if (root.right!= null && root.right.isVisited)
{
root.right= null; // Removing the bad edge
return true;
}
root.isVisited = true;
boolean leftEdgeRemoved = removeBadEdge(root.left);
boolean rightEdgeRemoved = false;
if (!leftEdgeRemoved) { // call right only if not removed in left for optimization
rightEdgeRemoved = removeBadEdge(root.right);
}
return leftEdgeRemoved || rightEdgeRemoved;
}

Given K sorted lists of up to N elements in each list, return a sorted iterator over all the items

Example: List 1: [1, 4, 5, 8, 9]
List 2: [3, 4, 4, 6]
List 3: [0, 2, 8]
Would yield the following result:
Iterator -> [0, 1, 2, 3, 4, 4, 4, 5, 6, 8, 8, 9]
I am reluctant to create a "merge" method that accepts the k lists and merges the contents of the List to another List in the spirit of space complexity. Is this a k-way merge problem that can be implemented using "min Heap". Any pointers would be very helpful.
public class CustomListIterator<E> implements Iterator<E>{
private boolean canAddIterators = true;
private boolean balanceTreeIteratorFlag = false;
private E f_element;
private E s_element;
private Iterator<E> left;
private Iterator<E> right;
private final Comparator<E> comparator;
public CustomListIterator(Comparator<E> comparator){
this.comparator = comparator;
}
public CustomListIterator(Iterator<E> left, Iterator<E> right, Comparator<E> comparator){
this.left = left;
this.right = right;
this.comparator = comparator;
}
public void addIterator(Iterator<E> iterator){
if (!canAddIterators)
throw new ConcurrentModificationException();
if (right == null){
right = iterator;
return;
}else if (left == null){
left = iterator;
return;
}
if (!balanceTreeIteratorFlag){
right = balanceTreeOfIterators(iterator, right);
}else{
left = balanceTreeOfIterators(iterator, left);
}
balanceTreeIteratorFlag = !balanceTreeIteratorFlag;
}
private Iterator<E> balanceTreeOfIterators(Iterator<E> iterator_1, Iterator<E> iterator_2){
if (iterator_2 instanceof CustomListIterator){
((CustomListIterator<E>)iterator_2).addIterator(iterator_1);
} else{
iterator_2 = new CustomListIterator<E>(iterator_1, iterator_2, comparator);
}
return iterator_2;
}
public boolean hasNext() {
if (canAddIterators){
if (left != null && left.hasNext()){
f_element = left.next();
}
if (right != null && right.hasNext()){
s_element = right.next();
}
}
canAddIterators = false;
return f_element != null || s_element != null;
}
public E next() {
E next;
if (canAddIterators){
if (left.hasNext()){
f_element = left.next();
}
if (right.hasNext()){
s_element = right.next();
}
}
canAddIterators = false;
if (s_element == null && f_element == null){
throw new NoSuchElementException();
}
if (f_element == null){
next = s_element;
s_element = right.hasNext() ? right.next() : null;
return next;
}
if (s_element == null){
next = f_element;
f_element = left.hasNext() ? left.next() : null;
return next;
}
return findNext();
}
public void remove() {
}
private E findNext(){
E next;
if (comparator.compare(f_element, s_element) < 0){
next = f_element;
f_element = left.hasNext() ? left.next() : null;
return next;
}
next = s_element;
s_element = right.hasNext() ? right.next() : null;
return next;
}
}
I don't this is the most optimal way of doing it (using a tree). Any suggestions on how this can be implemented only by overriding next() hasNext() and remove()?
There are basically three different ways to merge multiple sorted lists:
Successive two-way merges
Divide and conquer
Priority queue based
In the discussion below, n refers to the total number of items in all lists combined. k refers to the number of lists.
Case 1 is the easiest to envision, but also the least efficient. Imagine you're given four lists, A, B, C, and D. With this method, you merge A and B to create AB. Then you merge AB and C to create ABC. Finally, you merge ABC with D to create ABCD. The complexity of this algorithm approaches O(n*k). You iterate over A and B three times, C two times, and D one time.
The divide and conquer solution is to merge A and B to create AB. Then merge C and D to create CD. Then merge AB and CD to create ABCD. In the best case, which occurs when the lists have similar numbers of items, this method is O(n * log(k)). But if the lists' lengths vary widely, this algorithm's running time can approach O(n*k).
For more information about these two algorithms, see my blog entry, A closer look at pairwise merging. For more details about the divide and conquer approach specifically, see A different way to merge multiple lists.
The priority queue based merge works as follows:
Create a priority queue to hold the iterator for each list
while the priority queue is not empty
Remove the iterator that references the smallest current number
Output the referenced value
If not at end of iterator
Add the iterator back to the queue
This algorithm is proven to be O(n * log(k)) in the worst case. You can see that every item in every list is added to the priority queue exactly once, and removed from the priority queue exactly once. But the queue only contains k items at any time. So the memory requirements are very small.
The implementation of iterators in Java makes the priority queue implementation slightly inconvenient, but it's easily fixed with some helper classes. Most importantly, we need an iterator that lets us peek at the next item without consuming it. I call this a PeekableIterator, which looks like this:
// PeekableIterator is an iterator that lets us peek at the next item
// without consuming it.
public class PeekableIterator<E> implements Iterator<E> {
private final Iterator<E> iterator;
private E current;
private boolean hasCurrent;
public PeekableIterator(Iterator<E> iterator) {
this.iterator = iterator;
if (iterator.hasNext()) {
current = iterator.next();
hasCurrent = true;
}
else {
hasCurrent = false;
}
}
public E getCurrent() {
// TODO: Check for current item
return current;
}
public boolean hasNext() {
return hasCurrent;
}
public E next() {
// TODO: Error check to see if there is a current
E rslt = current;
if (iterator.hasNext()) {
current = iterator.next();
}
else {
hasCurrent = false;
}
return rslt;
}
public void remove() {
iterator.remove();
}
Then, since the priority queue will hold iterators rather than individual items, we need a comparator that will compare the current items of two PeekableIterator interfaces. That's easy enough to create:
// IteratorComparator lets us compare the next items for two PeekableIterator instances.
public class IteratorComparator<E> implements Comparator<PeekableIterator<E>> {
private final Comparator<E> comparator;
public IteratorComparator(Comparator<E> comparator) {
this.comparator = comparator;
}
public int compare(PeekableIterator<E> t1, PeekableIterator<E> t2) {
int rslt = comparator.compare(t1.getCurrent(), t2.getCurrent());
return rslt;
}
}
Those two classes are more formal implementations of the code you wrote to get and compare the next items for individual iterators.
Finally, the MergeIterator initializes a PriorityQueue<PeekableIterator> so that you can call the hasNext and next methods to iterate over the merged lists:
// MergeIterator merges items from multiple sorted iterators
// to produce a single sorted sequence.
public class MergeIterator<E> implements Iterator<E> {
private final IteratorComparator<E> comparator;
private final PriorityQueue<PeekableIterator<E>> pqueue;
// call with an array or list of sequences to merge
public MergeIterator(List<Iterator<E>> iterators, Comparator<E> comparator) {
this.comparator = new IteratorComparator<E>(comparator);
// initial capacity set to 11 because that's the default,
// and there's no constructor that lets me supply a comparator without the capacity.
pqueue = new PriorityQueue<PeekableIterator<E>>(11, this.comparator);
// add iterators to the priority queue
for (Iterator<E> iterator : iterators) {
// but only if the iterator actually has items
if (iterator.hasNext())
{
pqueue.offer(new PeekableIterator(iterator));
}
}
}
public boolean hasNext() {
return pqueue.size() > 0;
}
public E next() {
PeekableIterator<E> iterator = pqueue.poll();
E rslt = iterator.next();
if (iterator.hasNext()) {
pqueue.offer(iterator);
}
return rslt;
}
public void remove() {
// TODO: Throw UnsupportedOperationException
}
}
I've created a little test program to demonstrate how this works:
private void DoIt() {
String[] a1 = new String[] {"apple", "cherry", "grape", "peach", "strawberry"};
String[] a2 = new String[] {"banana", "fig", "orange"};
String[] a3 = new String[] {"cherry", "kumquat", "pear", "pineapple"};
// create an ArrayList of iterators that we can pass to the
// MergeIterator constructor.
ArrayList<Iterator<String>> iterators = new ArrayList<Iterator<String>> (
Arrays.asList(
Arrays.asList(a1).iterator(),
Arrays.asList(a2).iterator(),
Arrays.asList(a3).iterator())
);
// String.CASE_INSENSITIVE_ORDER is a Java 8 way to get
// a String comparator. If there's a better way to do this,
// I don't know what it is.
MergeIterator<String> merger = new MergeIterator(iterators, String.CASE_INSENSITIVE_ORDER);
while (merger.hasNext())
{
String s = merger.next();
System.out.println(s);
}
}
My performance comparisons of the divide-and-conquer and priority queue merges shows that the divide-and-conquer approach can be faster than using the priority queue, depending on the cost of comparisons. When comparisons are cheap (primitive types, for example), the pairwise merge is faster even though it does more work. As key comparisons become more expensive (like comparing strings), the priority queue merge has the advantage because it performs fewer comparisons.
More importantly, the pairwise merge requires twice the memory of the priority queue approach. My implementation used a FIFO queue, but even if I built a tree the pairwise merge would require more memory. Also, as your code shows, you still need the PeekableIterator and IteratorComparator classes (or something similar) if you want to implement the pairwise merge.
See Testing merge performance for more details about the relative performance of these two methods.
For the reasons I detailed above, I conclude that the priority queue merge is the best way to go.

coding with a singly linked list and bubble sort in java

I have a problem with my code, I have made a singly linked list class in which you can add, remove, modify, merge etc... however, I am attempting a simple bubble sort and have come across problems in which the list is not correctly sorted. here are some things to note:
it is a custom implementation of a linked list
the nodes of the singly linked list contain 2 things: a CustomerFile object with all the data for a customer and a 'next' node pointer to the next item in the list
the list is sorted in ascending order (A-Z) by the surname stored in the customer file of each node
the add record function inserts the nodes at the correct position in the list so that the list does not need to be sorted initially - however if the surname is changed, as part of the program, the list needs to be sorted again
I would rather not create a new list and re-use this insert record on that list to create a new list as this is memory intensive and my task is to be as efficient as possible
the very structure of the linked list cannot be changed - it is decided and I am too far to change to something such as an array
the list has a head node, it has next items but does not have a tail node. It has an appointed NULL next pointer to indicate the end pf the list
the code
public static void sortList()
{
if (isEmpty() == true)
{
System.out.println("Cannot sort - the list is empty");
}
else if (getHead().getNext() == null)
{
System.out.println("List sorted");
}
else
{
Node current = getHead().getNext();
CustomerFile tempDat;
boolean swapDone = true;
while (swapDone)
{
current = getHead().getNext();
swapDone = false;
while (current != null)
{
if (current.getNext() != null &&
current.getData().getSurname().compareTo(
current.getNext().getData().getSurname()) >0)
{
tempDat = current.getData();
current.setData(current.getNext().getData());
current.getNext().setData(tempDat);
swapDone = true;
}
current = current.getNext();
}
}
if (getHead().getData().getSurname().compareTo(
getHead().getNext().getData().getSurname()) >0)
{
current = getHead().getNext();
getHead().setNext(current.getNext());
setHead(current);
}
}
}
I would appreciate the feedback
Your code is an odd mixture, mostly swapping data but treating the head specially trying to swap it with the next by switching the links.
As noted in another answer, this last swap is not correctly implemented, but really there's no reason to treat the head specially if you're doing things by swapping the data.
All you have to do is start each traversal of the list at the head in the outer loop.
This yields a working solution:
public void sortList()
{
if (isEmpty())
{
System.out.println("An empty list is already sorted");
}
else if (getHead().getNext() == null)
{
System.out.println("A one-element list is already sorted");
}
else
{
Node current = getHead();
boolean swapDone = true;
while (swapDone)
{
swapDone = false;
while (current != null)
{
if (current.getNext() != null && current.getData().getSurname().compareTo(current.getNext().getData().getSurname()) >0)
{
CustomerFile tempDat = current.getData();
current.setData(current.getNext().getData());
current.getNext().setData(tempDat);
swapDone = true;
}
current = current.getNext();
}
current = getHead();
}
}
}
I've made this non-static because as noted in comments it wasn't clear to me how yours could work as a static. You may be able to make it static in your context.
I also changed a couple other minor things. It's never necessary to check a condition by code like
if (isEmpty() == true)
In Java, this is entirely equivalent to
if (isEmpty())
And tempDat doesn't need to be declared outside of where it's used.
I think the main issue here is that you start with
current = getHead().getNext()
With this code you will leave the head completely out of the sorting process and it could be the case that the data in here needs to go to the other end of the list, but in this case it will always be either the data in the head element, or be the data directly after the head node (the latter is due to your if statement at the end).
Try starting from the head of the list instead and see what that brings up.
You are not including the head in your sorting.
public static void sortList()
{
if (isEmpty() == true)
{
System.out.println("Cannot sort - the list is empty");
}
else if (getHead().getNext() == null)
{
System.out.println("List sorted");
}
else
{
Node current = getHead();
// Node current = getHead().getNext();
CustomerFile tempDat;
boolean swapDone = true;
while (swapDone)
{
current = getHead().getNext();
swapDone = false;
while (current != null)
{
if (current.getNext() != null && current.getData().getSurname().compareTo(current.getNext().getData().getSurname()) >0)
{
tempDat = current.getData(); // td -> objectA, cd -> objectA
current.setData(current.getNext().getData()); // cd -> objectB
current.getNext().setData(tempDat); // nd -> td -> objectA
swapDone = true;
}
current = current.getNext();
}
}
//if (getHead().getData().getSurname().compareTo(getHead().getNext().getData().getSurname()) >0)
//{
// current = getHead().getNext(); // current -> head+1
// getHead().setNext(current.getNext()); //head+1 -> head+2
// setHead(current); // head -> head+1
//}
}
}
Also there is a error in the commented out code above. Applying that code drops a node.
// list: a -> b -> c -> d
current = getHead().getNext(); // current = b
getHead().setNext(current.getNext()); // a -> c
setHead(current); // head = b
// list: b -> c -> d
// and nothing points to 'a' anymore
Rather then swapping data you should try swapping nodes. If you go about that approach you should find a better solution.

Categories

Resources