So,Im creating an add method for a linked list wich im making from scratch. I want the list to add Items (Nodes with int value) anywhere in the list. Here is my code:
public void Add(int val)
{
Node newNode = new Node();
newNode.value = val;
if (head == null)
{
head = newNode;
current = newNode;
}
if (current.Next == null)
{
current.Next = newNode;
current = newNode;
}
size++;
}
Now, when i tried my program I noticed that I only can add values linear in the list. Am I completely on the wrong side of the train?
For example:
I have 3 elements in my list, 1, 7, 9 and I want to add the item 2 to my list after element 1?
What about
public void Add(int val)
{
Node newNode = new Node();
newNode.value = val;
if (head == null)
{
head = newNode;
current = newNode;
}
else
{
current.Next = newNode;
current = newNode;
}
size++;
}
public void Insert(int index, int val)
{
// COMPLETELY UNTESTED BUT MAY POINT YOU IN THE RIGHT DIRECTION
Node newNode = new Node();
newNode.value = val;
if (head == null) { return; }
Node node = new Node();
if (index == 0){
newNode.Next = head;
head = newNode;
}
node = head;
while(node.Head!=null && index > 1)
{
node = node.Next;
index--;
}
if (node != null && index >= 0){
var next = node.Next;
newNode.Next = next;
node.Next = newNode;
}
size++;
}
What you'll want to do is start at the head of the list, then traverse it till you get to the appropriate spot, then insert it. Something like this:
public void Add(int val)
{
var newNode = new Node();
Node currentNode = head;
int index=0;
while (currentNode != null && index < val)
{
currentNode=currentNode.Next;
index++;
}
newNode.Next = currentNode.Next;
currentNode.Next = newNode;
// If its a doubly linked list, you might need to update .Prev too
}
What this is doing is traversing each node, incrementing an index counter as we do so. When we finally get to the right spot, we are taking the node that the current node points to and having our new node point to it instead. Then we point the current node's Next property to our new node, thus "inserting" our new node after the current node.
Related
I have TreeNode node.
something = treeview.Nodes[1].Nodes[4].Nodes[0];
TreeNode myNode = something;
And wish to know how pany parents it has and what indexes i need to use to find whole path out from this node.
I mean get "treeview.Nodes[1].Nodes[4].Nodes[0]" out from myNode
Something like this should work:
public IList<int> GetNodePathIndexes(TreeNode node)
{
List<int> indexes = new List<int>();
TreeNode currentNode = node;
while (currentNode != null)
{
TreeNode parentNode = currentNode.Parent;
if (parentNode != null)
indexes.Add(parentNode.Nodes.IndexOf(currentNode));
else
indexes.Add(currentNode.TreeView.Nodes.IndexOf(currentNode));
currentNode = parentNode;
}
indexes.Reverse();
return indexes;
}
You can then look at the result of this to get the indexes, and the count, to get the number of parents.
IList<int> path = GetNodePathIndexes(myNode);
StringBuilder fullPath = new StringBuilder("treeview");
foreach (int index in path)
{
fullPath.AppendFormat(".Nodes[{0}]", index);
}
Then fullPath.ToString() should return treeview.Nodes[1].Nodes[4].Nodes[0]
//...
string path = GetPath(treeView1.Nodes[0].Nodes[0].Nodes[1].Nodes[0]);
// now path is "treeView.Nodes[0].Nodes[0].Nodes[1].Nodes[0]"
//...
string GetPath(TreeNode node) {
int index;
Stack<string> stack = new Stack<string>();
while(node != null) {
if(node.Parent != null) {
index = node.Parent.Nodes.IndexOf(node);
stack.Push(string.Format("Nodes[{0}]", index));
}
else {
index = node.TreeView.Nodes.IndexOf(node);
stack.Push(string.Format("treeView.Nodes[{0}]", index));
}
node = node.Parent;
}
return string.Join(".", stack.ToArray());
}
I faced a very weird problem. I can`t insert a node by index into a custom linked list. So here it is my method:
public void Insert(int index, T item)
{
if(item == null)
throw new ArgumentNullException(nameof(item), "Item is equal null.");
if (index > Count || index < 0)
throw new ArgumentOutOfRangeException(nameof(index),"Index out of range.");
Item<T> newNode = new Item<T>(item);
Item<T> currentItem = Head;
if (index == 0)
{
newNode.Next = Head;
return;
}
var x = FindItemByData(this[index]);
while (currentItem.Next != null)
{
if (currentItem.Next == x)
{
currentItem.Next = newNode;
newNode.Next = FindItemByData(this[index]);
}
currentItem = currentItem.Next;
}
}
And there are Item class:
public class Item<T>
{
public T Data { get; set; }
public Item<T> Next { get; set; }
public Item(T data)
{
Data = data;
Next = null;
}
}
Indexator of my linked list returns a data from specify node in the list, so I need to insert a new node to list with data: item. For example: I have a list of items โ ๐งถ ๐ฆ ๐งฅ. And I need to insert on index 1 - element ๐ฆ, result list might be โ ๐ฆ ๐งถ ๐ฆ ๐งฅ.
I tried to show that this problem doesn't simple because I can`t found a solution for insertion by index, there are always only 'Insert before'.
The method that I implemented doesn't work. Hopefully, someone can help me with this.
Also, there the test to this method:
[TestCase(0)]
[TestCase(5)]
[TestCase(2)]
public void Insert_AtPositionValue_ReturnCount(int position)
{
//arrange
CustomList<int> list = new CustomList<int>(1, 2, 7, 8, 10);
//act
int elementToInsert = 100;
list.Insert(position, elementToInsert);
int count = list.Count;
int actualValue = list[position];
//arrange
Assert.Multiple(() =>
{
Assert.AreEqual(elementToInsert, actualValue, message: "Insert or Get Count work incorrectly ");
Assert.AreEqual(6, count, message: "Insert or Get Count work incorrectly ");
});
}
I think you are iterating the list two times, one with FindItemByData and one to recatch the item in the while.
You also forgot to append the rest of the list to the new node.
public void Insert(int index, T item)
{
if(item == null)
throw new ArgumentNullException(nameof(item), "Item is equal null.");
if (index > Count || index < 0)
throw new ArgumentOutOfRangeException(nameof(index),"Index out of range.");
Item<T> newNode = new Item<T>(item);
Item<T> currentItem = Head;
if (index == 0)
{
newNode.Next = Head;
Head = newNode; //you forgot this. You have to reset the head of the list.
return;
}
//delete this <var x = FindItemByData(this[index]);>
for (int i = 0; i<index-1; i++) //if index == 1 I want to add right after head
{
currentItem = currentItem.Next;
}
newNode.Next = currentItem.Next; //append the rest of the list after newNode
currentNode.Next = newNode; //insert new node after the current node
}
Actually the previous author was close. But the error was in passing links to the next element.
public void Insert(int index, T item)
{
if (item == null)
throw new ArgumentNullException(nameof(item), "Item is equal null.");
if (index > Count || index < 0)
throw new ArgumentOutOfRangeException(nameof(index), "Index out of range.");
Item<T> newNode = new Item<T>(item);
Item<T> currentItem = Head;
if (index == 0)
{
newNode.Next = Head;
Head = newNode;
Count++;
return;
}
for (int i = 0; i < index - 1; i++)
{
currentItem = currentItem.Next;
}
newNode.Next = currentItem;
currentItem.Next = newNode;
Count++;
}
I made big research in this forum and found many "solutions" but none of them work.
Maybe my situation is a little bit different and I maybe someone can see where is the problem. I need to delete each Node element which is has "value" less than given(kruvis).
public void Delete()
{
if (Start == null) return;
if (Start.Next == null)
{
Start = null;
return;
}
if (Current.Next == null)
{
Current = null;
}
Node temp = Start;
while (temp.Next.Next != null)
{
if (temp.Next == Current)
{
temp.Next = Current.Next;
Current = temp;
return;
}
temp = temp.Next;
}
}
There is another function(loop in function) in diferent class
for (MenesioAgentai.Pradzia(); MenesioAgentai.ArYra(); MenesioAgentai.Sekantis())
{
if (MenesioAgentai.GautiT().Kruvis <= kruvis)
{
kruvioSuma += MenesioAgentai.GautiT().Kruvis;
PasalintiAgentoPrenumeratorius(pren, MenesioAgentai.GautiT());
MenesioAgentai.Delete();
}
}
The problem is that the first and last element is not deleted
in NodeList class I have 3 nodes Start, End, Current. (and sealed class Node with T data and Node Next)
Deleting node from a linked list is a bit tricky when the head node also needs to be deleted. An easier way is to add a sentinel node at the beginning. The following Java code explains how to delete nodes that have a smaller value than a given value. I used a value of type int for simplicity.
/*
// Node definition
class Node {
Node next;
int val;
Node(int val) {
this.val = val;
}
}
*/
public Node delete(Node head, int k) {
Node sentinel = new Node(Integer.MIN_VALUE);
sentinel.next = head;
Node prev = sentinel, curr = sentinel.next;
while(curr != null) {
while(curr != null && curr.val < k) {
curr = curr.next;
}
prev.next = curr;
prev = curr;
if(curr != null) {
curr = curr.next;
}
}
return sentinel.next;
}
This is my method to simply remove the node indicated, but how can I implement the DeleteBefore() and DeleteAfter() method that removes the node before (after) the node having the given node value.
public void DeleteAFter(T nodeVal)
{
Node<T> curr = front;
Node<T> prev = null;
// becomes true if we locate target
bool foundItem = false;
// scan until locate nodeVal or
// come to end of list
while (curr != null && !foundItem)
{
// have a match
if (curr.NodeValue.Equals(nodeVal))
{
// remove the first node
if (prev == null)
{
front = front.Next;
}
// erase intermediate node
else
{
prev.Next = curr.Next;
}
foundItem = true;
}
else
{
// advanced curr and prev
prev = curr;
curr = curr.Next;
}
I am writing a single linked list in C#, could you please suggest to me if there any way to write a better remove method than the one I have:
using System;
class Node
{
public int data = int.MinValue;
public Node m_NextNode;
public Node(int data_in)
{
data = data_in;
}
public Node()
{
}
}
class LinkedList
{
private Node m_HeadNode;
public void InsertData(int data)
{
Node aCurrentNode = m_HeadNode;
if(m_HeadNode == null)
{
m_HeadNode = new Node();
m_HeadNode.data = data;
}
else
{
while(aCurrentNode.m_NextNode != null)
aCurrentNode = aCurrentNode.m_NextNode;
aCurrentNode.m_NextNode = new Node();
aCurrentNode.m_NextNode.data = data;
}
}
public void DisplayData()
{
Node aCurrentNode = m_HeadNode;
while (aCurrentNode != null)
{
Console.WriteLine("the value is {0}", aCurrentNode.data);
aCurrentNode = aCurrentNode.m_NextNode;
}
}
public void RemoveData(int data)
{
Node aCurrentNode = m_HeadNode;
while (aCurrentNode != null)
{
//if the data is present in head
//remove the head and reset the head
if (m_HeadNode.data == data)
{
m_HeadNode = null;
m_HeadNode = aCurrentNode.m_NextNode;
}
else
{
//else save the previous node
Node previousNode = aCurrentNode;
if (aCurrentNode != null)
{
//store the current node
Node NextNode = aCurrentNode.m_NextNode;
if (NextNode != null)
{
//store the next node
Node tempNode = NextNode.m_NextNode;
if (NextNode.data == data)
{
previousNode.m_NextNode = tempNode;
NextNode = null;
}
}
aCurrentNode = aCurrentNode.m_NextNode;
}
}
}
}
}
class Program
{
static void Main(string[] args)
{
LinkedList aLinkedList = new LinkedList();
aLinkedList.InsertData(10);
aLinkedList.InsertData(20);
aLinkedList.InsertData(30);
aLinkedList.InsertData(40);
aLinkedList.DisplayData();
aLinkedList.RemoveData(10);
aLinkedList.RemoveData(40);
aLinkedList.RemoveData(20);
aLinkedList.RemoveData(30);
aLinkedList.DisplayData();
Console.Read();
}
}
I would pull the 'if removing the head node' out of the while loop, and make the while loop simpler. Just keep track of the current and previous nodes, and switch the reference when you find the node to remove.
public void RemoveData(int data)
{
if (m_HeadNode == null)
return;
if (m_HeadNode.data == data)
{
m_HeadNode = m_HeadNode.m_NextNode;
}
else
{
Node previous = m_HeadNode;
Node current = m_HeadNode.m_NextNode;
while (current != null)
{
if (current.data == data)
{
// If we're removing the last entry in the list, current.Next
// will be null. That's OK, because setting previous.Next to
// null is the proper way to set the end of the list.
previous.m_NextNode = current.m_NextNode;
break;
}
previous = current;
current = current.m_NextNode;
}
}
}
Is RemoveData supposed to remove one instance of that integer from the list, or all instances? The previous method removes just the first one, here's one that removes all of them.
public void RemoveAllData(int data)
{
while (m_HeadNode != null && m_HeadNode.data == data)
{
m_HeadNode = m_HeadNode.m_NextNode;
}
if(m_HeadNode != null)
{
Node previous = m_HeadNode;
Node current = m_HeadNode.m_NextNode;
while (current != null)
{
if (current.data == data)
{
// If we're removing the last entry in the list, current.Next
// will be null. That's OK, because setting previous.Next to
// null is the proper way to set the end of the list.
previous.m_NextNode = current.m_NextNode;
// If we remove the current node, then we don't need to move
// forward in the list. The reference to previous.Next, below,
// will now point one element forward than it did before.
}
else
{
// Only move forward in the list if we actually need to,
// if we didn't remove an item.
previous = current;
}
current = previous.m_NextNode;
}
}
}
You have a line you do not need:
m_HeadNode = null;
m_HeadNode = aCurrentNode.m_NextNode;
You don't need to set m_HeadNode to null before you set it to something else.
public bool RemoveNode(int data) {
Node prev = null;
for (Node node = head; node != null; node = node.next) {
if (node.data == data) {
if (prev == null) head = node.next;
else prev.next = node.next;
return true;
}
prev = node;
}
return false;
}
public void RemoveData(int data)
{
if(null == m_HeadNode) return;
if(m_HeadNode.data == data)
{
// remove first node
}
else
{
Node current = m_HeadNode;
while((null != current.m_NextNode) && (current.m_NextNode.data != data))
current = current.m_NextNode;
if(null != current.m_NextNode)
{
// do remove node (since this sounds like homework, I'll leave that to you)
}
}
}
with only one local variable.
There is a bug in you code, imagine you have list that has 3 elements with data = 5 and you want to remove 5, you codes stores the head in aCurrentNode and starts the loop. There the condition is true so you move the head to the next. but aCurrentNode is not updated so in the next iteration it's pointing to the previous Head and aCurrentNode.m_NextNod would be your current Head, Hence you got yourself in a never ending loop!
public void Remove(int data)
{
for(var cur = new Node {Next = Head}; cur.Next != null; cur = cur.Next)
{
if (cur.Next.Data != data) continue;
if (cur.Next == Head)
Head = Head.Next;
else
cur.Next = cur.Next.Next;
}
}
a trick to make you loop simpler is to start with a fake node that points to head. This way you don't need to place an If to check head differently, however you need an if to set the head. the other trick is to check for next nodes data. that way you don't need to keep a previous Node.
public SLElement Remove(int index)
{
SLElement prev = _root;
if (prev == null) return null;
SLElement curr = _root._next;
for (int i = 1; i < index; i++)
{
if (curr == null) return null;
prev = curr;
curr = curr._next;
}
prev._next = curr._next;
curr._next = null;
return curr;
}
This deletes the element with a specific index, not with a specific value.
To Make really simple. Please follow the link. Below is a code snippet to remove item from a single link list.
public void DeleteNode(int nodeIndex)
{
int indexCounter = 0;
Node TempNode = StartNode;
Node PreviousNode = null;
while (TempNode.AddressHolder != null)
{
if (indexCounter == nodeIndex)
{
PreviousNode.AddressHolder = TempNode.AddressHolder;
break;
}
indexCounter++;
PreviousNode = TempNode;
TempNode = TempNode.AddressHolder;
}
}