How to search an element in a Linked List? (c#) - c#

I am given this set of code and I need to fill it up with some code above the while loop and in the While loop. I have seen some documentation but all i have seen is search methods with two arguments and this one only has one. I already wrote the part inside the while loop but im note sure if that is correct. How can I finish this code so that it searches for the value given as the parameter?
note: this is not a homework assignment where I ask you to do it for me, rather this is one of the few resources we have for studying and if you could complete this it would give me a better grasp.
When I run this code now I get this error message:
 Type "Tests.Node" does not contain a definition for "value" and no extension method "value" of type "Tests.Node" could be found. Are you missing an assembly reference?
{
public class Node<T> where T : IComparable
{
public T Value { get; }
public Node<T> Next { get; set; }
public Node(T value, Node<T> next)
{
this.Value = value;
this.Next = next;
}
}
public class LinkedList<T> where T : IComparable
{
public Node<T> start;
public LinkedList()
{
start = null;
}
public LinkedList(Node<T> node)
{
start = node;
}
public Node<T> Search(T value)
{
[here is code needed]
while (start != null)
if(start.value.CompareTo(value) == 0){
return start;
}
start = start.next;
}
}
public class Program {
public static void Main(string[] args){
var list =
new LinkedList<int>(
new Node<int>(
5, new Node<int>(
7, new Node<int>(
21, new Node<int>(
30, null)
)
)
)
);
var a = 21;
var fr = list.Search(a);
}
}
}

You are very close to correct solution. First of all you need to fix compiler errors - change value and next to Value and Next, cause that how properties on your Node class are called.
Next you need to add curly brackets so the while block will execute assignment start = start.Next; (currently only if statement is inside while, so you will end with infinite loop)
Next you need to fix return - add return null; after while block - value you will return if nothing is found (also without it code will not compile).
Lastly you will need to fix the issue with changing the list during search (you are modifying start field of your LinkedList class with start = start.Next, you should not do that), introduce a temporary variable (i've name it curr), assign it value of start and use it in your while loop:
public Node<T> Search(T value)
{
var curr = start;
while (curr != null)
{
if (curr.Value.CompareTo(value) == 0)
{
return curr;
}
curr = curr.Next;
}
return null;
}

I suggest implementing IEnumerable<Node<T>> interface
public class Node<T> : IEnumerable<Node<T>> where T : IComparable {
public IEnumerator<Node<T>> GetEnumerator() {
for (Node<T> item = this; item != null; item = item.Next)
yield return item;
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
...
Then you can use Linq to query the collection:
using System.Linq;
...
public static void Main(string[] args) {
LinkedList<int> list = ...
int a = 21;
var fr = list.start.FirstOrDefault(item => item.Value == a);

Related

NullReferenceException when trying to add item to end of singly linked list

I am trying to add an node to the end of singly linked list. But I keep getting NullReferenceException. I have tried everything but I can't get it to work. The idea behind the code is to keep looping through the list until we reach null(which marks the end of the linked list) then we add a new node to the end.
So the question is why am I getting this and how can I get it to work?
Below you will find the code.
using System;
using System.Diagnostics;
using System.Threading;
namespace LinkedList
{
public class Node<T> where T : IComparable
{
public T Value;
public Node<T> Next { get; set; }
public Node(T value, Node<T> next)
{
this.Value = value;
this.Next = next;
}
}
public class SortedLinkedList<T> where T : IComparable
{
public Node<T> start;
public SortedLinkedList()
{
start = null;
}
public SortedLinkedList(Node<T> node)
{
start = node;
}
public void Insert(T value)
{
if ( this.start == null )
{
this.start = new Node<T>(value, this.start);
}
Node<T> curr = this.start;
while ( curr != null )
{ curr = curr.Next;}
curr.Next = new Node<T>(value,curr.Next);
}
}
public class Program
{
public static void Main(string[] args)
{
var list =
new SortedLinkedList<int>(
new Node<int>(
5, new Node<int>(
7, new Node<int>(
21, new Node<int>(
30, null)
)
)
)
);
list.Insert(12);
var list2 = new SortedLinkedList<string>();
list2.Insert("hello");
}
}
}
You have to rewrite your while loop and check curr.Next property for null value, otherwise you'll get a null as curr value after loop finishes.
Node<T> curr = start;
while (curr.Next != null)
{
curr = curr.Next;
}
curr.Next = new Node<T>(value, curr.Next);
Also, you insert the node at the end of list without comparison with existing nodes. It means, that your list isn't sorted despite SortedLinkedList class name.
To have a list sorted you should compare the values one by one in while loop to find a correct place for value, or insert it to the end, if place is not found. Something like that
var comparer = Comparer<T>.Default;
Node<T> curr = start;
var inserted = false;
while (curr.Next != null)
{
if (comparer.Compare(curr.Value, value) < 0 &&
comparer.Compare(curr.Next.Value, value) >= 0)
{
var previous = curr.Next;
curr.Next = new Node<T>(value, previous);
inserted = true;
break;
}
curr = curr.Next;
}
if (!inserted)
curr.Next = new Node<T>(value, curr.Next);
Look at this fragment of code:
while ( curr != null )
{ curr = curr.Next;}
Here loop ends when curr is null, so next line you get null reference on curr.Next. Try following:
while (curr.Next != null)
{
curr = curr.Next;
}

How do I set the Next property of a node in a LinkedList to another node in another LinkedList?

In C#, I am currently trying to link one node from a certain LinkedList to another node in another LinkedList. I am trying to make this for a game where tiles are connected in levels stacked on top of eachother. However, changing the Next property in the list gives an error. This is the code:
tileList2.First.Next = tileList1.First;
This is the error;
Property or indexer 'LinkedListNode.Next' cannot be assigned to -- it is read only."
How can I (otherwise) set the Next of this node to the First of the other node? What is causing this error? Is there any workaround?
Every node in the framework implementation of LinkedList has a reference to the list containing it, which makes transferring elements to another list O(n) instead of O(1), which defeats the purpose of the linked list implementation. If you want to transfer elements to another list in this implementation, you would have to remove and add them one by one (using Remove and AddAfter on the list) so that they each get a reference to the other list.
I suspect this is not what you're after, though. As other comments state, the needs of your list are probably simple enough that you'd be better off making your own much simpler linked list. And that question is already addressed elsewhere on SO (Creating a very simple linked list).
Since that answer doesn't include easy enumeration and initialization, I made my own.
class ListNode<T> : IEnumerable<T>
{
public T data;
public ListNode<T> Next;
private ListNode() { }
public ListNode(IEnumerable<T> init)
{
ListNode<T> current = null;
foreach(T elem in init)
{
if (current == null) current = this; else current = current.Next = new ListNode<T>();
current.data = elem;
}
}
class ListEnum : IEnumerator<T>
{
private ListNode<T> first;
private ListNode<T> current;
bool more;
public ListEnum(ListNode<T> first) { this.first = first; more = true; }
public T Current { get { return current.data; } }
public void Dispose(){}
object System.Collections.IEnumerator.Current { get { return current.data; } }
public void Reset() { current = null; more = true; }
public bool MoveNext()
{
if (!more)
return false;
else if (current == null)
return more = ((current = first) != null);
else
return more = ((current = current.Next) != null);
}
}
public IEnumerator<T> GetEnumerator()
{
return new ListEnum(this);
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
static void Main(string[] args)
{
ListNode<int> l1 = new ListNode<int>(new int[] {3,1,4,1,5,9});
ListNode<int> l2 = new ListNode<int>(new int[] { 5 });
l2.Next = l1.Next;
foreach (int i in l2)
Console.WriteLine(i);
}
you can't set LinkedListNode.Next directly, it is readonly.
you also can't use LinkedList.AddLast because the LinkedlListNode you are trying to add is already in a list.
you actually need to break the lists and create new ones.
or you could implement your own linked list.

How to convert a linkedlist to an array in c#?

For a school project I am making an RPN calculator. This calculator has an abstract class Stack where three different implementations of stacks derive from. One of them is a linked list stack. For these stacks I have to show what values are on the stack. To do this I use an array. For my arraystack and list stack it was easy, but I can't figure out how to convert a linked list to an array. What is the best way to do that?
This is the code that I use for my linked list.
public class Node
{
public int data;
public Node next;
public Node(int i)
{
data = i;
next = null;
}
public void Add(int i)
{
if (next == null)
{
next = new Node(i);
}
else
{
next.Add(i);
}
}
}
public class MyLinkedList
{
private Node headNode;
private int count;
public MyLinkedList()
{
headNode = null;
count = 0;
}
public int Count()
{
return count;
}
public void Add(int i)
{
if (headNode == null)
{
headNode = new Node(i);
}
else
{
headNode.Add(i);
}
count++;
}
Implement IEnumerable on your LinkedList
using System.Linq;
Call ToArray on the LinkedList.
Implementing IEnumerable is trivial. Simply start at the root node in your list, yield return Node.data;, and move to the next node. Rinse and repeat until the next node is null.
Add a new method to your class.
public class MyLinkedList
{
... keep existing methods here ...
public int[] ToArray() {
var result = new int[count]();
var index = 0;
var node = headnode;
while (node != null) {
result[index] = node.data;
node = node.next;
}
return result;
}
Eh... Something like that?
public class MyLinkedList {
...
public Node[] ToArray() {
// You´ve got pre-computed count - let´s use it
Node[] result = new Node[count];
Node node = headNode;
for (int i = 0; i < result.Length; ++i) {
result[i] = node;
node = node.next;
}
return result;
}
}
P.S. public fields like next in the Node class is a bad practice. Convert them into properties
As #Will suggested, I would implement IEnumerable<int> by your class. That will bring you to powerful world of LINQ where you will be able to convert your linked list to array, list, or just filter nodes:
public class MyLinkedList : IEnumerable<int>
{
// your code here
public IEnumerator<int> GetEnumerator()
{
Node current = headNode;
while(current != null)
{
yield return current.data;
current = current.next;
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Now you can use all LINQ extensions with your class:
MyLinkedList myList = new MyLinkedList();
myList.Add(10);
myList.Add(15);
myList.Add(20);
int[] array = myList.ToArray();
List<int> list = myList.ToList();
// items above 13
var items = myList.Where(i => i > 13);

How do I resolve C# compiler error CS0102 when trying to add an indexer?

So I'm trying to port a java Bag class over to C#. I know I've done it wrong here, because a test of this code in a foreach statement produces only the first two added items, but this is not my primary question.
The compiler throws a CS0102 when I try to add an indexer to the Bag class, complaining that Bag<Item> already contains a definition for Item. But I can create a method public Item Get(int i), which does the very same thing just fine. Why is this happening and how can I create an indexer for this class?
Edit The exact error is: Bag.cs(15,15): Error CS0102: The type Algorithms4e.ch1.Bag<Item>' already contains a definition forItem' (CS0102)
Just as a side note, I know the Bag class is not supposed to use an indexer, but it's the principle of the thing; I should be able to add an indexer to any class right?
I'm running Mono C# compiler version 3.2.8.0 under Ubuntu 14.04.2 LTS, if that helps at all.
Please let me know if y'all need any more information, or if I'm posting this is the right place to begin with. I'd be happy to update the question.
public class Bag<Item> : IEnumerable<Item> {
private int N; // number of elements in bag
private Node<Item> first; // beginning of bag
// helper linked list class
private class Node<T> {
public T item;
public Node<T> next;
}
/**
* Initializes an empty bag.
*/
public Bag() {
first = null;
N = 0;
}
/**
* Is this bag empty?
* #return true if this bag is empty; false otherwise
*/
public bool isEmpty() {
return first == null;
}
/**
* Returns the number of items in this bag.
* #return the number of items in this bag
*/
public int size() {
return N;
}
/**
* Adds the item to this bag.
* #param item the item to add to this bag
*/
public void Add(Item item) {
Node<Item> oldfirst = first;
first = new Node<Item>();
first.item = item;
first.next = oldfirst;
N++;
}
public Item Get(int i)
{
return ((ListIterator<Item>)GetEnumerator ())[i];
}
public Item this[int i]
{
get {
return ((ListIterator<Item>)GetEnumerator ())[i];
}
}
/**
* Returns an iterator that iterates over the items in the bag in arbitrary order.
* #return an iterator that iterates over the items in the bag in arbitrary order
*/
public IEnumerator<Item> GetEnumerator() {
return new ListIterator<Item>(first);
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
// an iterator, doesn't implement remove() since it's optional
private class ListIterator<T> : IEnumerator<T> {
private Node<T> current;
private Node<T> first;
public ListIterator(Node<T> first) {
this.first = first;
current = first;
}
public T GetEnumerator() {
if (!MoveNext ())
throw new Exception ("No such element");
T item = current.item;
//current = current.next;
return item;
}
public T this[int index]
{
get {
Node<T> temp = first;
for (int i = 0; i < index; i++) {
temp = temp.next;
}
return temp.item;
}
}
public T Current
{
get { return current.item; }
}
object IEnumerator.Current
{
get { return Current; }
}
public void Dispose()
{
current = null;
}
public void Reset()
{
current = first;
}
public bool MoveNext()
{
bool res = (current != null);
current = current.next;
return (res);
}
}
}
If you are trying to make it generic why do you have T and Item try making it all T
public class Bag<T> : IEnumerable<T>
I believe this is the problem...
https://msdn.microsoft.com/en-us/library/a82kxee5%28v=vs.90%29.aspx
You're running into this because the default property name for indexers is Item.
If you had followed the naming guidlines for type parameters and named the type parameter TItem (or just T), you wouldn't have run into this issue.
But in case you really need the type parameter to be called Item, you can change the name of the indexer property using the IndexerName attribute:
public class Bag<Item> : IEnumerable<Item>
{
...
[IndexerName("MyIndexer")]
public Item this[int i]
{
get
{
return ((ListIterator<Item>)GetEnumerator ())[i];
}
}
...
}

Implementing IEnumerable to my object [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Implementing C# IEnumerable<T> for a LinkedList class
After searching the web for some hours now I still can't understand how IEnumerable/IEnumerator works and how to implement it.
I've constructed a simple LinkedList from scratch but now I want to implement IEnumerable for it so I can foreach it. How do I do that?
class Program
{
LL myList = new LL();
static void Main()
{
var gogo = new Program();
}
public Program()
{
myList.Add("test");
myList.Add("test1");
foreach (var item in myList) //This doesn't work because I havn't implemented Ienumerable
Console.WriteLine(item);
Console.Read();
}
}
class LL
{
private LLNode first;
public void Add(string s)
{
if (this.first == null)
this.first = new LLNode() { Value = s };
else
{
var node = this.first;
while (node.Next != null)
node = node.Next;
node.Next = new LLNode() { Value = s };
}
}
class LLNode
{
public string Value { get; set; }
public LLNode Next { get; set; }
}
It's really not that hard. To implement IEnumerable you just need to implement the GetEnumerator method.
To do that you need to create another class that implements IEnumerator. Implementing IEnumerator is pretty easy. Generally you will pass a reference to your collection when you create the enumerator (in GetEnumerator) and the enumerator will keep track of which item is the current item. Then it will provide MoveNext which just changes the Current to the next item (and returns false if it's at the end of the list) and Reset which just sets the Current back to before the first node.
So in very broad, untested code terms, you need something like:
public class MyLinkedListEnumerator : IEnumerator
{
private LL myList;
private LLNode current;
public object Current
{
get { return current; }
}
public MyLinkedListEnumerator(LL myList)
{
this.myList = myList;
}
public bool MoveNext()
{
if (current == null) {
current = myList.first;
}
else {
current = current.Next;
}
return current != null;
}
public void Reset()
{
current = null;
}
}
What you need to do is:
(1) Make your class implement IEnumerable<T> where T is the type of the enumerated items. (In your case, it looks like it would be LLNode).
(2) Write a public IEnumerator<T> GetEnumerator. Implement it using the "yield" keyword.
(3) Add a IEnumerator IEnumerable.GetEnumerator() method and just return GetEnumerator().
The following code should make this clear. Where I have <int>, you should put <LLNode>, assuming that is the correct type.
using System;
using System.Collections;
using System.Collections.Generic;
namespace Demo
{
internal class Program
{
private static void Main()
{
var test = new MyDemo();
foreach (int item in test)
{
Console.WriteLine(item);
}
}
}
public class MyDemo: IEnumerable<int>
{
public IEnumerator<int> GetEnumerator()
{
// Your implementation of this method will iterate over your nodes
// and use "yield return" to return each one in turn.
for (int i = 10; i <= 20; ++i)
{
yield return i;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
I would have modified your code to do it properly, but the code you posted won't compile.
[EDIT]
Now you've updated your code, I can see that you want to enumerate the values. Here's the completed code:
using System;
using System.Collections;
using System.Collections.Generic;
namespace Demo
{
internal class Program
{
private LL myList = new LL();
private static void Main()
{
var gogo = new Program();
}
public Program()
{
myList.Add("test");
myList.Add("test1");
foreach (var item in myList) // This now works.
Console.WriteLine(item);
Console.Read();
}
}
internal class LL: IEnumerable<string>
{
private LLNode first;
public void Add(string s)
{
if (this.first == null)
this.first = new LLNode
{
Value = s
};
else
{
var node = this.first;
while (node.Next != null)
node = node.Next;
node.Next = new LLNode
{
Value = s
};
}
}
public IEnumerator<string> GetEnumerator()
{
for (var node = first; node != null; node = node.Next)
{
yield return node.Value;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
private class LLNode
{
public string Value { get; set; }
public LLNode Next { get; set; }
}
}
}

Categories