C# Queue Display implementation - Print contents without modifying nodes - c#

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 >:(

Related

DoublyLinkedList C# Removelast two elements

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.

Queue Implementation using Linked List: C#

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;
}
}

virtualmode Datagridview with just in time data loading via async-await data retriever

I followed the example given here How to: Implement Virtual Mode with Just-In-Time Data Loading in the Windows Forms DataGridView Control to implement a just in time loading for a virtual mode DataGridView. This worked nice but given the size of the database I noticed a blocking of the UI thread during calls to my IDataPageRetriever. To address that, I implemented the async-await pattern into the class for the IDataPageRetriever. However, now there are a lot of rows not displaying any values or I need to click them to make them display the value. There must be something not straight forward in combining virtual-mode DataGridView with async-await.
I assume there is a typical pattern around and I miss something basic.
Thank you for your input!
Edit 1: adding code
DataGridView's CellValueNeeded
private async void dgvCompound_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
{
var dgv = (DataGridView)sender;
try
{
e.Value = await memoryCache.RetrieveElement(e.RowIndex, dgv.Columns[e.ColumnIndex].DataPropertyName);
}
catch (OperationCanceledException)
{
}
dgv.InvalidateRow(e.RowIndex);
}
Cache
public class Cache
{
private static int RowsPerPage;
public event EventHandler Initialised;
public event EventHandler CacheChanged;
// Represents one page of data.
public struct DataPage
{
public CompoundDataTable table;
public DataPage(CompoundDataTable table, int rowIndex)
{
this.table = table;
LowestIndex = MapToLowerBoundary(rowIndex);
HighestIndex = MapToUpperBoundary(rowIndex);
System.Diagnostics.Debug.Assert(LowestIndex >= 0);
System.Diagnostics.Debug.Assert(HighestIndex >= 0);
}
public int LowestIndex { get; private set; }
public int HighestIndex { get; private set; }
public static int MapToLowerBoundary(int rowIndex)
{
// Return the lowest index of a page containing the given index.
return (rowIndex / RowsPerPage) * RowsPerPage;
}
private static int MapToUpperBoundary(int rowIndex)
{
// Return the highest index of a page containing the given index.
return MapToLowerBoundary(rowIndex) + RowsPerPage - 1;
}
}
private DataPage[] cachePages;
private IDataPageRetriever dataSupply;
public Cache(IDataPageRetriever dataSupplier, int rowsPerPage)
{
dataSupply = dataSupplier;
Cache.RowsPerPage = rowsPerPage;
LoadFirstTwoPages();
}
public System.Data.SqlClient.SortOrder sortOrder
{
get { return dataSupply.sortOrder; }
set { dataSupply.sortOrder = value; }
}
public string sortByColumn
{
get { return dataSupply.sortByColumn; }
set
{
dataSupply.sortByColumn = value;
Reload();
}
}
public Dictionary<int, float> sortBySimilaritySeachResult
{
get { return dataSupply.sortBySimilaritySeachResult; }
set
{
dataSupply.sortBySimilaritySeachResult = value;
Reload();
}
}
// Sets the value of the element parameter if the value is in the cache.
private bool IfPageCached_ThenSetElement(int rowIndex, int columnIndex, ref string element)
{
if (IsRowCachedInPage(0, rowIndex))
{
if (cachePages[0].table == null || cachePages[0].table.Rows.Count == 0)
{
return true;
}
try
{
element = cachePages[0].table.Rows[rowIndex % RowsPerPage][columnIndex].ToString();
}
catch (Exception exx)
{
throw;
}
return true;
}
else if (IsRowCachedInPage(1, rowIndex))
{
if (cachePages[1].table == null || cachePages[1].table.Rows.Count == 0)
{
return true;
}
try
{
element = cachePages[1].table.Rows[rowIndex % RowsPerPage][columnIndex].ToString();
}
catch (Exception exx)
{
throw;
}
return true;
}
return false;
}
public async Task<string> RetrieveElement(int rowIndex, int columnIndex)
{
string element = null;
if (IfPageCached_ThenSetElement(rowIndex, columnIndex, ref element))
{
return element;
}
else
{
return await RetrieveData_CacheIt_ThenReturnElement(rowIndex, columnIndex);
}
}
static readonly CompoundDataTable c = new CompoundDataTable();
public async Task<string> RetrieveElement(int rowIndex, string colName) => await RetrieveElement(rowIndex, c.Columns[colName].Ordinal);
private async void LoadFirstTwoPages()
{
cachePages = new DataPage[]{
new DataPage(await dataSupply.SupplyPageOfData(DataPage.MapToLowerBoundary(0), RowsPerPage), 0),
new DataPage(await dataSupply.SupplyPageOfData(DataPage.MapToLowerBoundary(RowsPerPage),RowsPerPage), RowsPerPage)
};
Initialised?.Invoke(this, EventArgs.Empty);
CacheChanged?.Invoke(this, EventArgs.Empty);
}
public async void Reload()
{
cachePages[0].table = await dataSupply.SupplyPageOfData(DataPage.MapToLowerBoundary(0), RowsPerPage);
cachePages[1].table = await dataSupply.SupplyPageOfData(DataPage.MapToLowerBoundary(RowsPerPage), RowsPerPage);
CacheChanged?.Invoke(this, EventArgs.Empty);
}
private async Task<string> RetrieveData_CacheIt_ThenReturnElement(int rowIndex, int columnIndex)
{
var IndexToUnusedPage = GetIndexToUnusedPage(rowIndex);
// Retrieve a page worth of data containing the requested value.
try
{
CompoundDataTable table = await dataSupply.SupplyPageOfData(DataPage.MapToLowerBoundary(rowIndex), RowsPerPage);
// Replace the cached page furthest from the requested cell
// with a new page containing the newly retrieved data.
cachePages[IndexToUnusedPage] = new DataPage(table, rowIndex);
return await RetrieveElement(rowIndex, columnIndex);
}
catch (OperationCanceledException)
{
cachePages[IndexToUnusedPage] = new DataPage(null, rowIndex);
throw;
}
}
// Returns the index of the cached page most distant from the given index
// and therefore least likely to be reused.
private int GetIndexToUnusedPage(int rowIndex)
{
if (rowIndex > cachePages[0].HighestIndex && rowIndex > cachePages[1].HighestIndex)
{
int offsetFromPage0 = rowIndex - cachePages[0].HighestIndex;
int offsetFromPage1 = rowIndex - cachePages[1].HighestIndex;
if (offsetFromPage0 < offsetFromPage1)
{
return 1;
}
return 0;
}
else
{
int offsetFromPage0 = cachePages[0].LowestIndex - rowIndex;
int offsetFromPage1 = cachePages[1].LowestIndex - rowIndex;
if (offsetFromPage0 < offsetFromPage1)
{
return 1;
}
return 0;
}
}
// Returns a value indicating whether the given row index is contained
// in the given DataPage.
private bool IsRowCachedInPage(int pageNumber, int rowIndex)
{
return rowIndex <= cachePages[pageNumber].HighestIndex &&
rowIndex >= cachePages[pageNumber].LowestIndex;
}
}
DataRetriver
public class DataRetriever : IDataPageRetriever
{
private SemaphoreSlim _throttle;
private static Queue<CancellationTokenSource> _tasklist;
public DataRetriever()
{
sortByColumn = "Id";
_throttle = new SemaphoreSlim(2);
_tasklist = new Queue<CancellationTokenSource>();
//just add two cancelation dummies
for (int i = 0; i < _throttle.CurrentCount; i++)
{
_tasklist.Enqueue(new CancellationTokenSource());
}
}
public int RowCount
{
get { return DB.dsTgxChemTableAdapters.CompoundTableAdapter.RowCount(); }
}
// Declare variables to be reused by the SupplyPageOfData method.
private string _sortByColumn;
public string sortByColumn
{
get { return _sortByColumn; }
set
{
if (_sortByColumn == value)
{
sortOrder = sortOrder == SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending;
}
else
{
_sortByColumn = value;
sortOrder = SortOrder.Ascending;
}
}
}
public SortOrder sortOrder { get; set; }
List<int> exclusion = new List<int>();
public async Task<CompoundDataTable> SupplyPageOfData(int lowerPageBoundary, int rowsPerPage)
{
CompoundDataTable dt = new CompoundDataTable();
bool dowork = false;
lock (exclusion)
{
if (!exclusion.Contains(lowerPageBoundary))
{
exclusion.Add(lowerPageBoundary);
dowork = true;
}
}
if (dowork)
{
CancellationTokenSource cts = new CancellationTokenSource();
_tasklist.Enqueue(cts);
CancellationTokenSource prevous = _tasklist.Dequeue();
prevous.Cancel();
prevous.Dispose();
await _throttle.WaitAsync(cts.Token);
try
{
if (!cts.IsCancellationRequested)
{
await DB.dsTgxChemTableAdapters.CompoundTableAdapter.FillAsync(dt, lowerPageBoundary, rowsPerPage, sortByColumn, sortOrder, cts.Token);
}
}
finally
{
_throttle.Release();
lock (exclusion)
{
exclusion.Remove(lowerPageBoundary);
}
}
}
return dt;
}
}
In my case I did this: I have exposed a few things on the Cache (which I call "data source") - a method LoadNextPage() and an event PageLoaded (this could be just one async method, but I found this split resulted in a bit cleaner code), and a cached row count (in your case it would be HighestIndex of the last cached page).
LoadNextPage() starts an asynchronous loading process of the data, and when the data is loaded and cached, the PageLoaded event fires.
The UI class is first calling LoadNextPage() to load the first page, then PageLoaded fires and I set the grid view's RowCount to the loaded cached row count.
After that the grid view starts calling CellValueNeeded for all cells, and you can fill it synchronously from the cache. When it requires data for the last row of the cache, I call LoadNextPage() again, and the process repeats.
So all the time the grid view is tricked that it only has cached rows and nothing else.
One catch was that CellValueNeeded might be called multiple times for the same row, so make sure you are not loading things twice in parallel this case.
I did it for the Git log in NitroGit Git client for Windows, so there it is a one-way loading process meaning that pages from 1 to N are always cached. If you have a different case, e.g. want to start in the middle and scroll up, or even populate random pages, you need to do more work, but it is possible with the same principle of tricking the grid view to just have the same number of rows as your cache has, and then mapping between the grid view row index and the real data index, while populating data "on a side" when the borders of the cache are reached in the grid on the screen.

Recursive Insertion in a Binary Tree

Why reason the member variables LEFT and RIGHT never change when i make the recursive call?
Here's the Source Code:
public class C_Nodo
{
int dato;
C_Nodo left;
C_Nodo right;
public int DATO
{
get { return dato; }
set { dato = value; }
}
public C_Nodo LEFT
{
get { return this.left; }
set { this.left= value; }
}
public C_Nodo RIGHT
{
get { return this.right; }
set { this.right = value; }
}
public C_Nodo(int inf)
{
this.dato = inf;
this.left = null;
this.right = null;
}
}
public class C_Arbol_Bin
{
C_Nodo root;
public C_Arbol_Bin()
{
root = null;
}
Simple insertion in the root or make the recursive call
public void inserta(int dat)
{
if (root == null)
{
root = new C_Nodo(dat);
}
else
{
insert_Order(this.root, dat);
}
}
Here i make the recursive insertion in ordered way depending of the value that contains the father node but RIGH and LEFT never change.
public void insert_Order(C_Nodo tree, int inf)
{
if (tree == null)
{
tree = new C_Nodo(inf);
}
else
{
if (tree.DATO > inf)
{
insert_Order(tree.LEFT, inf);
}
else
{
insert_Order(tree.RIGHT, inf);
}
}
}
}
Declare the function like
public void insert_Order( ref C_Nodo tree, int inf );
Also as this function is an auxiliary function for function inserta then it could be declared like private
What Vlad said...
Basically the reason that the LEFT/RIGHT parts are always null is because you are passing a reference-type object by value, and then call new C_Nodo() on it - this creates a pointer to a new location for your object.
So you can either use Vlad's solution and pass it by reference, or you can change your insert and insert_Order methods to return the Node object and save it in the root node:
public void inserta(int dat)
{
if (root == null)
{
root = new C_Nodo(dat);
}
else
{
this.root = insert_Order(this.root, dat);
}
}
private C_Nodo insert_Order(C_Nodo tree, int inf)
{
if (tree == null)
{
tree = new C_Nodo(inf);
}
else
{
if (tree.DATO > inf)
{
tree.LEFT = insert_Order(tree.LEFT, inf);
}
else
{
tree.RIGHT = insert_Order(tree.RIGHT, inf);
}
}
return tree;
}
Check out this article for more info on references: https://msdn.microsoft.com/en-us/library/s6938f28.aspx

Null Refence in Linked List passing from Java to C#

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;
}

Categories

Resources