I am working on creating my own LinkedList. But I can't seem to solve this error. Can anyone help me!
The problem is that I want to insert an object after a particular element. I have created Find method to search for that particular item and return its reference, but I can't seem to solve it.
CustomLinkedList c = new CustomLinkedList();
c.Add(31);
c.Add(45);
c.Add(23);
c.Add(36);
c.PrintList();
Console.WriteLine("\n" + " Process of adding item at a spectifed location");
c.Addafter(66,23);
c.PrintList();
class Node
{
public object Element;
public Node Link;
public Node()
{
Element = null;
Link = null;
}
public Node(object TheElement)
{
Element = TheElement;
Link = null;
}
class CustomLinkedList
{
protected Node header;
protected Node last;
public CustomLinkedList()
{
//header = new Node("header");
}
private Node Find(object Item)
{
Node Current = new Node();
Current = header;
while (Current.Element != Item && Current.Link !=null)
{
Current = Current.Link;
}
return Current;
}
public void PrintList()
{
Node n = new Node();
n = header;
while (n != null)
{
Console.WriteLine(n.Element);
n = n.Link;
}
}
public void Add(object a)
{
Node n = new Node();
n.Element = a;
n.Link = null;
if (last == null)
{
header = n;
last = n;
}
else
{
last.Link = n;
last = n;
}
}
public void Addafter(object newitem, object After)
{
Node current = new Node();
Node newNode = new Node(newitem);
current = Find(After);
newNode.Link = current.Link;
current.Link = newNode;
}
}
The reason why it doesn't work is on this line:
while (Current.Element != Item && Current.Link !=null)
The == and != operators for the object type check for reference equality. If you're using your list with a value type (int for instance), the values will be boxed to distinct objects, and the != operator will always return true (see this article for details about boxing).
Consider this:
object x = 42;
object y = 42;
Console.WriteLine(x == y); // prints False
Console.WriteLine(x.Equals(y)); // prints True
Your current code is working fine with reference types:
var list = new CustomLinkedList();
list.Add("hello");
list.Add("!");
list.Addafter("world", "hello");
list.PrintList();
Output:
hello
world
!
But for value types it never finds the "after" value, so it appends the new item to the end of the list:
var list = new CustomLinkedList();
list.Add(1);
list.Add(3);
list.Addafter(2, 1);
list.PrintList();
Output:
1
3
2
So you need to replace the == operator with a call to Equals:
while (!object.Equals(Current.Element, Item) && Current.Link !=null)
I don't know what you're using for testing but value types won't work the way you think it should because the box values are being compared.
For example this will always return 3 (last element in list)
CustomLinkedList cList= new CustomLinkedList();
cList.Add(1);
cList.Add(2);
cList.Add(3);
Console.WriteLine(cList.Find(2).Element);
but this will work (output 2)
CustomLinkedList cll = new CustomLinkedList();
object a = 1;
object b = 2;
object c = 3;
cll.Add(a);
cll.Add(b);
cll.Add(c);
Console.WriteLine(cll.Find(b).Element);
The same goes for reference types that don't implement the != operators. So strings will work but little else will
Your code has 2 problems
The Find() function is returning the Tail element when the Item is not in the List.
Comparing n.Element and Item is tricky when they are of type object. Make your classes generic to solve that.
...
class CustomLinkedList<T> where T : IEquatable
{
....
private Node Find(object Item)
{
Node Current = header; // null for empty list
//while (Current.Element != Item && Current.Link !=null)
while(Current != null)
{
if (Current.Equals(Item) ) // can't always use ==
break;
Current = Current.Link;
}
return Current;
}
}
Related
There is a ListGenerator that accepts an array of int and turns it into a recursive object.
public class ListNode
{
public int val;
public ListNode next;
public ListNode(int x) { val = x; }
public ListNode(int val = 0, ListNode next = null)
{
this.val = val;
this.next = next;
}
}
public static ListNode GenerateList(int[] nums)
{
if (nums == null || nums.Length == 0) { return null; }
var i = 0;
var first = new ListNode(nums[i]);
var current = first;
while (++i < nums.Length)
{
current.next = new ListNode(nums[i]);
current = current.next;
}
return first;
}
I know that classes in C# are reference type so after executing this line of code current.next = new ListNode(nums[i]); the value of first variable will change same as current and everything is good.
But after current = current.next; the value of first and current are not same. Actually, the next property has a value in the first but it is null in the current.
I don't understand why that is. In my view, first must be the same as current but it is not.
With var current = first; you copy the reference in first to current. At that point they refer to the same object. Any change in current.next is visible in first.next.
Later you reassign current, so now that is pointing to something other that first. The reference in first in not affected.
So I've said it in the title, I want to delete the biggest value from a LinkedList, can't get my head around how to exactly do it. I tried this but I get an error.
//Remove n from list 'first'
public static void Remove(Node<int> first, Node<int> n)
{
Node<int> pos = first;
while (pos.GetNext() != n)
pos = pos.GetNext();
pos.SetNext(n.GetNext());
}
public static void DeleteMaxValue(Node<int> first)
{
int max = 0;
Node<int> pos = first;
Node<int> maxNode = null;
while(pos.GetNext() != null)
{
if (pos.GetNext().GetValue() > max)
{
maxNode = new Node<int>(pos.GetNext().GetValue());
}
pos = pos.GetNext();
}
Remove(first, maxNode);
}
imagine this is your Node structure in linked list
public class Node
{
public int data;
public Node next;
}
you can use this function to find the biggest number in the linked list and then remove it.
public int GetMax(Node head)
{
int max = int.MinValue();
while(head != null)
{
if(max < head.data)
max = head.data;
head = head.next;
}
return max;
}
Several issues:
max is never updated. It should be updated when you have found a greater value, otherwise the last positive value is considered the greatest.
maxNode is never a node that is in the list, since it is created as a new node. By consequence the Remove function will not find it and nothing gets deleted.
Your function's signature has no way of deleting the first node, since first is passed by value. There is no way to solve this for all cases, unless you change the design:
Either let first be a member of your class, and then don't pass it as argument, or
Let the function return the (potentially) new value of first, so the caller can adapt its own reference to the head of the list.
max = 0 assumes that your list cannot have negative values. In case this is possible, I would suggest initialising max with the value that is in the first node (after having checked that the list is not empty).
Instead of cycling again through the list with Remove, keep a reference to the node the precedes the node that is to be deleted.
Here is a function that returns the value of first, so the caller can make an update to their own reference in case the first node was deleted:
// Return type changed: the function will return the first node
public static Node<int> DeleteMaxValue(Node<int> first)
{
if (first == null) { // In an empty list there is nothing to delete
return;
}
int max = first.GetValue(); // Don't use 0, values might be negative
Node<int> pos = first;
Node<int> maxNode = first;
Node<int> beforeMaxNode = null; // Have a reference that lags behind
while(pos.GetNext() != null)
{
int val = pos.GetNext().GetValue();
if (val > max)
{
max = val; // Update max
beforeMaxNode = pos; // Don't create a new node
}
pos = pos.GetNext();
}
if (beforeMaxNode == null) { // First node has the maximum
// Now `first` reference will change, so it's important to return
// that new reference, else the caller will not see any change
first = maxNode.GetNext();
} else {
beforeMaxNode.SetNext(maxNode.GetNext());
}
return first;
}
Trying to swap the second and third nodes from a doubly linked list in c# with the following method:-
public static void swapNodes(List dblLinkList)
{
Node tempnodeTwo = dblLinkList.firstNode.next; //node two in list
Node tempnodeThree = dblLinkList.firstNode.next.next; //node three in list
Node tempnodeFive = tempnodeTwo.previous;
Node tempnodeSix = tempnodeThree.next;
tempnodeThree.previous = tempnodeFive;
tempnodeThree.next = tempnodeThree;
tempnodeTwo.previous = tempnodeTwo;
tempnodeTwo.next = tempnodeSix;
}
The following shows the output: The first is the original list and the second is the result of the method.
N:19:16 19:16:9 16:9:15 9:15:15 15:15:N
N:19:16 16:16:15 9:15:15 15:15:N
Where am I going wrong?? I have already studied previous questions about this topic which gave me the idea for the code but now stuck!
It seems that you assume tempnodeThree is the third and tempnodeTwo is the second node
of the linked list regardless of the changes you make but this is not the case.
After the initializations what you get is:
tempnodeFive <--> tempnodeTwo <--> tempnodeThree <--> tempnodeSix
And you need is:
tempnodeFive <--> tempnodeThree <--> tempnodeTwo <--> tempnodeSix
So what you have to change from left to right are:
tempNodeFive.next, tempNodeTwo.previous, tempNodeTwo.next, tempNodeThree.previous, tempNodeThree.next, tempNodeSix.previous
Let's go over them following the 2nd linked list representation:
tempNodeFive.next = tempNodeThree;
tempNodeTwo.previous = tempnodeThree;
tempNodeTwo.next = tempnodeSix;
tempNodeThree.previous = tempnodeFive;
tempNodeThree.next = tempnodeTwo;
tempNodeSix.previous = tempnodeTwo;
These six lines are what you need.
PS: You can reconsider variable names for a readable and maintainable code, esp. tempNodeFive and tempnodeSix because five and six does not make any sense as an index and it arises confusion while reading the code.
well here in these lines
tempnodeThree.next = tempnodeThree;
tempnodeTwo.previous = tempnodeTwo;
you are setting the next of a node to itself and the previous of another to itself.
don't you mean
tempnodeThree.next = tempnodeTwo;
tempnodeTwo.previous = tempnodeThree;
I think you would have an easier time if you used better names.
I also would not implement this function like this -- I'd make the function suit it's name like this:
public static void swapNodes(Node a, Node b)
{
if (a == null) return;
if (b == null) return;
Node afterA = a.next;
Node beforeA = a.previous;
a.previous = b.previous;
if (b.previous != null) b.previous.next = a;
a.next = b.next;
if (b.next != null) b.next.previous = a;
b.next = afterA;
if (afterA != null) afterA.previous = b;
b.previous = beforeA;
if (beforeA != null) beforeA.next = b;
}
// call it like this
swapNodes(dblLinkList.firstNode.next, dblLinkList.firstNode.next.next);
Are you sure it's c#? Looks like java. C# has LinkedListNode<T> class, not Node. And LinkedListNode<T> has Next and Previous properties. With capitals. And they are read only.
Any way c# implementation looks like this:
using System;
using System.Collections.Generic;
namespace LinkedListSwap
{
class Program
{
static void Main(string[] args)
{
var list = new LinkedList<string>(new[] { "1st", "2nd", "3rd", "4th", "5th", "6th", "7th" });
Console.WriteLine(list.ToDisplayString());
list.Swap(2, 3);
Console.WriteLine(list.ToDisplayString());
}
}
static class LinkedListExtensions
{
public static void Swap<T>(this LinkedList<T> list, int firstIndex, int secondIndex)
{
if (firstIndex < 1 || firstIndex > list.Count)
throw new IndexOutOfRangeException($"Index out of range: {nameof(firstIndex)}");
if (secondIndex < 1 || secondIndex > list.Count)
throw new IndexOutOfRangeException($"Index out of range: {nameof(secondIndex)}");
if (firstIndex == secondIndex)
return;
if (firstIndex > secondIndex)
(firstIndex, secondIndex) = (secondIndex, firstIndex);
int i = 0;
var leftNode = list.First;
while (++i < firstIndex)
leftNode = leftNode.Next;
var rightNode = leftNode.Next;
while (++i < secondIndex)
rightNode = rightNode.Next;
list.Replace(leftNode, rightNode);
list.Replace(rightNode, leftNode);
}
public static void Replace<T>(this LinkedList<T> list, LinkedListNode<T> oldNode, LinkedListNode<T> newNode)
{
list.AddAfter(oldNode, new LinkedListNode<T>(newNode.Value));
list.Remove(oldNode);
}
public static string ToDisplayString<T>(this LinkedList<T> list) => string.Join(" ", list);
}
}
Output is:
1st 2nd 3rd 4th 5th 6th 7th
1st 3rd 2nd 4th 5th 6th 7th
I've been trying to remove manually entered value from 'Solmu' class after changing it to integer.
private static void PoiataTiettyArvo(ref Solmu lista)
{
Console.WriteLine("Anna arvo jonka haluat poistaa: ");
int PoistaMinut = int.Parse(Console.ReadLine());
int arvo = Convert.ToInt32(lista.data);
if(PoistaMinut != null)
{
arvo.RemoveAt(PoistaMinut);
}
}
My Solmu class is defined like this:
public class Solmu
{
public Solmu next;
public Solmu prev;
public double data;
}
Seems RemoveAt does not work with this, any alternatives?
Based on your comment, this looks like a linked list. You'll have to loop through your values to find the node to delete (this code is untested):
private static void PoiataTiettyArvo(ref Solmu lista)
{
Console.WriteLine("Anna arvo jonka haluat poistaa: ");
int PoistaMinut = int.Parse(Console.ReadLine());
var previousNode = null;
var currentNode = lista;
while (currentNode != null)
{
int arvo = Convert.ToInt32(lista.data);
if (PoistaMinut == arvo)
{
if (previousNode == null)
{
// If there was no previous node, the head of the list is being deleted.
// update lista
lista = currentNode;
}
else
{
previousNode.next = currentNode.next;
if (currentNode.next != null)
{
currentNode.next.prev = previousNode;
}
}
break;
}
previousNode = currentNode;
currentNode = currentNode.next;
}
}
Updated Answer:
Okay, now I understand what you're trying to do. You're going through a linked list to remove an item that matches the item that the user enters.
Option 1) If your Solmu class has an implementation of RemoveAt, you can call it as I posted below - however, RemoveAt methods typically expect an index value, so I would call it Remove (or something more specific like RemoveValue).
Option 2) If your Solmu class is self-created, you will need a loop that starts with the head value and compares the data field to the user-entered value, and remove it.
(Removed my code in favor of Jacob's.)
Original answer:
You're not removing anything from lista. Your code:
int PoistaMinut = int.Parse(Console.ReadLine());
int arvo = Convert.ToInt32(lista.data);
if(PoistaMinut != null)
{
arvo.RemoveAt(PoistaMinut); // <- Remove an int from an int?
}
is trying to remove something from arvo.
You should modify your code to say
lista.RemoveAt(PoistaMinut);
instead.
(In that case, however, I wonder what purpose arvo serves. Can you elaborate?)
I have written a simple method that receives a Generic that I wish to place into an ArrayList using the ArrayList.Add() method. However I have discovered that when I go add a new item with the same type as previous items in the ArrayList this new item overwrites the previous items individual properties.
Here's the code its pretty basic and rather embarrassingly I can't seem to rectify this overwriting problem.
public class ChromosomeTree<T>
{
private GeneNode<T> root;
private ArrayList children = new ArrayList();
private int depMax;
string stemp;
public ChromosomeTree()
{
root = null;
}
public virtual void Clear()
{
root = null;
}
public GeneNode<T> Root
{
get
{
return root;
}
set
{
root = value;
}
}
public int MaxDepth
{
get
{
return depMax;
}
set
{
depMax = value;
}
}
public ArrayList Children
{
get
{
return children;
}
}
public GeneNode<T> lastChild()
{
return (GeneNode<T>)this.Children[this.Children.Count - 1];
}
public void addFull(GeneNode<T> node)
{
//check if the chromosome tree has a root if not add the first node as the chromosomes root
if (this.Root == null)
{
this.Root = node;
children.Add(node);
stemp += " " + node.Value;
}
else
{
for (int i = 0; i <= this.Children.Count - 1; i++)
{
GeneNode<T> parent = (GeneNode<T>)this.Children[i];
//check to ensure maxDepth of chromosome tree is not exceeded
if (parent.Depth != this.MaxDepth)
{
//check to see if the current node stil has room for another node to be added to it
if ((parent.Children == null) || (parent.Children[1] == null))
{
children.Add(node);
parent.Add(node);
stemp += " " + node.Value;
break;
}
}
else
{
break;
}
}
}
}
public override string ToString()
{
string chromosome = String.Empty;
foreach(GeneNode<Gene> gene in this.Children)
{
chromosome += " " + gene.Value.GeneValue.ToString();
}
return chromosome;
}
}
Im pretty sure its a simple mistake but ive looked at this for so long I cant see the wood from the trees. Any thoughts would be greatly appreciated.
Many thanks in advance.
Luke
here is the code that utilises the this class.
EDIT : THE OVERWRITE HAPPENS WHEN THE METHOD IS CALLED NOT AFTER THE METHOD HAS EXECUTED ITS LOGIC
class SimpleChromosome
{
Random rand = new Random();
Gene funcGene = new Gene();
Gene termGene = new Gene();
private string sChromosome;
private int currentdepth;
private string grownChromosome()
{
return sChromosome;
}
public ChromosomeTree<Gene> fullChromosome()
{
ChromosomeTree<Gene> chromosone = new ChromosomeTree<Gene>();
//chromosone.MaxDepth = rand.Next(1, 5);
chromosone.MaxDepth = 1;
int maxGenes = (int)Math.Pow(2, chromosone.MaxDepth + 1) - 1;
for (int i = 0; i <= chromosone.MaxDepth; i++)
{
int numNodesForLevel = (int)Math.Pow(2, i);
int numNodesOnLevel = 0;
for (int j = 0; j < numNodesForLevel; j++)
{
if (currentdepth != chromosone.MaxDepth)
{
funcGene.GenerateValue(GeneType.Function);
GeneNode<Gene> geneNode = new GeneNode<Gene>(funcGene);
sChromosome += " " + geneNode.Value;
chromosone.addFull(geneNode);
numNodesOnLevel++;
}
else
{
termGene.GenerateValue(GeneType.Terminal);
GeneNode<Gene> geneNode = new GeneNode<Gene>(termGene);
sChromosome += " " + geneNode.Value;
chromosone.addFull(geneNode);
numNodesOnLevel++;
}
if ((numNodesForLevel == numNodesOnLevel) && (currentdepth != chromosone.MaxDepth))
{
currentdepth++;
}
}
}
currentdepth = 0;
//Console.WriteLine("Before ADD :" + sChromosome);
sChromosome = "";
return chromosone;
}
}
Post the code where you are adding a new object of this type to your ArrayList.
My guess is that you are using two references to the same object.
Remember that objects are reference types, therefore if you assign them to each other you are only assigning their references. e.g. in the following code:
Foo foo1 = new Foo();
foo1.x = 1;
Foo foo2 = new Foo();
foo2.x = 2;
foo2 = foo1; // foo2 now points to the same object as foo1;
// foo1.x does not get copied into foo2.x.
// You have also lost your reference to the original foo2 object here and it will be garbage collected.
foo2.x = 100;
// since foo2 and foo1 are now pointing to the same object. both foo2.x and foo1.x will be 100
For this sort of relationship you really should be coding to interfaces. eg.
public interface IGeneNode{
//genenode definition including perhaps equality interfaces etc
}
If the above is correct then you can overload your Assignment operator to pass the values you wish to pass.
This might be useful to you as well.
C# - Multiple generic types in one list
in this loop parent == Children[i] and Children is a getter for children
Do you really mean to be adding the same node to children and parent, which would make the same node a sibling of parent in addition to a child? I'm not clear on what you're really trying to do but this seems wrong:
if ((parent.Children == null) || (parent.Children[1] == null))
{
children.Add(node);
parent.Add(node);
..
}
edit
From the supporting code you posted the problem could be related to how you create objects:
/* outside the loop */
Gene funcGene = new Gene();
Gene termGene = new Gene();
...
/* inside the loop*/
funcGene.GenerateValue(GeneType.Function);
GeneNode<Gene> geneNode = new GeneNode<Gene>(funcGene);
sChromosome += " " + geneNode.Value;
chromosone.addFull(geneNode);
Seems like you are create a new GeneNode multiple times using a one of two instances of Gene in its constructor. Assuming that your GeneNode is saving that as a property value, each GeneNode is going to reference the same instance of Gene (well, one of two, either funcGene or termGene). I'm guessing this is what you mean when you say new item with the same type as previous items in the ArrayList this new item overwrites the previous items individual properties. Any changes to a Gene property assigned from the constructor in any node of the same type will refer to the same Gene. Even though you are creating new GeneNodes they are constructed from the same Gene.
So assuming that GeneNode.Value references the Gene that it was constructed with, there can only be two different values returned (corresponding to the the current value of one of the two Gene instances) by any node at any given point in time.
Probably, you want to move the code to create a new Gene inside your loop.