Java Double Linked List - java

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.

Related

Question about Conceptual Understanding for Circular doubly linked list in Java

I am a beginner coder in java and in general and I wanted to ask for some help. I am doing an assignment in which I am supposed to make a CircularLinkedList which is like a DoublyLinkedList. But for CircularLinkedList am not allowed to have a head or a tail. Instead, I have a pointer to one of the nodes in the CircularLinkedList. So, to my understanding from basic LinkedList, the head node is where we would implement our series of Singly LinkedList.
I have made a DoubleNode pointer as a global variable that will at first point at the first node when we create a circular linked list. when I construct a CircularLinkedList that is empty.
My question is: Should this DoubleNode pointer point to null within the constructor or should I just create a new node and make them point to null with not value to claim its empty?
I am posting my code for better understanding my concept
public class CircularLinkedList<T> {
DoubleNode pointer; //create a double node of pointer [/| no data |\]
int lengthoflinkedlist = 0;
private class DoubleNode<T> { //create a DoubleNode class to understand how nodes would look in the circular linked list
private DoubleNode prev;
private T data;
private DoubleNode next;
// Now we input our functions into the class or methods as they call it
public DoubleNode(){ //constructors for bas node.
this.prev = null;
this.next = null;
}
public DoubleNode(T data) {
this.prev = null;
this.data = data;
this.next = null;
}
public DoubleNode(DoubleNode P, T data, DoubleNode N){
this.prev = P;
this.data = data;
this.next = N;
}
}
public CircularLinkedList() {
// pointer
DoubleNode A = new DoubleNode(); // creates a node with nothing and pointers to null;
}
public CircularLinkedList(int initSize, T initValue) { //constucting a circular linked list
// TODO implement me
//initSize means the size of linkedlist
//initValue means the value of data T in the nodes.
if(initSize == 0) { //throw error as length 0 means linkedlist is empty
System.out.println("The linked list with size 0 means it is an empty linkedlist with a Pointer pointing to Nothing");
}
else {
DoubleNode check = this.pointer;
for(int lengthoflinkedlist = 0; lengthoflinkedlist < initSize - 1; lengthoflinkedlist++) {
DoubleNode A = new DoubleNode(this.pointer.next,initValue,this.pointer.prev);
}
}
}
public void moveForward() {
// TODO implement me
}
public void moveBackward() {
// TODO implement me
}
public T getValue() {
// TODO implement me
return null;
}
/**
* #return the previous value of the updated node
*/
public T setValue(T value) {
// TODO implement me
return null;
}
public void addBefore(T value) {
// TODO implement me
}
public void addAfter(T value) {
// TODO implement me
}
/**
* #return the previous value of the removed node
*/
public T removeBefore() {
// TODO implement me
return null;
}
/**
* #return the previous value of the removed node
*/
public T removeAfter() {
// TODO implement me
return null;
}
public boolean isEmpty() {
// TODO implement me
return true;
}
}
I am still implementing my class and constructors atm so i need help based on that
My question is, first of, I have made a DoubleNode pointer as a global variable that will at first point at the first node when we create a circular linked list.
I can't see a "global" variable. I can see an instance variable called pointer ... which I assume is what you are talking about.
Should this DoubleNode pointer point to null within the constructor or should I just create a new node and make them point to null with not value to claim its empty?
Actually, you can do it either way.
One way would be to have an empty list represented as a CircularLinkedList with a null value in the pointer field.
Another way would be to have an empty list represented as a CircularLinkedList with a pointer that refers to a DoubleNode with null data.
I think that the first approach will be simpler. Either way you need special case code for when the list is empty.
You wrote:
But for CircularLinkedList am not allowed to have a head or a tail.
I would expect this to be true since a circle doesn't have a concrete beginning or end. In a circle, they are arbitrary. Unlike a conventional list, when a circular list is empty, the head (beginning node) is whatever you want it to be. The trick is how you calculate the end. This is important because at some point you need to calculate if the circular list is full.
Assume this array is your "circular list". You could literally decide to make your first insertion right in the middle (index 2). In this case, the "tail" will be your starting index minus 1 (i.e. 1). The problem is, how do you wrap around when you reach index 4 to go to index 0 for the next insertion?
To increment an index in a wrap around manner, you need to use the following formula: index = (index + 1) % N where N is the size of the list; in this case 5.
Now, how do you know your circular list is full? This is actually pretty simple. Before you insert, you will "peek" to the next location to see if there is something there already. If the next slot in your circular list is empty, you can then insert. ON the other hand, if the next slot is full, your list is full.
Last, you need to consider going in reverse order (i.e. to get previous node). The technique is the same. First, you will "peek" the previous index to see if there something there. If the previous slot has a node, you can freely do what you need with it.
The rest of things to considered are unknown to me because your post is not very specific.

Get Exception in thread "main" java.lang.NullPointerException with LinkedList

Simple Linked List
public class List_manager {
Entry first;
Entry last;
public void add(String el) {
if (isEmpty()) { first=new Entry(el); last=first; return; }
new Entry(el,last);
}
public String get() {
Entry temp=first;
first=first.next;
return temp.data;
}
public boolean isEmpty() {
return first==null;
}
private class Entry {
String data;
Entry next;
public Entry(String data,Entry to) {
this.data=data;
to.next=this;
to=this;
}
public Entry(String data) {
this.data=data;
}
}
}
#The main class#
I added 3 element and list contains only 2... why?
public class Main {
public static void main(String[] args) {
List_manager l=new List_manager();
l.add("1");
l.add("2");
l.add("3");
System.out.println(l.get());
System.out.println(l.get()); // Why here output: "3"??
System.out.println(l.get()); // here is an error occurs
}
}
I really don`t get why list contains 2 elements?
Why it ignores 2nd added element?
to=this; This sentence have no influence on variable 'last', because veriable 'to' is formal parameter, while variable 'last' is actual parameter. So, when you executed this sentence "to = this;" the value of
variable 'last' was not changed to next.That's mean variable 'last' always pointed to the first element.
my change is : new Entry(el,last); --> last = new Entry(el,last);
Things look better.
Think about what your get method is doing. You already noticed some aberrant behavior with it.
public String get() {
Entry temp=first;
first=first.next;
return temp.data;
}
What happens the first time I call this?
temp gets whatever first is pointing to
first is moved to its next element (RED FLAG)
temp's data is returned...
One problem is that you're moving your head reference around - this is a bad idea, since it means that you can never access the true first element in your list ever again.
Now on its own, even with this implementation, you should still be able to get the first element.
The above was just a red herring - although you should not be moving your head pointer around. This is the real problem. What happens on subsequent add calls to your list?
public void add(String el) {
if (isEmpty()) {
first = new Entry(el);
last = first;
return;
}
new Entry(el,last);
}
Only the first element inserted and the last element inserted are respected. All other entries after next are overwritten.
I suggest that you use a debugger to figure this one out, as it stems from a misunderstanding of a good approach to do this. You only want to insert things through your tail pointer once you have one element. Doing this through object creation only causes heartache and confusion.
For posterity, I'll leave you with a sample, verbatim implementation I wrote for a singly linked list implementation I did a while back. It describes a more viable approach to inserting into a list.
public void insert(E data) {
Node<E> candidate = new Node<>(data);
if(head == null) {
head = candidate;
tail = head;
} else {
tail.setNext(candidate);
tail = tail.getNext();
}
size = size + 1;
}

Develop a 2-3 search tree in java

I have been given an assignment to create a 2-3 search tree that is supposed to support a few different operations each divided in to different stages of the assignment.
For stage 1 I'm supposed to suport the operations get, put and size. I'm curently trying to implement the get operation but I'm stuck and I can't wrap my head around how to continue so I'm questioning all of my code I have written and felt like a need someone elses input.
I have looked around how to develop a 2-3 search tree but what I found was alot of code that made no sence to me or it just did not do what I needed it to do, and I wanted to try and make it for my self from scratch and here we are now.
My Node class
package kth.id2010.lab.lab04;
public class Node {
boolean isLeaf = false;
int numberOfKeys;
String[] keys = new String[2]; //each node can contain up to 2 keys
int[] values = new int[2]; //every key contains 2 values
Node[] subtrees = new Node[3]; //every node can contain pointers to 3 different nodes
Node(Node n) {
n.numberOfKeys = 0;
n.isLeaf = true;
}
}
My Tree creating class
package kth.id2010.lab.lab04;
public class Tree {
Node root; // root node of the tree
int n; // number of elements in the tree
private Tree(){
root = new Node(root);
n = 0;
}
//Return the values of the key if we find it
public int[] get(String key){
//if the root has no subtrees check if it contain the right key
if(this.root.subtrees.length == 0){
if(this.root.keys[0] == key){
return(this.root.keys[0].values);
}
else if(this.root.keys[1] == key){
return(this.root.keys[1].values);
}
}
//if noot in root, check its subtree nodes
//and here I can't get my head around how to traverse down the tree
else{
for(int i = 0; i < this.root.subtrees.length; i++){
for(int j = 0; j < this.root.subtrees[i].keys.length; j++){
if(this.root.subtrees[i].keys[j] == key){
return(this.root.subtrees[i].keys[j].values);
}
}
}
}
return null;
}
}
What I can tell for my self is that I need to find a way to bind values[] to each key but I can't figure out a way how. Might be the lack of sleep or that I'm stuck in this way of thinking.
bind values[] to each key
It might make more sense to use a HashMap to do that mapping for you, since that's what it's for. Beyond that, if you have two keys and each key has two values, you have 4 values, not 2 ;)
In general, the get method in a tree structure is almost always implementable recursively. Here is a very general implementation of a get algorithm for a 2-3 tree in psudo-code.
V get<K, V>(Node<K, V> node, K key)
{
if(node.is_leaf())
{
return node.keys.get(key); // This will either return the value, or null if the key isn't in the leaf and thus not in the tree
}
if(key < node.left_key)
{
return get(node.left_child, key); // If our key goes to the left, go left recursively
}
else if(node.two_node && key <= node.right_key)
{
return get(node.center_child, key) // If we have two keys, and we're less than the second one, we go down the center recursively
}
else
{
return get(node.right_child, key); // If we've gotten here, we know we're going right, go down that path recursively
}
}
That should get you started in the right direction. Insertion/deletion for 2-3 trees is a bit more complicated, but this should at least get your head around how to think about it. Hint; Your Node class needs to be doubly-linked, that is each node/leaf needs to reference its parent node as well as its children, and the root is simply a node whose parent is null.

Iterators over Tries in Java

I am currently trying to implement a trie data structure for integer tuples. And have implemented as follows:
import java.util.ArrayList;
public class TrieNode {
int num;
ArrayList<TrieNode> links;
boolean endOfTuple;
public TrieNode(int num)
{
this.num = num;
links = new ArrayList<TrieNode>();
this.endOfTuple = false;
}
}
I then have a trie class as follows:
public class Trie {
TrieNode root;
public Trie() {
root = new TrieNode(-1);
}
public void insertTuple(int[] tuple)
{
int l = tuple.length;
TrieNode curNode = root;
for (int i = 0; i < l; i++)
{
TrieNode node = new TrieNode(tuple[i]);
if(!curNode.links.contains(node)){
curNode.links.add(node);
}
curNode = curNode.links.get(curNode.links.indexOf(node));
}
curNode.endOfTuple = true;
}
}
I can add values to this trie, but i need to be able to iterate over this and was wondering how i could do this? For example if i wanted to print the tree using an iterator...Any help will be great...
All you need for an interator is to implement the Iterator interface, which only requires that you supply boolean hasNext() and Integer next(). So the question to ask is: how do represent a position in your trie, such that it's possible to (a) fetch the value associated with that position, and (b) figure out the "next" position given a current one?
I'll refrain from posting an actual solution since I'm not sure whether this is homework. But consider: you can represent a "current position" in your trie just by choosing a particular trie node, and the path of trie nodes you used to reach it. Then you can compute the "next" element recursively: if the current element is a node that has children, then find the first child for which endOfTuple is true. If the current element doesn't have children, then go to its parent and advance to that parent's next child. If that parent doesn't have next children, then go it its parent's next child, etc.

Manual Linked List - Insert before method

This is part of an exercise we did in class, I just can't figure it out...
The required method is the insertBefore(object data) method wherein when a user choose this method it will prompt it to enter a data to be inserted before the reference data(input by user)
An example of how it should run:
// assuming linked list has data 1,2,3 inserted already
Choose Method:
1)Insert Before
choice: 1 // input by user
====Insert Before====
Enter Reference data: 2 // input by user
Enter Data to be inserted: 5 // input by user
supposed output: 1,5,2,3
Here's my code for this exercise: (This is inside a class called LinkList with variables
protected int end;
protected Node start;
and an inner class called Node)
private class Node
{
public char data;
public Node next;
public Node(char data)
{
this.data = data;
}
}
public void insertBef(char ref,char data)
{
Node temp = new Node(data);
Node current = start;
if(end!=0)
{
for(int i = 1; i<end; i++)
{
if(current == start)
{
Node newNode = start;
newNode.data = current.data;
newNode.next = temp;
current = current.next;
}
else if(current.data == ref)
{
Node newNode = current;
newNode.data = current.data;
newNode.next = temp;
current = current.next;
}
}
end++;
}
else
{
temp.next = start;
start = temp;
}
end++;
}
But when I run my code it ouputs 3,5, not 1,5,2,3! I can't see where I might have gone wrong...
Can someone please tell me where the mistake is, and explain how I might fix it?
I understand that to be able to insert before a reference value you should:
Make a new node for the new data
Make a temporary node for the reference value and link
Make the link of the data before the reference value point to the new node and make the link of the new node point to the temporary node
I just can't seem to figure out how to implement it in Java code...
When programming, if it seems hard, you're probably going about it the wrong way...
You only need one line of code to accomplish the task!
list.add(list.indexOf(reference), data);
Here's this line wrapped as an insertBefore method:
public static void insertBefore(List<Integer> list, int reference, int data) {
list.add(list.indexOf(reference), data);
}
Here's a test using your example:
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>(Arrays.asList(1, 2, 3));
insertBefore(list, 2, 5);
System.out.println(list);
}
Output:
[1, 5, 2, 3]
Note: This code will throw an exception if the reference element is not found.
I'll leave it to you to plug that hole.
First things first: for loops are generally a bad idea with linked lists. while loops are much better; you can do something like while(next != null).
Looking at your code, you seem to have a few problems.
Your for loop is overly complicated, and doesn't seem to make a lot of sense. Here's how your loop should look:
Get head node
Begin looping through the list, checking the next node's value as you go
Once you find that the next node's value is the one you're looking for, creating a new node.
Insert the new node by setting its Next value to be equal to the current node's Next value, then set the current node's next value to be the new node.
Return from the function.
Your middle bullet point is actually unnecessary, and I have no idea what you use end for. Regardless, you seem to have the basic principle down, so I won't feel like I'm spoiling you by posting code.
Now, I'm not sure what your start is. Does it hold a value, or is it a dedicated head node? I'd vote for a dedicated head node, I generally find it easier to work with because you don't need to add code for a special case where the number should come before the head. So your start node should be "empty"; the value it holds is ignored, the only thing it's used for is to keep a pointer to the first legit node in the list. If you do this, the insertBef method becomes incredibly simple. NOTE: untested code to follow.
public void insertBef(char ref, char data)
{
Node current = start;
while( current.next != null )
{
if( current.next.value == ref )
{
Node n = new Node(data);
n.next = current.next;
current.next = n;
return;
}
current = current.next;
}
}
Please don't just copy the code. If you have questions, post them and I'll do my best to answer.

Categories

Resources