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;
}
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.
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
In a foreach loop I want to compare an element with the previous element that was read. How can I do that? What is the syntax for addressing a previous element in a foreach loop?
You don't have that option built in with a foreach loop.
You can either switch to a for loop or use a variable.
Suppose you iterate through a list of objects, these are your options:
object prev = null;
foreach(var current in myListOfObjects)
{
if(current == prev)
{
// do stuff
}
// don't forget the next row!
prev = current;
}
or
for(var i = 1; i < myListOfObjects.count, i++) // Note: starting from 1 to avoid another condition inside the loop.
{
if(myListOfObjects[i] == myListOfObjects[i-1])
{
// do stuff
}
}
Everything is better with Bluetooth extension methods:
public static class EnumerableExtensions
{
public struct CurrentAndPrevious<T>
{
public T Current { get; private set; }
public T Previous { get; private set; }
public CurrentAndPrevious(T current, T previous) : this()
{
Previous = previous;
Current = current;
}
}
public static IEnumerable<CurrentAndPrevious<T>> WithPrevious<T>(this IEnumerable<T> enumerable)
{
var previous = default(T);
using(var enumerator = enumerable.GetEnumerator())
{
while(enumerator.MoveNext())
{
yield return new CurrentAndPrevious<T>(enumerator.Current, previous);
previous = enumerator.Current;
}
}
}
}
var items = new[] { 1, 2, 3, 4, 5 };
foreach(var item in items.WithPrevious())
{
Console.WriteLine(item.Previous + " " + item.Current);
}
You might need to tweak this depending on how you want first and last elements handled.
You can loop over a bit modified source instead of initial, say ListOfMyObjects:
MyObject prior = default(MyObject);
var source = ListOfMyObjects
.Select(item => {
var result = new {
Current = item,
Prior = prior,
};
prior = item; // side effect, not a good practice
return result;
});
So you can loop
foreach(var item in source) {
if (item.Prior == item.Current) {
...
}
}
A foreach itself has no syntax 'for addressing a previous element'. There are two options, depending on the characteristics of the collection and also the notion of a 'previous' element in respect of the first one. The following the examples are a little bit simplistic, but you should be able to choose the right path and fine-tune the details.
Option 1: Use a temporary variable
Works well if there's no cheap (performance-wise) way to index elements in the sequence, and you are OK with 'pretending' there's an empty (null, or default(T)) item before the very first item.
T previous = default(T); // corresponds to null for reference types
foreach (T item in sequence)
{
… work with previous and item here…
// the current 'item' is the new 'previous' for the next iteration
previous = item;
}
Note that if T is a value type, your would be actually copying the values themselves.
Option 2: Use a for loop and indexing
Works well if there is a cheap (performance-wise) way to index individual elements directly. List<T> and arrays are good examples here.
// indexing from 1, i.e. from the second item in the sequence
for (int i = 1; i < sequence.Count; i++)
{
var previous = sequence[i-1]; // this is obviously the previous item
var current = sequence[i]; // this is obviously the current item
}
Similar to using a temp variable, however this solution moves the scope of the temp variable inside the loop
var collection = new List<int>() { 1, 2, 3, 4, 5 };
foreach (var item in collection)
{
var currentIndex = collection.IndexOf(item);
if (currentIndex > 0 && currentIndex < collection.Count)
{
var previousItem = collection[currentIndex - 1];
}
}
As mentioned by Pham X, one easy way to do this would be a temp variable.
ObjectType temp_object = null;
foreach(var entry in ListOfObjects)
{
if(temp_object==null)
{
//this is the first time through...
temp_object=entry;
}
else
{
//it's anything after the first loop
if(entry==temp_object) Console.WriteLine("There is a match between two entries.");
else temp_object=entry;
}
}
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 hope I am using the right terminology.
I have made a single-chained list.
class MyStack
{
public Node Initial { get; set; }
public MyStack()
{
Initial = null;
}
public void Push(int data)
{
var node = new Node { Data = data, Next = Initial };
Initial = node;
}
public int Pop()
{
int res = Initial.Data;
Initial = Initial.Next;
return res;
}
public int Sum()
{
int sum = 0;
Node currentNode = Initial;
while (currentNode != null)
{
sum += currentNode.Data;
currentNode = currentNode.Next;
}
return sum;
}
public int Count()
{
int count = 0;
Node currentNode = Initial;
while (currentNode != null)
{
count++;
currentNode = currentNode.Next;
}
return count;
}
public void PrintAll()
{
Node currentNode = Initial;
while(currentNode != null)
{
Console.WriteLine("tmp.Data = " + currentNode.Data);
currentNode = currentNode.Next;
}
}
}
public class Node
{
public int Data;
public Node Next;
}
Meaning you can do something like this:
var s = new MyStack();
s.Push(5);
s.Push(3);
s.Push(7);
s.PrintAll();
Console.WriteLine("Sum: " + s.Sum());
Console.WriteLine("Count: " + s.Count());
Now, I want to try and make a Reverse method. This seems to be working:
public void Reverse()
{
Node predesesor, location;
location = Initial;
predesesor = null;
while(Initial != null)
{
Initial = Initial.Next;
location.Next = predesesor;
predesesor = location;
location = Initial;
}
Initial = predesesor;
}
I am hardly able to see how it works, and it will be tough to maintain.
It seems more like a hack than anything else.
Can you offer any assistance?
It doesn't seem like a hack to me and I don't see what's there to maintain (it is either correct or not, what else would you do with it?). If you want to figure out how it works, "execute" each step on paper. Draw a list (e.g 1 -> 3 -> 5 -> 7 -> 9 -> NULL), mark out where all Nodes point at any time and start "single-stepping".
I couldn't think of a cleaner way to reverse a singly linked list. You need a reference to the next node (Initial at the beginning of the loop), before you can reverse the link between current node and previous node. You just won't be able to move on in the original list otherwise.
What you could do is fix the spelling of the variables and perhaps not use Initial in the loop itself (use a third variable, so the role of each variable is clearer) and only set Initial to the first Node in the reversed list at the end.
So, all in all:
public void Reverse() {
Node current = Initial, previous = null;
while (current) {
Node next = current.Next;
current.Next = previous;
previous = current;
current = next;
}
Initial = previous;
}
One solution would be to turn it into a doubly-linked list, and then work backwards using the previous node property:
public class Node
{
public int Data;
public Node Next;
public Node Previous;
}
There is already a doubly-linked list in the framework if you want to save yourself some effort.
you can do it recursivly:
a->b->c->d
a->null
b->null
c->null
c<-d
b<-c
a<-b
a<-b<-c<-d
public void Reverse()
{
Reverse(Initial);
}
private void Reverse(Node node)
{
if(node != null && node.Next != null)
{
//go deeper
Reverse(node.Next);
//swap
node.Next.Next = node
node.Next = null;
}
}
Instead of reinventing the wheel you should check, if there is already something you can use something from .Net Framework.
For example i would take here the LinkedList with the LinkedListNode. In other cases you could probably take the Queue or a Stack.
If you call it "nreverse" or "reverse in place" then any developer worth tuppence would recognise it as a classic algorithm rather than a hack.
It shouldn't require much maintenance, except maybe renaming any incorrectly spelled variables.
The following code might be a bit more intuitive:
public void Reverse()
{
MyStack reverse = new MyStack();
while (Initial != null)
{
reverse.Push(this.Pop());
}
Initial = reverse.Initial;
}
(Reverse is a member method of the MyStack class).
Of course, it does require twice the space compared with the original code.
stack s1
s1.push_front(...)
...
s1.push_front(...)
////////////////////////////////////////////////////////
void reverse(stack& to,stack_or_list& s )
while(!s.empty()){
to.push_front(s.pop_front());
}
}
now a series of to.pop_fronts gets you what you want
stack_or_list needs: pop_front empty
to needs: push_front,pop_front