So I am working on an assignment where we make a rudimentary browser history with c#. The requirement is that we need to use a singly linked list to do this. The issue that I am having is that when I want to go backwards in the history and print it takes from the beginning of the list and not the front. (Example is if I had a list with 1, 2, 3, 4 in it and went back It would be 2, 3, 4 and 1 gets moved to the future category).
public class UnderflowException : Exception
{
public UnderflowException(string s) : base(s) { }
}
public class OverflowException : Exception
{
public OverflowException(string s) : base(s) { }
}
class History
{
protected class IntListNode
{
public string Data;
public IntListNode Next;
public IntListNode(string data)
{
Data = data;
}
public IntListNode(string data, IntListNode next)
{
Next = next;
}
}
protected IntListNode first;
private int i;
public void PrintAll()
{
int j = 0;
IntListNode node = first;
Console.WriteLine("Privious things that you have viewed.");
while (node != null)
{
if (counter <= j)
{
break;
}
Console.WriteLine(node.Data);
node = node.Next;
j++;
}
Console.WriteLine("Things to go forward to.");
while (node != null)
{
Console.WriteLine(node.Data);
node = node.Next;
}
}
private int counter;
public void MoveBackwards()
{
if (counter >= 0)
{
counter = counter - 1;
}
else
{
throw new UnderflowException("underflow");
}
}
public void MoveForwards()
{
if (counter > i)
{
throw new OverflowException("overflow");
}
else
{
counter++;
}
}
public void VisitPage(string desc)
{
IntListNode n = new IntListNode(desc);
n.Next = this.first;
this.first = n;
counter++;
i = counter;
}
}
When I already have items in the list and ask it to move one backwards it takes the first node not the last in the list. from earlier example wanting it to go from 1, 2, 3, 4 use the go backwards command and have the history display 1, 2, 3 and the forward display 4.
Here's an example based on your code, though changed slightly.
Instead of tracking counter and i for our state, I just keep track of two nodes: head (the first one) and current (the one the user is on right now). I'm also inserting new pages at the current.Next node instead of at the head node because that's how I'm used to using a linked list.
By doing this, it makes navigation easy. To go forward, we just set current = current.Next, and to go backward we start at the head and move forward until we find the node whose Next is pointing to current. Then we set current to that node.
To print out the history, we just start at the head and keep moving Next. When we see that Next == current, we know we're at the current page (and I print that in a different color). Then we can keep printing the Next nodes to show the future nodes, until Next is null.
Note that this is really navigation history, not a complete record of browsing history, because if you go back and then visit a new page, you lose the page you went back from.
Hope this helps:
class History
{
private class Node
{
public string Data { get; set; }
public Node Next { get; set; }
public Node(string data) { Data = data; }
}
private Node head;
private Node current;
public void VisitNewPage(string desc)
{
// Create a node for this page
var node = new Node(desc);
// If it's our first page, set the head
if (head == null) head = node;
// Update our current.Next pointer
if (current != null) current.Next = node;
// Set this page as our current page
current = node;
}
public void MoveBackwards()
{
// Can't move backwards from the head
if (current == head) return;
var previous = head;
// Find the node that's behind (pointing to) the current node
while (previous.Next != current)
{
previous = previous.Next;
}
// Make that node our new current
current = previous;
}
public void MoveForwards()
{
// Just move to the next node
if (current.Next != null) current = current.Next;
}
public void PrintCurrent()
{
Console.WriteLine($"You are on page: {current.Data}");
}
public void PrintHistory()
{
Console.WriteLine("\nBrowsing History");
if (head == null)
{
Console.WriteLine("[Empty]");
return;
}
var node = head;
// Print previous pages
while (node != current)
{
Console.WriteLine($" - {node.Data}");
node = node.Next;
}
// Print current page in green
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine($" - {node.Data}");
Console.ResetColor();
node = node.Next;
// Print next pages
while (node != null)
{
Console.WriteLine($" - {node.Data}");
node = node.Next;
}
Console.WriteLine();
}
}
Sample Usage
Here's a simple infinite loop that lets you visit new sites, move forwards, backwards, and print the history:
private static void Main()
{
var history = new History();
while (true)
{
Console.Write("Enter new page to visit, [b]ack, [f]orward, or [p]rint: ");
var input = Console.ReadLine();
if (string.IsNullOrWhiteSpace(input)) continue;
switch (input.ToLower())
{
case "b":
case "back":
history.MoveBackwards();
break;
case "f":
case "forward":
history.MoveForwards();
break;
case "p":
case "print":
history.PrintHistory();
break;
default:
history.VisitNewPage(input);
break;
}
}
}
Output
Related
So I have my code implementing Queue in a Linked List version. Everything working, but the display method. I have spent days trying to figure out the right way to display the contents of the nodes in my Queue, without modifying the nodes or queue itself.
This is my code:
public class QueueNode
{
private Object bike;
private QueueNode next;
public QueueNode(Object bike)
{
this.bike = bike;
next = null;
}
public Object Bike //Content
{
get
{
return bike;
}
set
{
bike = value;
}
}
public QueueNode Next //Pointer
{
get
{
return next;
}
set
{
next = value;
}
}
} // end of QueueNode
// This class inherits the interface IQueue, that uses these methods, not relevant here.
public class CircularQueue : IQueue
{
private int capacity = Int32.MaxValue;
private int count = 0;
private QueueNode tail = null; //Node
public int Capacity
{
get
{
return capacity;
}
}
public int Count
{
get
{
return count;
}
}
public bool IsEmpty()
{
return count == 0;
}
public bool IsFull()
{
return count == capacity;
}
public void Enqueue(Object item)
{
// check the pre-condition
if (!IsFull())
{
QueueNode aNode = new QueueNode(item);
if (count == 0) //special case: the queue is empty
{
tail = aNode;
tail.Next = tail;
}
else //general case
{
aNode.Next = tail.Next;
tail.Next = aNode;
tail = aNode;
}
count++;
}
}
public Object Dequeue()
{
// check the pre-condition
if (!IsEmpty())
{
Object data;
if (count == 1) //special case: the queue has only 1 item
{
data = tail.Bike;
tail = null;
}
else //general case
{
data = tail.Next.Bike;
tail.Next = tail.Next.Next;
}
count--;
return data;
}
else
return null;
}
MY PROBLEM: I created this code to display the content of the Nodes (and it display them all), but it ends up modifying the contents, placing the same value in every single node at the end of the task.
/*public void DisplayBikes()
{
if (!IsEmpty())
{
Object data;
for(int i = 0; i <count; i++)
{
data = tail.Next.Bike;
Console.WriteLine(data);
tail.Next = tail.Next.Next;
}
}
else
Console.WriteLine("Sorry. There are no Bikes available");
}*/
Then I went a bit adventurous, and created a temporary Node to display the contents of all the Nodes in my Queue, but ended up being a messed up thing. I got this message:
System.NullReferenceException: 'Object reference not set to an instance of an object.'
tail was null.
So, at this point I have zero idea on how to do this. I know I'm pretty close, but I don't know what I'm missing here, to make this code print the contents of my Nodes....
HELP PLEASE!
public void DisplayBikes()
{
int c = count;
QueueNode temp = tail.Next;
if(!isFull())
{
while(c > 0)
{
Console.WriteLine(temp.Bike);
temp = tail.Next.Next;
c--;
}
}
else
Console.WriteLine("Sorry. There are no Bikes available");
}
SOLVED myself.
public void DisplayBikes()
{
int c = count;
QueueNode temp = tail.Next;
if(!isFull())
{
while(c > 0)
{
Console.WriteLine(temp.Bike);
temp = temp.Next; //Here. I needed to iterate over the same node
c--;
}
}
else
Console.WriteLine("Sorry. There are no Bikes available");
}
That was it. No one dared to help.... So, thank you guys >:(
i tried to fix a code, which is a LinkedList. The task is to Remove the last X elements of the list.
I tried it with RemoveRange, but VS don't accept my solution and says, that RemoveRange doesn't exist.
var list = new DoublyLinkedList<string>();
list.Add("A");
list.Add("B");
list.Add("C");
list.Add("D");
list.Add("E");
list.RemoveLast(2);
This is the Code in the Program (Main).
In a second class there should be the method RemoveLast, but i dont get a working code. Can someone explain me, how i get the RemoveLast?
using System;
using System.Collections;
using System.Collections.Generic;
namespace Test
{
public class DoublyLinkedList<T> : IEnumerable<T>
{
public void RemoveLast(int v)
{
int remove = Math.Max(0, this.Count - v);
this.RemoveRange(v, this.Count - v);
}
}
}
RemoveRange is red underlined
Thank you for your help!
Full DoublyLinkedList:
`using System;
using System.Collections;
using System.Collections.Generic;
namespace Test
{
public class DoublyLinkedList<T> : IEnumerable<T>
{
public void RemoveLast(int v)
{
int remove = Math.Max(0, this.Count - v);
this.RemoveRange(v, this.Count - v);
}
private sealed class Node
{
public T Item { get; set; }
public Node Previous { get; set; }
public Node Next { get; set; }
}
private Node first, last;
public int Count { get; private set; }
public void Add(T item)
{
Node newItem = new Node() { Item = item, Next = null, Previous = null };
if (first == null)
{
first = newItem;
last = newItem;
}
else
{
last.Next = newItem;
newItem.Previous = last;
last = newItem;
}
Count++;
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
Node node = first;
while (node != null)
{
yield return node.Item;
node = node.Next;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable<T>)this).GetEnumerator();
}
public override string ToString()
{
string s = "";
Node node = first;
while (node != null)
{
s += node.Item.ToString() + " -> ";
node = node.Next;
}
s += "Count: " + Count.ToString();
return s;
}
private Node find(T item)
{
Node node = first;
while (node != null)
{
if (node.Item.Equals(item))
return node;
node = node.Next;
}
return null;
}
private Node findPrevious(T item)
{
Node previousNode = null;
Node node = first;
while (node != null)
{
if (node.Item.Equals(item))
return previousNode;
previousNode = node;
node = node.Next;
}
return null;
}
}
}`
You do know there is already a double linked list class, don't you?
System.Collections.Generic.LinkedList? My advice would be to use that class.
If it is too much work to redesign your code, for instance because your DoublyLinkedList is already used a lot, my advice would be to make DoublyLinkedList an adapter for LinkedList:
class DoublyLinkedList<T> : IEnumerable<T>, IEnumerable
{
private readonly LinkedList<T> linkedList = new LinkedList<T>();
public int Count => this.linkedList.Count;
public void Add(T item)
{
this.LinkedList.Add(item);
}
public IEnumerator<T> GetEnumerator()
{
return this.LinkedList.GetEnumerator();
}
... // etc.
}
You need to add a method to remove the last N items from your list. For example
RemoveLast(10) is supposed to remove the last 10 elements from your doubly linked list. If your list has 10 or less elements, this would clear your complete list.
void Clear()
{
this.LinkedList.Clear();
}
void RemoveLast()
{
if (this.LinkedList.Count != 0)
this.linkedList.RemoveLast();
}
void RemoveLast(int removeCount)
{
if (this.Count <= removeCount)
{
this.linkedList.Clear();
}
else
{
for (int i=0; i<removeCount; ++i)
{
this.RemoveLast();
}
}
}
It might be that your supervisor is stubborn and does not follow your advise to reuse fully tested trustworthy .NET classes. In that case you'll have to change the RemoveLast() method.
void Clear()
{
this.first = null;
this.last = null;
this.count = 0;
}
void RemoveLast()
{
switch (this.Count)
{
case 0:
// empty list; do nothing
break;
case 1:
// removing the last element of the list
this.Clear();
break;
default:
var lastNode = this.last;
// because more than one element I'm certain there is a previous node
var previousNode = lastNode.Previous;
var previousNode.Next = null;
this.last = previousNode;
--this.count;
break;
}
}
Here is how you can implement RemoveLast(int n) in your DoublyLinkedList:
// Removes last "n" elements.
public void RemoveLast(int n)
{
for (int i = 0; i < n; i++)
RemoveLast();
}
// Removes the last element.
public void RemoveLast()
{
// List is empty. No need to remove elements.
if (first == null)
{
return;
}
// List contains only one element. Remove it.
else if (first == last)
{
first = null;
last = null;
}
// List contains more than one element. Remove the last.
else
{
// The next two lines make "last" to point to the element before the last.
last = last.Previous;
last.Next = null;
}
Count--;
}
Here is complete sample.
If RemoveRange is not available, you can easiliy roll your own implementation that works on any enumerable without Linq in this way (this code is an idea as I do not have access to all your code).
using System;
using System.Collections;
using System.Collections.Generic;
public void RemoveRange(int count)
{
if (count > this.Count)
throw new ArgumentOutOfRangeException(nameof(count));
while (count > 0)
{
RemoveTail();
count--;
}
}
private void RemoveTail()
{
if (this.Count == 0)
return;
var previous = last.Previous;
if (previous != null)
{
previous.Next = null;
last = previous;
this.Count--;
}
else
{
// this implies count == 1
last = null;
first = null;
this.Count = 0;
}
}
Essentially, you can expose your RemoveRange method and then perform an agnostic removal of the last node (tail) one by one.
This answer has been edited to reflect the code changes.
I am learning Data Structure. Today, I wanted to implement Queue using Linked List. As we have FRONT and REAR first index of the entry point of the Queue. If someone asks me to implement a Queue with Linked List, please confirm my below implementation (I am able to achieve the Queue objective without the REAR object.)
Is this implementation valid?
class Queue
{
Node head;
class Node
{
public int Value;
public Node next;
public Node()
{
next = null;
}
}
public void addElement(int val)
{
if (head == null)
{
Node temp = new Node();
temp.Value = val;
head = temp;
return;
}
Node tempNode = head;
while (tempNode.next != null)
{
tempNode = tempNode.next;
}
Node newElement = new Node();
newElement.Value = val;
tempNode.next = newElement;
}
public void Dequeue()
{
if (head != null)
{
if (head.next != null)
{
head = head.next;
return;
}
head = null;
}
}
}
class Program
{
static void Main(string[] args)
{
Queue queue = new Queue();
queue.addElement(10);
queue.addElement(20);
queue.addElement(30);
queue.addElement(40);
queue.Dequeue();
queue.Dequeue();
queue.Dequeue();
queue.Dequeue();
}
}
Well, if we want to have front and rear ends, let's have them:
private Node m_Head;
private Node m_Tail;
You have just one Node head; field and that's why your implementation at least inefficient: you have O(N) time complexity to addElement:
...
while (tempNode.next != null)
{
tempNode = tempNode.next;
}
...
When you can easily have O(1)
I suggest using typical names like Enqueue instead of addElement and have Try methods (often, we don't want exceptions if queue is empty). Finally, let's use generics: MyQueue<T> where T is item's type.
public class MyQueue<T> {
private class Node {
public Node(Node next, T value) {
Next = next;
Value = value;
}
public Node Next { get; internal set; }
public T Value { get; }
}
private Node m_Head;
private Node m_Tail;
public void Enqueue(T item) {
Node node = new Node(null, item);
if (m_Tail == null) {
m_Head = node;
m_Tail = node;
}
else {
m_Tail.Next = node;
m_Tail = node;
}
}
public bool TryPeek(out T item) {
if (m_Head == null) {
item = default(T);
return false;
}
item = m_Head.Value;
return true;
}
public T Peek() {
if (m_Head == null)
throw new InvalidOperationException("Queue is empty.");
return m_Head.Value;
}
public bool TryDequeue(out T item) {
if (m_Head == null) {
item = default(T);
return false;
}
item = m_Head.Value;
m_Head = m_Head.Next;
return true;
}
public T Dequeue() {
if (m_Head == null)
throw new InvalidOperationException("Queue is empty.");
T item = m_Head.Value;
m_Head = m_Head.Next;
return item;
}
}
I just pass this linked list code from java to C# but I keep getting errors in the print method with a NullReferenceException, I am new working with C#, I dont know if the error if in the method or probably it is way that the code is implemented.
Node Class
class SLLNode
{
public int info;
public SLLNode next;
public SLLNode() { }
public SLLNode(int el)
:this(el, null)
{
}
public SLLNode(int el, SLLNode next)
{
this.info = el;
this.next = next;
}
}
Linked List Class
class SLList
{
protected SLLNode head;
protected SLLNode tail;
public SLList()
{
head = tail = null;
}
public Boolean isEmpty()
{
return head == null;
}
public void addToHead(int el)
{
if (!isEmpty())
{
head = new SLLNode(el, head);
}
else
{
head = tail = new SLLNode(el);
}
}
public void addToTail(int el)
{
if (!isEmpty())
{
tail.next = new SLLNode(el);
tail = tail.next;
}
else
{
head = tail = new SLLNode(el);
}
}
public String print()
{
String str = "";
for (SLLNode tmp = head; head.next != null; tmp = tmp.next)
{
str += ", " + tmp.info;
}
return str;
}
}
Your print() method logic is a bit off in for loop part. It is "incrementing" tmp variable, but check null condition from head.next.
for (SLLNode tmp = head; head.next != null; tmp = tmp.next)
{
str += ", " + tmp.info;
}
Value of head.next is never change, so the loop will never end until something (exception for example) force it to stop. You should check null condition from tmp instead, so I think the loop should've been this way :
for (SLLNode tmp = head; tmp != null; tmp = tmp.next)
{
str += ", " + tmp.info;
}
I have a very strange issue. Basically I have created a class called TreeNode that represents a node in a tree. I then create the tree by adding all the nodes to a List.
class TreeNode
{
private TreeNode parent, lChild, rChild;
private int key, val;
public int Key
{
get { return key; }
set { key = value; }
}
public int Val
{
get { return val; }
set { val = value; }
}
public TreeNode Parent
{
get { return parent; }
set { parent = value; }
}
public TreeNode LChild
{
get { return lChild; }
}
public TreeNode RChild
{
get { return rChild; }
}
public TreeNode(int k, int v)
{
key = k;
val = v;
}
public void SetChild(TreeNode leftChild, TreeNode rightChild)
{
this.lChild = leftChild;
this.rChild = rightChild;
}
public bool isLeaf()
{
if (this.lChild == null && this.rChild == null)
{
return true;
} else
{
return false;
}
}
public bool isParent()
{
if (this.parent == null)
{
return true;
}
else
{
return false;
}
}
public void SetParent(TreeNode Parent)
{
this.parent = Parent;
}
}
So if i put a breakpoint just after the creation of the tree and hover over the list in Visual Studio I can see the structure of the tree - with all the references working perfectly from the root down to the leaves.
If however I do the following:
TreeNode test = newTree[newTree.Count - 1];
please note:
private List<TreeNode> newTree = new List<TreeNode>();
which returns the root node - and hover over again I can do down one level (i.e. left child or right child) but these children do not have any references for their children after that.
I'm wondering if I'm losing the reference in memory to the other nodes in the list as the test node is not part of the list?
Any help would be greatly appreciated.
Thanks
Tom
you sure you don't have (note no space between new and tree in your code)
TreeNode test = new Tree[newTree.Count - 1];
Which would create a new empty array of tree (probably not what you intended), and leave your original tree un-rooted and inaccessible.
Can you make sure your code is correct, please?
Seems as though I found the issue - I wasn't correctly updating some of the parent nodes with their relevant child nodes - problem solved.
Thanks for your help
Tom