Given a:
LinkedList<int> myList;
How would I remove an element at index n? I can't seem to find any methods, only ones to remove by value which is no good as this particular list can have duplicate values.
EG:
myList.removeAt(n);
Linked lists have great advantage in speed if you are adding or removing a node you have a existing reference to, but when you don't have a reference the best you can do is walk the list to the index, grab the node, then delete it.
Here is a extension method that does that process. It returns a reference to the removed node in case you want it later to insert to some other list or you are moving it's position within the list.
public static class ExtensionMethods
{
public static LinkedListNode<T> RemoveAt<T>(this LinkedList<T> list, int index)
{
LinkedListNode<T> currentNode = list.First;
for (int i = 0; i <= index && currentNode != null; i++)
{
if (i != index)
{
currentNode = currentNode.Next;
continue;
}
list.Remove(currentNode);
return currentNode;
}
throw new IndexOutOfRangeException();
}
}
Related
I have such a class for implementation of Sorted Linked List in C#. Now it's not actually sorted, but what changes do I have to make to this method it become one?
class LinkedSortedList<T>
{
public Node<T> Head { get; set; }
public Node<T> Tail { get; set; }
public int Count { get; set; }
public LinkedSortedList()
{
Head = null;
Tail = null;
Count = 0;
}
public LinkedSortedList(T data)
{
CreateList(data);
}
public void AddElement(T data)
{
if (Tail != null)
{
var node = new Node<T>(data);
Tail.Next = node;
Tail = node;
Count++;
}
else
{
CreateList(data);
}
}
public void CreateList(T data)
{
var node = new Node<T>(data);
Head = node;
Tail = node;
Count = 1;
}
I want to modify AddElement function so that the list is and remains sorted. How can I implement this logic?
A key observation you need to make in order to complete the task is that at the beginning of AddElement the list is either empty, or sorted. If the list is empty, your task is trivial; if the list is sorted, you must pick an insertion point for the element being added, and insert the new element there. The list will remain sorted after the insertion, because no other elements would need to be moved.
To find the insertion point, start walking the list from the head until you either (1) find an element that is greater than the one being inserted, or (2) you reach the end of the list. In both cases you simply insert the new element immediately after the last element that you've passed during the traversal, or at the head if the initial element is greater than the one you are inserting.
Currently you're just adding elements to the end of the list. Instead, we want to walk the list and look at each value until we find the correct place to insert the node.
One way to do this is to do the following checks:
Is the Head null? If so, create a new list with this data and we're done.
Is the new node's data less than the Head data? If so, put this node in front of the Head and point the Head to our new node.
Is the new node's data greater than the Tail data? If so, put this node after the Tail and point the Tail to our new node.
Otherwise, create a "current" node that points to the head, compare the data of the current node with our new node, and continue to move through the list by setting "current" to it's Next property until we find the proper place to insert the new node. Then rearrange the Next and Previous properties of the three nodes (the new node, the one before it, and the one after it).
For example:
public void AddElement(T data)
{
if (Head == null)
{
CreateList(data);
}
else
{
var node = new Node<T>(data);
if (node.Data < Head.Data)
{
Head.Previous = node;
node.Next = Head;
Head = node;
}
else if (node.Data > Tail.Data)
{
Tail.Next = node;
node.Previous = Tail;
Tail = node;
}
else
{
var current = Head;
while(node.Data >= current.Data && current.Next != null)
{
current = current.Next;
}
node.Previous = current.Previous;
if (node.Previous != null) node.Previous.Next = node;
current.Previous = node;
node.Next = current;
if (Head == current) Head = node;
Count++;
}
}
}
I have multiple objects(nodes) and each node has a getter and setter for a list named Calea which contains other nodes, also each node has neighbours and they are also nodes . The problem is that list is stacking up and I can't figure out why , it's like a static variable and also I am not using that getter and setter anywhere else.
Here is my code :
private int cost = 10000;
private LinkedList<GraphNode<string>> calea=new LinkedList<GraphNode<string>>() ;
public int Cost
{
get
{
return cost;
}
set
{
cost = value;
}
}
public LinkedList<GraphNode<string>> Calea
{
get
{
if (calea == null) return new LinkedList<GraphNode<string>>();
return calea;
}
set
{
calea = value;
}
}
Code above shows the method for Cost and Calea , Cost works fine but Calea is stacking up.The code below is a sample of code of how I am setting the value Calea for each node:
if (curr.Neighbors.ElementAt(i).Cost > curr.Costs.ElementAt(i) + curr.Cost)
{
curr.Neighbors.ElementAt(i).Cost = curr.Costs.ElementAt(i) + curr.Cost;
curr.Neighbors.ElementAt(i).Calea = curr.Calea;
curr.Neighbors.ElementAt(i).Calea.AddLast((GraphNode<string>)curr.Neighbors.ElementAt(i));
index = i;
}
++i;
The sample code where I change the current node below:
pathNodesToVisit.Remove(curr);
if (pathNodesToVisit.Count == 0) break;
if (curr.Neighbors.Count > index)
{
for (int j = 0; j < pathNodesToVisit.Count; j++)
{
if (pathNodesToVisit.ElementAt(j).Value == curr.Neighbors.ElementAt(index).Value)
{
indexx = j;
//MessageBox.Show(pathNodesToVisit.ElementAt(j).Value);
}
}
curr = pathNodesToVisit.ElementAt(indexx);
}
else
{
curr = pathNodesToVisit.ElementAt(0);
}
A few words : pathNodesToVisit are all the nods which I want to visit(Dijkstra algorithm) , in the code above I remove the curr node from the list and the new curr node is a node which had the Costs and Calea changed.
I have no idea what you mean by "stacking up," but:
public LinkedList<GraphNode<string>> Calea
{
get
{
if (calea == null) return new LinkedList<GraphNode<string>>();
return calea;
}
... creates a new list every time the property is read, not just the first time. calea will always be null with this approach.
Try
get
{
if (null == calea)
calea = new LinkedList<GraphNode<string>>();
return calea;
}
Update
The line
curr.Neighbors.ElementAt(i).Calea = curr.Calea;
Does not make a copy of the list. It copies a reference to the list. Any changes made to any node's calea afterward will affect every node, not just the one you're after.
Try
curr.Neighbors.ElementAt(i).Calea = new LinkedList<GraphNode<string>>(curr.Calea);
Though, you should make sure .Neighbors actually has an element i before doing this, among other things.
Note: In the case of an uninitialized node, this will actually create two lists - once when Calea is read (LH of the expression, which calls your .get), and another on the right.
There are many ways to copy a collection. I suggest googling c# deep copy LinkedList<T>.
I am trying to implement Insertion Sort using C# in the code below. But its giving me the error that:
The LinkedList node already belongs to a LinkedList
public void Sort(ref LinkedList<int> list)
{
LinkedListNode<int> tempNode = new LinkedListNode<int>(0); //Contains zero just for initalization
for(tempNode = list.First; tempNode!=null; tempNode=tempNode.Next)
{
LinkedListNode<int> sortedListBoundary = tempNode; //Contains zero just for initalization
while (sortedListBoundary.Value < sortedListBoundary.Next.Value && sortedListBoundary.Previous!=null)
{
sortedListBoundary = sortedListBoundary.Previous;
}
list.AddAfter(tempNode, sortedListBoundary); //This line gives error
}
}
I have even tried to take that node in a temp. Delete the existing node (sortedListBoundary) and then call AddAfter(), but this time error is:
Node doesn't belong to LinkedList()
So how can I overcome this deadlock? Thanks in advance
AddAfter(node, newNode) requires 2 things, node has to belong to the list, and newNode cannot belong to a list, this is all well and good, and removing sortedListBoundary and adding it after tempNode should have worked if not for the following:
You initialize (in the for loop) tempNode = list.First and then LinkedListNode<int> sortedListBoundary = tempNode; so now sortedListBoundary = tempNode = list.First and sortedListBoundary.Previous == null because it is first, so you do not enter the if. And so, when you get to AddAfter part, sortedListBoundary = tempNode... you are trying to add a node after itself...
Edit:
Just to clarify, when you remove sortedListBoundary, because sortedListBoundary = tempNode you are also removing tempNode (as they are the same) therefor, you get the error that it is not in the list... you can't add something after something that is not in the list.
Edit 2:
You ask for a solution, the best answer I can give is to not try to place a node after itself, go over the insertion sort algorithm carefully and see where you deviate from it, here is an implementation of insertion sort:
public void Sort(ref LinkedList<int> list)
{
LinkedListNode<int> tempNode;
for(tempNode = list.First.Next; tempNode!=null; tempNode=tempNode.Next)
{
LinkedListNode<int> sortedListBoundary = tempNode.Previous;
list.Remove(tempNode);
while (sortedListBoundary != null && tempNode.Value < sortedListBoundary.Value)
{
sortedListBoundary = sortedListBoundary.Previous;
}
if(sortedListBoundary == null)
list.AddFirst(tempNode);
else
list.AddAfter(sortedListBoundary, tempNode);
}
}
It is the closest I could make it to your code, but I don't know what you where going for.
LinkedListNode<int> sortedListBoundary is of type LinkedListNode and tempNode is also of type LinkedListNode<int> LinkedList says:
public LinkedListNode<T> AddAfter(
LinkedListNode<T> node,
T value
)
I want to add an element to a linked list so that the list remains sorted. I wrote this function. He's got a place that should be included, but I do not know how to insert the element.
public void AddSorted(int num)
{
Node n = new Node(num);
Node curr = _first;
Node curr1 = _first.Link;
while (curr1.Data < n.Data && curr1 != null)
{
curr = curr.link;
curr1= curr1.link;
}
// how to add element ???
}
You have provided absolutely no context regarding your LinkedList class, so I can only make an educated guess.
Given what I understand from the above code, after traversing to the location you want to insert the new Node, you will need to set the link of Node curr1 (which is the last Node) to the new node object.
Node temp = curr1.Link; // store next Node in temporary object
curr1.Link = n; // Insert new Node
Remember that you need to set the link of the new node to the next node in the LinkedList in order to continue the LinkedList (if the newly inserted Node is not the last):
n.Link = temp;
Please let me know if I made a mistake understanding your code, I can then change my answer accordingly.
With the help of my dear friends.
I could write this function.
Below you can see the code :
public void AddSorted(int num)
{
Node n = new Node(num);
Node curr = _first;
if (_first == null || _first.Data >= n.Data)
{
n.Link = _first;
_first = n;
}
else
{
while (curr.Link != null && curr.Link.Data < n.Data)
{
curr = curr.Link;
}
n.Link = curr.Link;
curr.Link = n;
}
I have 2 millions items in a SortedDictionary<string, MyClass>
I've done the following and takes ages, any ideas?
for(int i = 0; i<dic.Count-1; i++)
{
Debug.WriteLine(dic.ElementAt(i).Value.ToString());
}
The SortedDictionary<TKey, TValue> class does not directly support (fast) retrieval by index; it is internally implemented as a binary search tree. Consequently, every call to the LINQ Enumerable.ElementAt method you've got there creates a new enumerator that iterates each value of the sequence represented by the key-value pairs in the collection (sorted by key) from the beginning until it reaches the desired index. This means that the loop is going to have to pull something like 1 + 2 + 3 + ... + Count (roughly 2 trillion) elements before it completes, making it (atleast) quadratic in its time-complexity.
Try this instead, which should run in roughly linear time:
foreach(var myClass in dic.Values)
Debug.WriteLine(myClass);
If you really do want fast access by index (from the provided code, there doesn't seem to be any reason to indicate this), consider using a SortedList<TKey, TValue> instead. There are downsides to this choice (slower non-appending inserts and deletes) that you should evaluate.
I also notice that the loop condition is i < dic.Count - 1 rather than the more common i < dic.Count. This is either an off-by-one bug, or perhaps you intend to not consider the last value in the dictionary. In the latter case, you could maintain a local variable serving as a counter, or with LINQ:
foreach(var myClass in dic.Values.Take(dic.Count - 1))
Debug.WriteLine(myClass);
foreach might be faster, since you don't use the indexer
foreach (var value in dic.Values)
Debug.Writeline(value)
Also, as far as speed is concerned, Debug.Writeline is probably not the best option (what are you going to do with 2 million debug trace entries anyway??). Consider writing to a file, a database, etc.
EDIT Looking at reflector, finding a value in a SortedDictionry boils down to a binary search:
internal virtual Node<T> FindNode(T item)
{
int num;
for (Node<T> node = this.root; node != null; node = (num < 0) ? node.Left : node.Right)
{
num = this.comparer.Compare(item, node.Item);
if (num == 0)
{
return node;
}
}
return null;
}
The implementation of SortedDictionary's iteration seems a bit more involved:
public bool MoveNext()
{
this.tree.VersionCheck();
if (this.version != this.tree.version)
{
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
}
if (this.stack.Count == 0)
{
this.current = null;
return false;
}
this.current = this.stack.Pop();
SortedSet<T>.Node item = this.reverse ? this.current.Left : this.current.Right;
SortedSet<T>.Node node2 = null;
SortedSet<T>.Node node3 = null;
while (item != null)
{
node2 = this.reverse ? item.Right : item.Left;
node3 = this.reverse ? item.Left : item.Right;
if (this.tree.IsWithinRange(item.Item))
{
this.stack.Push(item);
item = node2;
}
else
{
if ((node3 == null) || !this.tree.IsWithinRange(node3.Item))
{
item = node2;
continue;
}
item = node3;
}
}
return true;
}
It seems to maintain a stack whose top element is the smallest (or largest, depending on the direction) one, and thus always the one to be popped and returned during iteration. I haven't done any complexity analysis, but it's bound to be considerably more efficient than running a binary search each time.
Use foreach:
foreach (var pair in d)
Debug.WriteLine(pair.Value);
I bet that debug output takes more time than dictionary lookup though.