Remove operation in c# linked list - c#

I have a problem concerning c# remove operation in linked list. LinkedListNode<T> is immutable, but Remove(LinkedListNode<T>) is constant time. Why do I have a problem with it? Here is the reason:
Normally, when removing I would write the following code (forget about nulls):
public void Remove(LinkedListNode<T> node)
{
node.Previous.Next = node.Next;
node.Next.Previous = node.Previous;
}
But since LinkedListNode<T> is immutable, this is not an option. How is it done in O(1) time then?

It isn't immutable but those properties are read-only properties:
//Out of LinkListNode<T>:
public LinkedListNode<T> Next {
get { return next == null || next == list.head? null: next;} //No setters
}
public LinkedListNode<T> Previous {
get { return prev == null || this == list.head? null: prev;} //No setters
}
That is why you can't assign them.
Instead of implementing it yourself use LinkedList<T>.Remove() method:
LinkedList<int> list = new LinkedList<int>(new int[] { 1, 2, 3, 4 });
list.Remove(3);
// list: 1,2,4
If you look under Reference Source you will see the implementation as:'
public bool Remove(T value) {
LinkedListNode<T> node = Find(value);
if (node != null) {
InternalRemoveNode(node); // <==============
return true;
}
return false;
}
public void Remove(LinkedListNode<T> node) {
ValidateNode(node);
InternalRemoveNode(node); // <==============
}
internal void InternalRemoveNode(LinkedListNode<T> node) {
Debug.Assert( node.list == this, "Deleting the node from another list!");
Debug.Assert( head != null, "This method shouldn't be called on empty list!");
if ( node.next == node) {
Debug.Assert(count == 1 && head == node, "this should only be true for a list with only one node");
head = null;
}
else {
/******************** Relevant part here *****************/
node.next.prev = node.prev;
node.prev.next = node.next;
if ( head == node) {
head = node.next;
}
}
node.Invalidate();
count--;
version++;
}
So basically they implemented it as you wanted too but they can use different variables which are internal and are not read-only:
internal LinkedListNode<T> next;
internal LinkedListNode<T> prev;

Internally, the method Remove of LinkedList(T) relies on:
internal void InternalRemoveNode(LinkedListNode<T> node)
which itself, in turn, directly manipulates the corresponding backing fields of LinkedListNode(T), both declared with the internal visibility as well :
internal LinkedListNode<T> prev;
and
internal LinkedListNode<T> next;
'Hope this helps,

Related

NullReferenceException when returning an object in C#, without accessing its parameters

I haven't programmed in c# in ages, but I have this task for school, where I am supposed to implement a doubly linked list. I am meant to do this, without using OOP, so it is all written procedural. The issue is, whenever I run the code, during the second insertion, at the end, when it should return the node we inserted the new node after, I get a null refference exception.
The whole message is:
"System.NullReferenceException: 'Object reference not set to an instance of an object.' node was null."
I have no Idea why this is happening, so I thought I'd post the question here. From the debugger, I can clearly see that node is, in fact, not null, and even if it was, I am just returning the object, not accessing it's properties.
Here is my code:
class Program
{
public class LinkedList
{
public int value;
public LinkedList next;
public LinkedList prev;
}
public static LinkedList CreateLinkedList(int value)
{
LinkedList seznam = new LinkedList();
seznam.value = value;
seznam.prev = null;
seznam.next = null;
return seznam;
}
public static LinkedList GetFront(LinkedList node)
{
if (node.prev == null)
{
return node;
}
return GetFront(node.prev);
}
public static LinkedList InsertAfter(LinkedList node, int value)
{
if (node != null)
{
var temp = node.next;
var newNode = CreateLinkedList(value);
newNode.prev = node;
newNode.next = temp;
node.next = newNode;
temp.prev = newNode;
return node;
}
return CreateLinkedList(value);
}
static void Main(string[] args)
{
LinkedList s = null;
s = InsertAfter(s, 5);
s = InsertAfter(s, 7);
}
}
Any Ideas on what I might be doing wrong? Thanks in advance for the tips, and I hope my mistake wasn't too stupid, lol.
sine node.next is null, your temp variable is null too. You have to use ref keyword if you want to assign a temp value a node.next value, after node.next was assigned again
var temp = node.next; // before
ref var temp = ref node.next; //should be

How to search an element in a Linked List? (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);

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 properly return an object that is equal to null? (simplified bst)

I've tried to implement a binary-search-tree(BST) insert using the following method but i really don't get why i get the value instead of the actual "reference" to the node.
I've done other implementations that worked fine but I really want to understand why instead of getting the pointer to let's say node.m_left I get just it's value (null).
How can I get that without resorting to unsafe code ?
The reason i'm choosing this way is because searching and inserting are closely related and i don't want to implement the same thing twice.
public void Add(int value)
{
if (root == null)
{
root = new Node(value);
return;
}
Node parent = null ,
res;
//finding the correct place
res = Find(value, root, ref parent);
if (res == null) //probably redunant
{
//once found create a node and asign it's parent
res = new Node(value);
res.m_parent = parent;
}
//EvaluateAVT(res);
}
private Node Find(int value, Node node, ref Node parent,bool justfind = false)
{
if (node.Data == value && justfind)
{
return node;
}
if (node.Data >= value)
{
if (node.m_left == null)
{
parent = node;
return node.m_left;
}
return Find(value,node.m_left,ref parent ,justfind);
}
else
{
if (node.m_right == null)
{
parent = node;
return node.m_right;
}
return Find(value, node.m_right, ref parent, justfind);
}
}

C# - LinkedList - How to remove all nodes after specified node?

I am implementing an undo/redo buffer with generic LinkedList.
In this state:
[Top]
state4 (undone)
state3 (undone)
state2 <-- current state
state1
[bottom]
When I do a Push, I would like to remove all states after the current one, and push the new one.
My current bypass is to do while (currentState != list.last), list.removeLast(); but it sucks
LinkedList just support Remove, RemoveFirst & removeLast...
I would like something like RemoveAllNodesAfter(LinkedListNode ...) ?
How can I code that nicely, without iterating throught all nodes ? Maybe with extensions ?...
I can't see anything in the standard LinkedList<T> which lets you do this. You could look in PowerCollections and the C5 collections if you want - or just roll your own LinkedList type. It's one of the simpler collections to implement, especially if you can add functionality in a "just in time" manner.
If I were to implement this myself, I would chose a different way to implement this.
Instead of the .RemoveAllNodesAfter(node) method, I would opt to make a .SplitAfter(node) method that returned a new linked list starting with the next node after node. This would make a handier tool than just being able to chop off the tail. If you wanted your RemoveAllNodesAfter method, it would just have to call the SplitAfter method internally and discard the result.
Naive implementation:
public LinkedList<T> SplitAfter(Node node)
{
Node nextNode = node.Next;
// break the chain
node.Next = null;
nextNode.Previous = null;
return new LinkedList<T>(nextNode);
}
public void RemoveAllNodesAfter(Node node)
{
SplitAfter(node);
}
Linked List (especially the singly linked list) is one of the most basic fundamental collection structures. I'm certain that you could probably implement it (and add the behavior your need) with little effort.
In reality, you don't actually need a collection class to manage the list. You could manage the nodes without a collection class.
public class SingleLinkedListNode<T>
{
private readonly T value;
private SingleLinkedListNode<T> next;
public SingleLinkedListNode(T value, SingleLinkedListNode<T> next)
{
this.value = value;
}
public SingleLinkedListNode(T value, SingleLinkedListNode<T> next)
: this(value)
{
this.next = next;
}
public SingleLinkedListNode<T> Next
{
get { return next; }
set { next = value; }
}
public T Value
{
get { return value; }
}
}
If you're interested in a possible implementation, however, here's a somewhat simple SingleLinkedList implementation.
public class SingleLinkedList<T>
{
private SingleLinkedListNode<T> head;
private SingleLinkedListNode<T> tail;
public SingleLinkedListNode<T> Head
{
get { return head; }
set { head = value; }
}
public IEnumerable<SingleLinkedListNode<T>> Nodes
{
get
{
SingleLinkedListNode<T> current = head;
while (current != null)
{
yield return current;
current = current.Next;
}
}
}
public SingleLinkedListNode<T> AddToTail(T value)
{
if (head == null) return createNewHead(value);
if (tail == null) tail = findTail();
SingleLinkedListNode<T> newNode = new SingleLinkedListNode<T>(value, null);
tail.Next = newNode;
return newNode;
}
public SingleLinkedListNode<T> InsertAtHead(T value)
{
if (head == null) return createNewHead(value);
SingleLinkedListNode<T> oldHead = Head;
SingleLinkedListNode<T> newNode = new SingleLinkedListNode<T>(value, oldHead);
head = newNode;
return newNode;
}
public SingleLinkedListNode<T> InsertBefore(T value, SingleLinkedListNode<T> toInsertBefore)
{
if (head == null) throw new InvalidOperationException("you cannot insert on an empty list.");
if (head == toInsertBefore) return InsertAtHead(value);
SingleLinkedListNode<T> nodeBefore = findNodeBefore(toInsertBefore);
SingleLinkedListNode<T> toInsert = new SingleLinkedListNode<T>(value, toInsertBefore);
nodeBefore.Next = toInsert;
return toInsert;
}
public SingleLinkedListNode<T> AppendAfter(T value, SingleLinkedListNode<T> toAppendAfter)
{
SingleLinkedListNode<T> newNode = new SingleLinkedListNode<T>(value, toAppendAfter.Next);
toAppendAfter.Next = newNode;
return newNode;
}
public void TruncateBefore(SingleLinkedListNode<T> toTruncateBefore)
{
if (head == toTruncateBefore)
{
head = null;
tail = null;
return;
}
SingleLinkedListNode<T> nodeBefore = findNodeBefore(toTruncateBefore);
if (nodeBefore != null) nodeBefore.Next = null;
}
public void TruncateAfter(SingleLinkedListNode<T> toTruncateAfter)
{
toTruncateAfter.Next = null;
}
private SingleLinkedListNode<T> createNewHead(T value)
{
SingleLinkedListNode<T> newNode = new SingleLinkedListNode<T>(value, null);
head = newNode;
tail = newNode;
return newNode;
}
private SingleLinkedListNode<T> findTail()
{
if (head == null) return null;
SingleLinkedListNode<T> current = head;
while (current.Next != null)
{
current = current.Next;
}
return current;
}
private SingleLinkedListNode<T> findNodeBefore(SingleLinkedListNode<T> nodeToFindNodeBefore)
{
SingleLinkedListNode<T> current = head;
while (current != null)
{
if (current.Next != null && current.Next == nodeToFindNodeBefore) return current;
current = current.Next;
}
return null;
}
}
Now you can do this:
public static void Main(string[] args)
{
SingleLinkedList<string> list = new SingleLinkedList<string>();
list.InsertAtHead("state4");
list.AddToTail("state3");
list.AddToTail("state2");
list.AddToTail("state1");
SingleLinkedListNode<string> current = null;
foreach (SingleLinkedListNode<string> node in list.Nodes)
{
if (node.Value != "state2") continue;
current = node;
break;
}
if (current != null) list.TruncateAfter(current);
}
The thing is depending on your situation, it's not much better than this:
public static void Main(string[] args)
{
SingleLinkedListNode<string> first =
new SingleLinkedListNode<string>("state4");
first.Next = new SingleLinkedListNode<string>("state3");
SingleLinkedListNode<string> current = first.Next;
current.Next = new SingleLinkedListNode<string>("state2");
current = current.Next;
current.Next = new SingleLinkedListNode<string>("state1");
current = first;
while (current != null)
{
if (current.Value != "state2") continue;
current.Next = null;
current = current.Next;
break;
}
}
This eliminates the need for the collection class altogether.
Alternatively, you can do this:
while (currentNode.Next != null)
list.Remove(currentNode.Next);
Actually, a linked list is a fairly trivial data structure to implement especially in managed code (read: no memory management hassle).
Here's one I hacked up that support just enough functions (read: YAGNI) to support your undo/redo operations:
public class LinkedListNode<T>
{
public LinkedList<T> Parent { get; set; }
public T Value { get; set; }
public LinkedListNode<T> Next { get; set; }
public LinkedListNode<T> Previous { get; set; }
}
public class LinkedList<T> : IEnumerable<T>
{
public LinkedListNode<T> Last { get; private set; }
public LinkedListNode<T> AddLast(T value)
{
Last = (Last == null)
? new LinkedListNode<T> { Previous = null }
: Last.Next = new LinkedListNode<T> { Previous = Last };
Last.Parent = this;
Last.Value = value;
Last.Next = null;
return Last;
}
public void SevereAt(LinkedListNode<T> node)
{
if (node.Parent != this)
throw new ArgumentException("Can't severe node that isn't from the same parent list.");
node.Next.Previous = null;
node.Next = null;
Last = node;
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable<T>)this).GetEnumerator();
}
public IEnumerator<T> GetEnumerator()
{
var walk = Last;
while (walk != null) {
yield return walk.Value;
walk = walk.Previous;
}
}
}
Then you can use the SevereAt method in your code to "cut" the linked list nice and simple.
The first idea that springs to mind is to set Node.Next.Previous = null (if it's a doubly-linked list) and then Node.Next = null .
Unfortunately, because LinkedListNode<T>.Next and LinkedListNode<T>.Previous are read-only properties in the .NET implementation of Linked List, I think you may have to implement your own structure to achieve this functionality.
But as others have said, that should be easy enough. There are plenty of resources you can use as a starting point if you just Google for linked lists C#.
if(this.ptr != null && this.ObjectName != null)
{
LinkedListNode<ObjectType> it = ObjectName.Last;
for (; it != this.ptr; it = it.Previous)
{
this.m_ObjectName.Remove(it);
}
}
this.ptr is of type LinkedListNode<ObjectType> just fyi
this.ptr is a pointer pointing to the node you are currently at, I'm assuming you want to delete everything to the right of it.
Don't make a new copy of your structure, its the worst idea ever. It is a complete memory hog and the structure could be extremely large. Copying the Object is not good programming practice unless its absolutely necessary. Try to do in-place operations.
I've made two extension methods for "removing all nodes before specific node" and "removing all nodes after specific node". However, these extension methods are extensions of LinkedListNode, not LinkedList itself, just for convenience:
public static class Extensions
{
public static void RemoveAllBefore<T>(this LinkedListNode<T> node)
{
while (node.Previous != null) node.List.Remove(node.Previous);
}
public static void RemoveAllAfter<T>(this LinkedListNode<T> node)
{
while (node.Next != null) node.List.Remove(node.Previous);
}
}
Example of use:
void Main()
{
//create linked list and fill it up with some values
LinkedList<int> list = new LinkedList<int>();
for(int i=0;i<10;i++) list.AddLast(i);
//pick some node from the list (here it is node with value 3)
LinkedListNode<int> node = list.First.Next.Next.Next;
//now for the trick
node.RemoveAllBefore();
//or
node.RemoveAllAfter();
}
Well it's not the most effective approach and if you find yourself calling this method on large lists or very often, then other here described approaches are probably more fit (like writing your own linked list class which allows splitting as described in other answers) but if it is just occassional "remove node here and there" than this is simple and quite intuitive.

Categories