Suppose I have the following dataset stored in a linkedlist (excluding the header):
ID | Name
1 | John
2 | Albert
3 | Simon
Now, I would like to sort the nodes according to, say, alphabetical order.
I would like to know how I can come up with my own sorting method without using Arrays (and similar stuff like Lists, Vectors, ArrayLists etc.) and without using a library sorting method (e.g. Collections.sort).
In other words, I would like to know the concept of sorting and how one should go about arranging the nodes in a systematic manner. It doesn't have to be efficient - it just has to work.
I'll be trying this out in Java but I would appreciate pseudocodes or tips / hints / other resources as well.
Thank you.
Addendum:
LinkedList.java
class LinkedList
{
private Node head; // first node in the linked list
private int count;
public int getCount()
{
return count;
}
public Node getHead()
{
return head;
}
public LinkedList()
{
head = null; // creates an empty linked list
count = 0;
}
public void deleteFromFront()
{
if (count > 0)
{
Node temp = head;
head = temp.getLink();
temp = null;
count--;
}
}
public void AddToFront(Object cd)
{
Node newNode = new Node(cd);
newNode.setLink(head);
head = newNode;
count++;
}
public void RemoveAtPosition(int n)
{
int counter=1;
Node previous=null;
if(n==1)
deleteFromFront();
else if(n<=getCount())
for(Node j=head;j!=null;j=j.getLink())
{
if(counter==n&&previous!=null)
{
previous.setLink(j.getLink());
j.setLink(null);
}
previous=j;
counter++;
}
else
System.out.println("Unable to remove object at position "+n);
}
public void AddAtPosition(int n, Object cd)
{
int counter=1;
Node newNode=new Node(cd);
Node previous=null;
for(Node j=head;j!=null;j=j.getLink())
{
if(counter==n&&previous!=null)
{
newNode.setLink(j.getLink());
j.setLink(newNode);
}
previous=j;
counter++;
}
}
public void Swap(int n1, int n2)
{
// how do I swap nodes?
}
public void Sort()
{
// how do I sort nodes?
}
}
Node.java
public class Node {
private Object data;
private Node link;
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public Node getLink() {
return link;
}
public void setLink(Node link) {
this.link = link;
}
public Node(Object data) {
this.data = data;
this.link = null;
}
}
If you want to do it yourself, insertion sort is really easy on linked lists. Create a new empty linked list, then insert all elements from the old one into it. Wikipedia has a C code example.
If you want to know how the JDK does it... I copies the list into an array, sorts that and copies it back.
You can use a bubble sort for a linked list but it will be slower, so it makes no sense, unless you like pain. ;)
I realize you say you don't want to use Collections.sort, but just to make sure: you do realize that Collections.sort allows you to implement for yourself the sorting order, right? If not, http://www.digizol.com/2008/07/java-sorting-comparator-vs-comparable.html (and many other resources) will provide info on that.
Otherwise, there are a lot of sorting algorithms you can implement. One of the easier to understand is Bubble Sort. http://en.wikipedia.org/wiki/Bubble_sort contains a good explanation of it, including a nice visualization of the different sorting steps.
But Bubble Sort isn't (at all) an efficient way of sorting. There are many other sorting algorithms (merge sort, insertion sort, quicksort, ... see Wikipedia's article on "Sorting algorithm" for an overview), and they each have their advantages and disadvantages. It depends on the data you're sorting which algorithm will fit best.
You can copy the list into an array and sort that. Otherwise, there are various sorting algorithms that can be used i.e. merge sort, bubble sort etc.
You can see this for merge sort implementation.
While not exactly the same, look at external sorts (where the data isn't loaded into memory; for example, you want to sort a file bigger than your RAM). They generally work by moving data between files, in a manner similar to how you might move nodes between linked lists.
Related
This question already has answers here:
How to implement a Linked List in Java? [duplicate]
(7 answers)
Closed 6 years ago.
I am new to data structures. I am very curious to learn data structures, but i didnt find any healthy tutorial for that so I am posting it here thinking someone would help me. I know theory of linked list but m totally blank while implementation. If Someone can make me understand how it works that would be really helpful for me.Like, how to traverse through Linked List ,insert and delete. Please provide me a running code so that its easy for me to understand.
I KNOW there are lot of peoples who will think to mark this question as a duplicate and downvote this. Rather than finding mistakes if you guys provide me a good solution that would be really Helpful. Thanks.
Simple implementation of a linked list showing append, insert, delete and iterate. There are inefficiencies, they're for you to figure out :) Go do some research to see how to make it better.
public class LinkedList {
public static class Node {
private Object data;
private Node next = null;
public Node(Object data) {
this.data = data;
}
public void setNext(Node n) {
next = n;
}
public Node getNext() {
return next;
}
public Object getData() {
return data;
}
}
public static void iterate(Node n) {
while (n != null) {
System.out.println(n.getData());
n = n.getNext();
}
}
public static void insert(Node newNode, Node after) {
newNode.setNext(after.getNext());
after.setNext(newNode);
}
public static void delete(Node toDelete, Node root) {
Node n = root;
while (n.getNext() != toDelete) {
n = n.getNext();
}
n.setNext(toDelete.getNext());
}
public static void main(String[] args) {
Node a = new Node("a");
Node b = new Node("b");
Node c = new Node("c");
// append
a.setNext(b);
b.setNext(c);
// iterate
System.out.println("Initial list");
iterate(a);
// insert d after b
Node d = new Node("d");
insert(d, b);
// iterate again
System.out.println("After insert");
iterate(a);
// delete d
delete(d, a);
// iterate again
System.out.println("After delete");
iterate(a);
}
}
Well to start, if you go on youtube and search up Derek Banas you will find a great video just on LinkedLists, and how to implement them. He talks kind of fast, but the content is very well taught in my opinion. Just following along in his videos and after the video I think you will have a better understanding.
https://www.youtube.com/watch?v=195KUinjBpU
First of all, let me say that this is an assignment for a class where we have been tasked with writing our own doubly linked list class and cannot use anything from Java SE (e.g. the LinkedList class). We have to make our code work with a provided driver class. I am not asking for anyone to do the homework for me, I am simply asking for some kind of clarification as to how exactly to implement these methods, since I have struggled with this on and off over the past few days.
We have been provided with an Interface, textEditor.java that provides methods which will be utilized by the driver class, driver.java. These methods include the typical insert, et. al. but my concern is the insertAfter(int lineNum, E line) method and its counterpart, insertBefore. I have not been able to get these to work because comparing int to E, despite my best efforts and reading through several Java texts for guidance.
Below is the code in the DoublyLinkedList.java file, as provided at onset. I would like to know how I can implement some kind of indexing and checking in order to be able to make an insertion following or preceding the line entered by the user/driver class.
public class DoublyLinkedList<E> implements TextEditor<E>
{
Node<E> head, tail;
public DoublyLinkedList()
{
head = null;
tail = null;
}
public boolean isEmpty()
{
return (head == null);
}
public void insert(E line)
{
}
public void insertAfter(int lineNum, E line)
{
}
public void insertBefore(int lineNum, E line) throws IndexOutOfBoundsException
{
}
public void deleteByPosition(int position)
{
}
public void printNode(int position)
{
}
public void printAllNodes()
{
}
}
I have not been able to do this, and having tried several things over several hours, I have given up hope of being able to do it. If I don't find help here or still can't get these methods to work, I will be speaking with my instructor. It may simply be that I am overthinking the problem, and I hope that that is the case.
I'm assuming that your Node class looks like this :
class Node<E> {
private Node next;
private E value;
[...]
}
You can add an attribute in your DoublyLinkedList class, in which you keep the number of Node that your list contains.
Then, if you want the Nth element of your list, you can do this :
private Node getNthElement(int n) {
Node node = head;
for (int i=0; i<n; i++) {
node = node.next;
}
return node;
}
These methods should also check if there are enough elements in the list, etc. But this is the main idea.
I have a method to flatten a Binary search tree. I have two approaches for it:
• Using a variable and passing it around
import java.util.*;
public class BST {
private Node root;
private class Node {
private int val; // associated data
private Node left, right; // left and right subtree
public Node(int val) {
this.val = val;
}
}
public ArrayList<Integer> flattenTree(){
ArrayList<Integer> list = new ArrayList<>();
flattenTree(root, list);
return list;
}
public void flattenTree(Node node, ArrayList<Integer> list)
{
if (node == null)
return;
flattenTree(node.left, list);
list.add(node.val);
flattenTree(node.right, list);
}
public static void main(String[] args) {
BST bst = new BST();
bst.add(5);
bst.add(1);
bst.add(0);
bst.add(3);
System.out.println(bst.flattenTree());
}
}
• Using a class variable:
import java.util.*;
public class BST {
private Node root;
ArrayList<Integer> list = new ArrayList<>();
private class Node {
private int val; // associated data
private Node left, right; // left and right subtree
public Node(int val) {
this.val = val;
}
}
public ArrayList<Integer> flattenTree(){
flattenTree(root);
return list;
}
public void flattenTree(Node node)
{
if (node == null)
return;
flattenTree(node.left);
list.add(node.val);
flattenTree(node.right);
}
public static void main(String[] args) {
BST bst = new BST();
bst.add(5);
bst.add(3);
bst.add(1);
bst.add(0);
bst.add(3);
bst.add(3);
bst.printInorder();
System.out.println(bst.flattenTree());
}
}
In both cases I get:
sgupta$ java BST
[0, 1, 3, 5]
I'm a beginner to java (high school) and wondering what the pros and cons of each approach are.
The only one I can think of is that approach #2 has less messy code by not having to pass the list around.
To add to #caskey's points, I'd like to point out two other major advantages of the first version of the code.
First, the code that accepts an explicit list is harder to use incorrectly. If you call the second version of the code, you need to
make sure no one else is calling the method in a parallel thread,
make sure that the list variable has been initialized,
make sure that the list doesn't already contain anything else, and
remember to read off the list when you're done with it.
If you forget to do any of these, your program will not behave as expected, but you won't get any compiler errors indicating this. This makes the code harder to use correctly and increases the chances that you'll get more bugs in your program.
Second, the first version has an easier description. The first version of the code can be described as "populate the given list with an inorder traversal of the tree." The second version is "appends to the existing contents of the list list an inorder traversal of the tree." It's harder to describe what this second one does, so the burden on the documentation is greater. Plus, it's harder for programmers reading the code for the first time to understand what it does.
Hope this helps!
The disadvantage, in general, to global variables is twofold.
1) you have only one global variable and so two copies of your code can't run at the same time (i.e., multiple threads).
2) The global variable can be modified in other places which your code might not expect.
Your first answer is the better engineered solution.
Good questions to ask:
Does the class have state it needs to hold onto?
If so, what is the state (i.e. the fields)?
Can you avoid state by passing arguments in method calls, which makes for easier to test code.
Is there a way to recursively traverse a tree and return an array that is scoped to that recursive method?
So I recently answered someone else's question on this topic. That question can be found here: SO Question. My solution uses an array outside of the scope of the recursion, and therefore the method cannot (or at least probably should not) return the array. However, is there a way to write a recursive method for traversing trees such that it returns an array? Even writing an initial method that calls the recursive one would be fine, but I can't think of a good way to do this.
Here's the code that I suggested before:
private List nodeValues = new ArrayList();
public void traversePreRecursive(BinarySearchTreeNode node)
{
if (node != null)
{
nodeValues.add(node.getValue());
traversePreRecursive(node.getLeft());
traversePreRecursive(node.getRight());
}
}
As you can see the ArrayList is outside of the scope of the recursion - And therefore returning it doesn't make a lot of sense. Is there a better way to do this?
public static List traversePreRecursive(Node node) {
if (node == null) return new ArrayList();
List nodeValues = new ArrayList();
nodeValues.add(node.getValue());
nodeValues.addAll(traversePreRecursive(node.getLeft()));
nodeValues.addAll(traversePreRecursive(node.getRight()));
return nodeValues;
}
There is an alternative, but it involves two passes over the tree. You would only employ this alternative if the array operations in my first answer were giving you grief. This approach starts by providing an index for each of the nodes (the index() method) -- basically working out which element of the array a node should occupy before we actually create the array. This also gives me a count of nodes (size). I then allocate an array (list) big enough to hold all the nodes and pass it into a method (addToList) that copies the node-references into the previously identified element in the array.
public static List<Node> getNodes(Node a) {
int size = index(a, 0);
List<Node> list = new ArrayList<Node>(size);
addToList(a, list);
return list;
}
private static int index(Node node, int index) {
if (node == null) return index;
node.setIndex(index);
int iLeft = index(node.getLeft(), index++);
int iRight = index(node.getRight(), iLeft++);
return iRight + 1;
}
private static void addToList(Node node, List<Node> list) {
if(node == null) return;
list.add(node.getIndex(), node);
addToList(node.getLeft(), list);
addToList(node.getRight(), list);
}
In c you can have static function variables,(Ie, adding a value to a list in one iteration of a function means that that value will be in the list in the next iteration--if the list is static) but using them isn't the best (most optimal) solution for the problem you are suggesting. So, I think you are searching for static variables, but this isn't an appropriate case to use them.
Alright, my professor (Data Structures class) assigned this: Your task is to write a program that can update character access frequencies in a doubly-Link list. The program should read one character at a time from a text file that contain many characters. To make it easier, do not count spaces. Every time a character is accessed, increment its access frequency by one in the node of the list. If the frequency of the current node is higher than of its previous node, the two nodes need to be swapped in the list. Continue doing so for all the previous nodes until no more previous node has lower access frequency. Eventually, the character with the highest frequency will appear at the beginning of the list, the next highest will be in the next node, etc. Your program also need to print out the characters in the list according to the order of the list.
Here is the program I have made so far. It's just a doubly linked list as of right now.
My main question is how should I go about the "Every time a character is accessed, increment its access frequency by one in the node of the list. If the frequency of the current node is higher than of its previous node, the two nodes need to be swapped in the list."?
I know there aren't any lines getting the info from a file. I'm going to add that later.
Any help is appreciated!
public class DoublyLinkedList {
private class Node {
String value;
Node next,prev;
public Node(String val, Node n, Node p) {
value = val;
next = n;
prev=p;
}
Node(String val) {
this(val, null, null);
}
}
private Node first;
private Node last;
public DoublyLinkedList() {
first = null;
last = null;
}
public boolean isEmpty(){
return first==null;
}
public int size(){
int count=0;
Node p=first;
while(p!=null){
count++;
p=p.next;
}
return count;
}
public void add(String e) {
if(isEmpty()){
last=new Node(e);
first=last;
}
else{
last.next=new Node(e, null, last);
last=last.next;
}
}
public void add(int index, String e){
if(index<0||index>size()){
String message=String.valueOf(index);
throw new IndexOutOfBoundsException(message);
}
if(index==0){
Node p=first;
first=new Node(e,p,null);
if(p!=null)
p.prev=first;
if(last==null)
last=first;
return;
}
Node pred=first;
for(int k=1; k<=index-1;k++){
pred=pred.next;
}
Node succ=pred.next;
Node middle=new Node(e,succ,pred);
pred.next=middle;
if(succ==null)
last=middle;
else
succ.prev=middle;
}
public String toString(){
StringBuilder strBuilder=new StringBuilder();
Node p=first;
while(p!=null){
strBuilder.append(p.value+"\n");
p=p.next;
}
return strBuilder.toString();
}
public String remove(int index){
if(index<0||index>=size()){
String message=String.valueOf(index);
throw new IndexOutOfBoundsException(message);
}
Node target=first;
for(int k=1; k<=index;k++){
target=target.next;
}
String element=target.value;
Node pred=target.prev;
Node succ=target.next;
if(pred==null)
first=succ;
else
pred.next=succ;
if(succ==null)
last=pred;
else
succ.prev=pred;
return element;
}
public boolean remove(String element){
if(isEmpty())
return false;
Node target=first;
while(target!=null&&!element.equals(target.value))
target=target.next;
if(target==null)
return false;
Node pred=target.prev;
Node succ=target.next;
if(pred==null)
first=succ;
else
pred.next=succ;
if(succ==null)
last=pred;
else
succ.prev=pred;
return true;
}
public static void main(String[] args){
DoublyLinkedList list1=new DoublyLinkedList();
String[] array={"a","c","e","f"};
for(int i=0; i<array.length; i++){
list1.add(array[i]);
}
list1.add(1,"b");
list1.add(3,"d");
System.out.println(list1);
}
}
Since this is a homework assigment, I'll only give hints:
Your Node class needs an extra field for a counter.
You need to iterate through the list to find the accessed character and increment its counter value.
You need a temporary Node object to swap nodes. Try it yourself first, then google it. It's an essential process every programmer must know.
I would recommend breaking down the procedure into the component parts. You know you need to keep and update a count, as Sebastian says above. You also know you need to be able to compare a node's count with the count of the node above it in the rankings. You know you need to be able to swap two nodes. You should have methods for those things. Think through what needs to happen in each broken-down method.
I always recommend a physical approach for these kinds of problems to get a feel for them: Try doing this with a set of note cards or post-it notes. On each one, write an object name and the fields for the Node object. Write field values in pencil. Jot down other fields (like the reference to the first element) on a sheet of paper. Then step through your algorithm and see what needs to change on each update. (note: Because this is a doubly-linked list, your changes should survive shuffling your stack of cards. Try that and see)
Good luck with the assignment!
Advice:
"I know there aren't any lines getting the info from a file.". You would be better off writing that code now, so that you can test what you have already written.
The other problem is that what you have written so far is a generic linked list, ignoring the requirement which say how the list is to be used. As a result, you have:
implemented a bunch of methods that appear to be unnecessary, and
not implemented the Node class correctly for the requirements.
Go back and look at the requirements, and work out what methods you actually need, and then implement them. (What you have done so far is a "bottom up" design that is largely ignoring what the top level needs. You would have been better of with a "top down" approach.)
The problem you are asked to solve is collating characters, not creating a "general purpose" linked list data structure.