Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

Programming Assignment 1 Data structure Java Implement Shellsort for a linked li

ID: 3854566 • Letter: P

Question

Programming Assignment 1

Data structure Java

Implement Shellsort for a linked list, based on a variant of bubble sort. The rather severe constraints imposed by the singly-linked list organization presents special problems for implementing Shellsort. Your task is to overcome these constraints and develop a simple, elegant implementation that does not sacrifice efficiency or waste space.

Step 1. First, implement a routine to build a list: read integers from standard input, and build a list node for each item consisting of an integer key and a link to the node for the next item. Also, write a routine to print out the contents of the linked list.

Have a Class File for Linked List Implementation, and define a set of methods:

LinkedNode<T>() – a constructor that initializes an Empty LinkedNode
LinkedNode<T>(T element) - a constructor that initializes an Empty LinkedNode with the given element.

LinkedNode<T> getNext() – return the next node
void setNext(LinkedNode<T> node) – set next to point to the node T getElement() – return the element
void setElement(T element) – store the element in current node

In your main Java file, have the following methods:

readValues(): read values from a file and build a linked list of integers.
displayList(): Write a routine to display the contents of the linked list.

Step 2. Next, implement bubble sort: it should take as input a link to the beginning of a list, and should rearrange the nodes of the list so that they are in sorted order. This is not the same as rearranging keys within nodes: that is to be avoided because, in real applications, other information might be associated with the keys, or other data structures might have pointers to

the nodes. You may use dummy nodes or circular lists as you see fit, but do not use doubly-linked lists. That is, you should use only one link per node, with a constant extra number of links for bookkeeping.

Create a Class File to implement Sorting Algorithms:

bubbleSort(LinkedNode<T> first): Implement the bubble sort on the linked list.

Step 3: There is a variation of the bubble sort algorithm called a shell sort that, rather than comparing neighboring elements each time through the list, compares elements that are some number (i) positions apart, where i is an integer less than n. For example, the first element would be compared to the (i+1) element, the second element would be compared to the (i+2) element, the nth element would be compared to the (n-i) element, etc. A single iteration is completed when all of the elements that can be compared, have been compared. On the next iteration, i is reduced by some number greater than 1 and the process continues until i is less than 1. Implement a shell sort using Knuth’s increment sequence: 1, 4, 13,....(3k – 1)/2: it should take as input a link to the beginning of a list, and should rearrange the nodes of the list so that they are in sorted order.

shellSort(LinkedNode<T> first): Implement the gap sort on the linked list.

Make a call to the Sorting algorithms from your Main Java Files.

Analysis. Use explicit counters to determine how many key comparisons and exchanges are used. Report these counts and the amount of time your program takes to sort random input files of size 100, 1,000, and 10,000. Include in your output.txt a two-dimensional table with a row corresponding to each file size and columns giving the total number of comparisons and exchanges used. Also, include a column that indicates how many seconds your program takes on each input.

Input and output. The input consists of integers separated by whitespace. You may use the sample input files given in the document folder. Your program should output the intermediate stages of the sort for debugging and to provide evidence that your program works. For example, on the input file random10.txt, your program should output:

a.out < random10.txt

k pass cmp exch ----------------------------------

18794675999198531023

10234653187998759991 10234653187998759991 10182346537579989199 10182346537579919899 10182346537579919899

If N is larger than 20, for brevity only print out the number of comparisons and exchanges for

each value of h.
a.out < random100000.txt

k pass cmp exch ----------------------------------

4 1 4 2 1 1 1 2 1 3

125

277 ---------------------------------- Total 5 39 12

88573 2 29524 4 9841 10 3280 16 1093 21 364 29 121 36 40 49 13 46 4 28 1 16

---------------------------------- Total 257 25213317 2951075

Submission:

Submit your files on Canvas using the Programming Assignment 1 submission Link. You will submit a zip file containing:

Main.java – the controller and tester for your program.

LinkedList.java - the Linked List class file.

Sorting.java- Class file for Sorting Algorithms

Output.txt – With the output details as explained earlier.

Grading Rubric:

Grading will be done across the following points:

Correct implementation of Linked List interface.

Correct working of all three algorithms

Correct working for all input files

Compiles correctly on the first try

Exception Handling

Output File generated properly

All required files submitted

Explanation / Answer

Main.java

package linkedlists;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Scanner;

public final class Main {
  
   public static void main(String[] args) throws IOException {
       String filePrefix = "./src/input/";
       String fileSufix = ".txt";
       LinkedList<String> fileList = new LinkedList<>();
       fileList.add("inorder100");
       fileList.add("inorder1000");
       fileList.add("inorder10000");
       fileList.add("random100");
       fileList.add("random1000");
       fileList.add("random10000");
       fileList.add("reverse100");
       fileList.add("reverse1000");
       fileList.add("reverse10000");
      
       //files
       LinkedNode<String> runner = fileList.getHead();
       StringBuilder sb = new StringBuilder();
       for(int i = 0; i < fileList.getSize(); i++) {
           LinkedList<Integer> inputForBubble =
                   readValues(filePrefix + runner.getData() + fileSufix);
           LinkedList<Integer> inputForShell =
                   readValues(filePrefix + runner.getData() + fileSufix);
           LinkedList<Integer> bubbleList =
                   new LinkedList<Integer>(Sort.bubbleSort(inputForBubble.getHead()));  
           LinkedList<Integer> shellList =
                   new LinkedList<Integer>(Sort.shellSort(inputForShell));  
           sb.append(displayList(runner.getData()));
           if (bubbleList.getSize() <= 20) {
               sb.append("Sorted values: ");
               sb.append(getValuesofList(bubbleList));
           }
           runner = runner.getNext();
       }
       PrintWriter writer = new PrintWriter("output.txt", "UTF-8");
       writer.print(sb.toString());
       writer.close();

      
   }
  
   private static LinkedList<Integer> readValues(final String theFile)
           throws IOException {
       Scanner s = new Scanner(new File(theFile));
       LinkedList<Integer> newList = new LinkedList<>();
       while(s.hasNextInt()) {
           newList.add(s.nextInt());
       }
       s.close();
       return newList;
   }
   private static String displayList(String thePath) {
       return " " + thePath + " > output.txt " +
               Sort.getBubbleStats() + Sort.getShellStats();
   }
   private static String getValuesofList(LinkedList<Integer> theList) {
       return theList.getList();
   }
}

LinkedList.java

package linkedlists;

public final class LinkedList<T> {
   private LinkedNode<T> myHead;
   private LinkedNode<T> myRunner;
   private LinkedNode<T> myTail;
   private int mySize;
  
   public LinkedList(){
       myHead = null;
       myRunner = null;
       myTail = null;
       mySize = 0;
   }
   public LinkedList(LinkedNode<T> theHead) {
       myHead = theHead;
       myRunner = theHead;
       mySize = 1;
       while(myRunner.getNext() != null) {
           mySize++;
           myRunner = myRunner.getNext();
           myTail = myRunner;
       }
   }
   /**
   * Adds a node to the end of the list.
   *
   * @param theElement the data to add to a node
   */
   public void add(final T theElement) {
       if (myHead == null) {
           myHead = new LinkedNode<T>(theElement);
           myTail = myHead;
           mySize++;
       } else {
           myRunner = myTail;
           myRunner.setNext(new LinkedNode<T>(theElement));
           myTail = myRunner.getNext();
           mySize++;
       }
   }
   /**
   * Sets node.next at thePosition to a new node that contains theElement.
   *
   * @param theElement the element to add.
   * @param thePosition the position to add it to.
   */
   public void add(final T theElement, final int thePosition) {
       goToNode(thePosition);
       LinkedNode<T> newNode = new LinkedNode<T>(theElement);
       newNode.setNext(myRunner.getNext());
       myRunner.setNext(newNode);
       mySize++;
   }
   public void addHead(final T theElement) {
       LinkedNode<T> newFront = new LinkedNode<T>(theElement);
       newFront.setNext(myHead);
       myHead = newFront;
       mySize++;
   }
   /**
   * Moves the runner to a position
   *
   * @param thePosition the position to move to
   * @return the runner at thePosition
   */
   public LinkedNode<T> goToNode(final int thePosition) {
       if (thePosition >= mySize - 1) {
           myRunner = myTail;
       } else if (thePosition <= 0) {
           myRunner = myHead;
       } else {
           myRunner = myHead;
           for (int i = 0; i != thePosition; i++) {
               myRunner = myRunner.getNext();
           }
       }
       return myRunner;
   }
   /**
   * Remove the head of the list.
   */
   public void remove() {
       myHead = myHead.getNext();
       mySize--;
   }
   public void removeLast() {
       myRunner = myHead;
       while (myRunner.getNext().getNext() != null) {
           myRunner = myRunner.getNext();
       }
       myTail = myRunner;
       myRunner.setNext(null);
       mySize--;
       }
   /**
   * Remove a value at a position.
   *
   * @param thePosition the position of the value to be removed
   */
   public void removeAt(final int thePosition) {
       if (thePosition >= mySize - 1) {
           removeLast();
       } else if (thePosition <= 0) {
           remove();
       } else {
           myRunner = goToNode(thePosition - 1);
           myRunner.setNext(myRunner.getNext().getNext());
       }
   }
   public void clear() {
       while(myHead != null) {
           remove();
       }
       mySize = 0;
   }
   public int getSize() {
       return mySize;
   }
   public LinkedNode<T> getHead() {
       return myHead;
   }
   public LinkedNode<T> getTail() {
       return myTail;
   }
   //switch to string return?
   public String getList(){
       final StringBuilder sb = new StringBuilder();
       if (myHead == null) {
           sb.append("empty");
       } else {
           myRunner = myHead;
           while (myRunner.getNext() != null) {
               sb.append(myRunner.getData());
               sb.append(' ');
               myRunner = myRunner.getNext();
           }
           sb.append(myRunner.getData());
       }
       return sb.toString();
   }
}


LinkedNode.java

package linkedlists;

public final class LinkedNode<T> implements Comparable<T>{
   //add counter?
   private T myData;
   //private?
   private LinkedNode<T> myNext;
   public LinkedNode(final T theElement) {
       myData = theElement;
       myNext = null;
   }
   public LinkedNode(final LinkedNode<T> theNode) {
       myData = theNode.getData();
       this.setNext(theNode.getNext());
   }
   public T getData() {
       T returnMe = myData;
       return returnMe;
   }
   public void setData(final T theData) {
       myData = theData;
   }
   public LinkedNode<T> getNext() {
       return myNext;
   }
   public void setNext(final LinkedNode<T> theNode) {
       myNext = theNode;
   }
   public String toString() {
       return myData.toString();
   }
   //I'm sure ill be fine
   @SuppressWarnings("unchecked")
   @Override
   public int compareTo(T theOther) {
       return ((Comparable<T>) this.getData()).compareTo(theOther);
   }
  
}

Sort.java

import java.math.BigDecimal;
import java.math.RoundingMode;


public final class Sort {
   /**
   * Some class wide variables
   */
   private static int bubbleSwaps;
   private static int bubbleComps;
   private static int bubblePass;
   private static int[][] shellData;
   private static double bubbleElapsed;
   private static double shellElapsed;  
  
   private Sort() {
       //don't do this
   }
  
   /**
   * Sorts the list by swapping bigger values with the adjacent value.
   *
   * @param theHead The head node of the list to be sorted
   * @return the head of a sorted list
   */
   public static <T> LinkedNode<T> bubbleSort(final LinkedNode<T> theHead) {
       final double start = System.nanoTime();
       LinkedNode<T> head = new LinkedNode<T>(theHead);
       //the runners
       LinkedNode<T> prev = null;
       LinkedNode<T> curr = head;
       LinkedNode<T> next = curr.getNext();
       LinkedNode<T> hold = null;
       int swaps = 0;
       int cmp = 0;
       int pass = 0;
       while (hold != head.getNext()){
           while (next != null && next != hold) {
               cmp++;
               if (curr.compareTo(next.getData()) > 0) {
                   if (prev == null) {
                       curr.setNext(next.getNext());
                       next.setNext(curr);
                       head = next;
                       head.setNext(curr);
                       next = curr.getNext();
                       prev = head;
                   } else {
                       curr.setNext(next.getNext());
                       next.setNext(curr);
                       prev.setNext(next);
                       next = curr.getNext();
                       prev = prev.getNext();
                   }
                   swaps++;
               } else {
                   if (prev == null) {
                       curr = curr.getNext();
                       next = next.getNext();
                       prev = head;
                   } else {
                       prev = prev.getNext();
                       curr = curr.getNext();
                       next = next.getNext();
                   }
               }
           }
           hold = prev.getNext();
           curr = head;
           next = curr.getNext();
           prev = null;
           pass++;
       }
       final double stop = System.nanoTime();
       final double elapsed = (stop - start) / 1000000000;
       Sort.setBubbleStats(swaps, cmp, pass, elapsed);
       return head;
   }

   /**
   * Sorts the list in the same way as a bubbleSort, but with a gap.
   *
   * @param theList the list to be sorted
   * @return returns the head of a sorted list
   */
   public static <T> LinkedNode<T> shellSort(final LinkedList<T> theList) {
       final double start = System.nanoTime();
       LinkedNode<T> head = theList.getHead();
       LinkedNode<T> pos1, pos2, pre2, pre1 = null;
       boolean hasSwap;
       int rowSize = 9;
       int[][] outputTable = new int[rowSize][4];
       int col = 0;
       int row = 0;
       double k = 15;
       int seq = theList.getSize() + 1;
      
       while (seq > theList.getSize()) {
           seq = (int) ((Math.pow(3, k) - 1 ) / 2);
           k--;
       }
       for (int gap = seq; gap > 1; k--) {
           int swaps = 0;
           int cmp = 0;
           int pass = 0;
           hasSwap = true;
           while (hasSwap) {
               hasSwap = false;
               pos1 = new LinkedNode<T>(head);
               pre2 = pos1;
               //gap set
               for (int i = 0; i < gap - 1; i++) {
                   pre2 = pre2.getNext();
               }              
               pos2 = pre2.getNext();
               while (pos2 != null) {
                   if (pre1 == null) {
                       cmp++;
                       if (pos1.compareTo(pos2.getData()) > 0) {
                           swaps++;
                           pre2.setNext(pos1);
                           pos1.setNext(pos2.getNext());
                           pos2.setNext(head.getNext());
                           head = pos2;
                           hasSwap = true;
                       }
                   } else {
                       cmp++;
                       if (pos1.compareTo(pos2.getData()) > 0) {
                           swaps++;
                           LinkedNode<T> tmp = new LinkedNode<T>(pos1);
                           pre2.setNext(pos1);
                           pos1.setNext(pos2.getNext());
                           pos2.setNext(tmp.getNext());
                           pre1.setNext(pos2);
                           hasSwap = true;
                       }
                   }      
                   if (pre1 == null) {
                       pre1 = head;
                   } else {
                       pre1 = pre1.getNext();
                   }
                   pos1 = pre1.getNext();
                   pre2 = pre2.getNext();
                   pos2 = pre2.getNext();
               }
               pre1 = null;
               pass++;
           }
           col = 0;
           outputTable[row][col++] = gap;
           outputTable[row][col++] = pass;
           outputTable[row][col++] = cmp;
           outputTable[row][col++] = swaps;
           row = rowSize - (int) k;
                  
           gap = (int) ((Math.pow(3, k) - 1 ) / 2);
       }      
       hasSwap = true;
       pre1 = null;
       pos1 = head;
       pos2 = pos1.getNext();
      
       int swaps = 0;
       int cmp = 0;
       int pass = 0;
       while(hasSwap) {
           hasSwap = false;
           while (pos2 != null) {
               cmp++;
               if (pos1.compareTo(pos2.getData()) > 0) {
                   if (pre1 == null) {
                       pos1.setNext(pos2.getNext());
                       pos2.setNext(pos1);
                       head = pos2;
                       head.setNext(pos1);
                       pos2 = pos1.getNext();
                       pre1 = head;
                       hasSwap = true;
                   } else {
                       pos1.setNext(pos2.getNext());
                       pos2.setNext(pos1);
                       pre1.setNext(pos2);
                       pos2 = pos1.getNext();
                       pre1 = pre1.getNext();
                       hasSwap = true;
                   }
                   swaps++;
               } else {
                   if (pre1 == null) {
                       pos1 = pos1.getNext();
                       pos2 = pos2.getNext();
                       pre1 = head;
                   } else {
                       pre1 = pre1.getNext();
                       pos1 = pos1.getNext();
                       pos2 = pos2.getNext();
                   }
               }
           }
           pass++;
           pos1 = head;
           pos2 = pos1.getNext();
           pre1 = null;  
       }
       col = 0;
       outputTable[row][col++] = 1;
       outputTable[row][col++] = pass;
       outputTable[row][col++] = cmp;
       outputTable[row][col++] = swaps;
      
       final double stop = System.nanoTime();
       final double elapsed = (stop - start) / 1000000000;
       Sort.setShellStats(outputTable, elapsed);
       return head;
   }

   /**
   * Sets the class wide variables to the most recent sort's data.
   *
   * @param theData the number of exch, cmp, pass, and gap value.
   * @param theElapsed time taken to complete sort
   */
   private static void setShellStats(final int[][] theData, final double theElapsed) {
       shellData = theData;
       shellElapsed = theElapsed;
   }
   /**
   * Sets the class wide variables to the most recent sort's data.
   *
   * @param theSwp amount of data exchanges
   * @param theCmp amount of comparisons
   * @param theElapsed time elapsed
   */
   private static void setBubbleStats(final int theSwp,
           final int theCmp, final int thePass, final double theElapsed) {
       bubbleComps = theCmp;
       bubbleSwaps = theSwp;
       bubblePass = thePass;
       bubbleElapsed = theElapsed;
   }
   /**
   * @return the stats of the most recent sort.
   */
   public static String getShellStats() {
       StringBuilder sb = new StringBuilder();
       sb.append(" Shell Sort----------- ");
       sb.append("k   pass   cmp   exch ");
       sb.append("--------------------- ");
       int passTotal = 0;
       int cmpTotal = 0;
       int exchTotal = 0;
      
       for (int row = 0; row < 9; row++) {
           for (int col = 0; col < 4; col++) {
               sb.append(shellData[row][col] + "   ");
              
               if(col == 1) {
                   passTotal += shellData[row][col];
               } else if (col == 2) {
                   cmpTotal += shellData[row][col];
               } else {
                   exchTotal += shellData[row][col];
               }  
           }
           sb.append(" ");
       }
       sb.append("--------------------- ");
       sb.append("Total: " + passTotal + " "
               + cmpTotal + " " + exchTotal + ' ');
       sb.append("Time Elapsed: " + new BigDecimal
               (shellElapsed).setScale(3, RoundingMode.FLOOR));
       sb.append(" seconds ");
       return sb.toString();
   }
   /**
   * @return the stats of the most recent sort.
   */
   public static String getBubbleStats() {
       StringBuilder sb = new StringBuilder();
       sb.append("Bubble Sort---------- ");
       sb.append("cmp: " + bubbleComps + " ");
       sb.append("exch: " + bubbleSwaps + " ");
       sb.append("pass: " + bubblePass + " ");
       sb.append("Time Elapsed: " + new BigDecimal
               (bubbleElapsed).setScale(3, RoundingMode.FLOOR));
       sb.append(" seconds ");
       return sb.toString();
   }
}