How to push 0 item to the stack of int? - c#

I have a simple stack implementation. But I cant realize how programmer solve the following problem: It is not possible to push a 0 to the stack. How to do that? I mean how to track is it a 0 value or just end of the stack? Or its not a problem in my implementation?
public class Stack: IStack
{
private int[] s;
private int N = 0;
public Stack(int N)
{
s = new int[N];
}
public void push(int x)
{
s[N++] = x;
if (N >= s.Length)
{
Array.Resize(ref s, s.Length*2);
}
}
public int pop()
{
s[N] = 0;
return s[--N];
}
}

You are already tracking the last element of the stack with N (or rather, N - 1). You don't need to verify whether the element is 0, and your implementation actually doesn't distinguish between zeroes and other numbers.
In the implementation you provided, it is perfectly possible to push a 0 into the stack.
By the way, I would reimplement your pop() method like this:
public int? pop()
{
if (N != 0)
{
return s[--N];
}
else
{
return null;
}
}
This way, it returns null in case the stack is empty.

You should realize that it doesn't matter what the values S[N], S[N+1], ... are since you are only using the values S[0..N-1] for your implementation. You consider the part S[N...] as uninitialized and adding a new element, even 0, causes S[N] to become initialized as the new value.

You can push 0 nothing prevents it. N is equal to number of elements, it's also used to track index of next item to push N == (index of last element + 1). The problem i see is that if you run pop() too many times you will get IndexOutOfRangeException.
You can add IsEmpty property like this:
public bool IsEmpty
{
get { return N < 1; }
}

Related

SortedSet with element duplication - can't remove element

I'm working on an implementation of the A-star algorithm in C# in Unity.
I need to evaluate a collection of Node :
class Node
{
public Cell cell;
public Node previous;
public int f;
public int h;
public Node(Cell cell, Node previous = null, int f = 0, int h = 0)
{
this.cell = cell;
this.previous = previous;
this.f = f;
this.h = h;
}
}
I have a SortedSet which allows me to store several Node, sorted by h property. Though, I need to be able to store two nodes with the same h property. So I've implemented a specific IComparer, in a way that allow me sorting by h property, and triggerring equality only when two nodes are representing the exact same cell.
class ByHCost : IComparer<Node>
{
public int Compare(Node n1, Node n2)
{
int result = n1.h.CompareTo(n2.h);
result = (result == 0) ? 1 : result;
result = (n1.cell == n2.cell) ? 0 : result;
return result;
}
}
My problem : I have a hard time to remove things from my SortedSet (I named it openSet).Here is an example:
At some point in the algorithm, I need to remove a node from the list based on some criteria (NB: I use isCell127 variable to focus my debug on an unique cell)
int removedNodesNb = openSet.RemoveWhere((Node n) => {
bool isSame = n.cell == candidateNode.cell;
bool hasWorseCost = n.f > candidateNode.f;
if(isCell127)
{
Debug.Log(isSame && hasWorseCost); // the predicate match exactly one time and debug.log return true
}
return isSame && hasWorseCost;
});
if(isCell127)
{
Debug.Log($"removed {removedNodesNb}"); // 0 nodes where removed
}
Here, the removeWhere method seems to find a match, but doesn't remove the node.
I tried another way :
Node worseNode = openSet.SingleOrDefault(n => {
bool isSame = n.cell == candidateNode.cell;
bool hasWorseCost = n.f > candidateNode.f;
return isSame && hasWorseCost;
});
if(isCell127)
{
Debug.Log($"does worseNode exists ? {worseNode != null}"); // Debug returns true, it does exist.
}
if(worseNode != null)
{
if(isCell127)
{
Debug.Log($"openSet length {openSet.Count}"); // 10
}
openSet.Remove(worseNode);
if(isCell127)
{
Debug.Log($"openSet length {openSet.Count}"); // 10 - It should have been 9.
}
}
I think the problem is related to my pretty unusual IComparer, but I can't figure whats exatcly the problem.
Also, I would like to know if there is a significative performance improvment about using an auto SortedSet instead of a manually sorted List, especially in the A-star algorithm use case.
If i write your test you do:
n1.h < n2.h
n1.cell = n2.cell -> final result = 0
n1.h > n2.h
n1.cell = n2.cell -> final result = 0
n1.h = n2.h
n1.cell != n2.cell -> final result = 1
n1.h < n2.h
n1.cell != n2.cell -> final result = -1
n1.h > n2.h
n1.cell != n2.cell -> final result = 1
when you have equality on h value (test number 3) you choose to have always the same result -> 1. so its no good you have to have another test on cell to clarify the position bacause there is a confusion with other test which gives the same result (test number 5)
So i could test with sample, but i am pretty sure you break the Sort.
So if you clarify the test, i suggest you to use Linq with a list...its best performance.
I'll answer my own topic because I've a pretty complete one.
Comparison
The comparison of the IComparer interface needs to follow some rules. Like #frenchy said, my own comparison was broken. Here are math fundamentals of a comparison I totally forgot (I found them here):
1) A.CompareTo(A) must return zero.
2) If A.CompareTo(B) returns zero, then B.CompareTo(A) must return zero.
3) If A.CompareTo(B) returns zero and B.CompareTo(C) returns zero, then A.CompareTo(C) must return zero.
4) If A.CompareTo(B) returns a value other than zero, then B.CompareTo(A) must return a value of the opposite sign.
5) If A.CompareTo(B) returns a value x not equal to zero, and B.CompareTo(C) returns a value y of the same sign as x, then A.CompareTo(C) must return a value of the same sign as x and y.
6) By definition, any object compares greater than (or follows) null, and two null references compare equal to each other.
In my case, rule 4) - symetry - was broken.
I needed to store multiple node with the same h property, but also to sort by that h property. So, I needed to avoid equality when h property are the same.
What I decided to do, instead of a default value when h comparison lead to 0 (which broke 4th rule), is refine the comparison in a way that never lead to 0 with a unique value foreach node instance. Well, this implementation is probably not the best, maybe there is something better to do for a unique value, but here is what I did.
private class Node
{
private static int globalIncrement = 0;
public Cell cell;
public Node previous;
public int f;
public int h;
public int uid;
public Node(Cell cell, Node previous = null, int f = 0, int h = 0)
{
Node.globalIncrement++;
this.cell = cell;
this.previous = previous;
this.f = f;
this.h = h;
this.uid = Node.globalIncrement;
}
}
private class ByHCost : IComparer<Node>
{
public int Compare(Node n1, Node n2)
{
if(n1.cell == n2.cell)
{
return 0;
}
int result = n1.h.CompareTo(n2.h);
result = (result == 0) ? n1.uid.CompareTo(n2.uid) : result; // Here is the additional comparison which never lead to 0. Depending on use case and number of object, it would be better to use another system of unique values.
return result;
}
}
RemoveWhere method
RemoveWhere use a predicate to look into the collection so I didn't think it cares about comparison. But RemoveWhere use internally Remove method, which do care about the comparison. So, even if the RemoveWhere have found one element, if your comparison is inconstent, it will silently pass its way. That's a pretty weird implementation, no ?

How to modify loop into recursion if we need to use index as a condition?

Let's say we want to implement a sum algorithm I use C# as an illustration here:
// Iterative
int sum(int[] array) {
int result = 0;
foreach(int item in array) {
result += item;
}
return item;
}
which is equivalent to
// Recursive
int sum(int[] array) {
if(array.Length == 0) {
return 0;
}
// suppose there is a SubArray function here
return array[0] + sum(array.SubArray(1));
}
However, if we want to add a condition to the algorithm where we don't want to add the integer at index 2 to our result, we only need to add one conditional statement to our first (iterative) implementation.
Q: Is there any adaptation to our recursive one to make it work?
The recursive version is inefficient due to the repeated SubArray calls, making the time complexity O(n2). You can re-write this function to accept an additional index parameter, which also happens to be how you can implement skipping a particular index (or set of indices, if you choose).
In C#:
private static int SumSkipIndex(int[] arr, int skip, int i)
{
if (i >= arr.Length) return 0;
return (i == skip ? 0 : arr[i]) + SumSkipIndex(arr, skip, i + 1);
}
If you don't like the added i parameter which changes the function header, just write a separate private recursive "helper" function that can be called from the wrapper with your preferred header.
I'm also assuming you don't wish to hardcode index 2 into the algorithm (if you do, remove the skip parameter and replace i == skip with i == 2).
using System;
class MainClass
{
private static int SumSkipIndex(int[] arr, int skip, int i)
{
if (i >= arr.Length) return 0;
return (i == skip ? 0 : arr[i]) + SumSkipIndex(arr, skip, i + 1);
}
public static int SumSkipIndex(int[] arr, int skip)
{
return SumSkipIndex(arr, skip, 0);
}
public static void Main(string[] args)
{
Console.WriteLine(SumSkipIndex(new int[]{16, 11, 23, 3}, 1)); // => 42
}
}
Lastly, bear in mind that recursion is a terrible choice for this sort of algorithm (summing an array), even with the index version. We have to call a new function just to handle one number, meaning we have a lot of call overhead (allocating stack frames) and can easily blow the stack if the list is too long. But I'm assuming this is just a learning exercise.
A consise solution can be done in C# 8 using array slices.
public static int SumArray(int[] arr, int exclude){
if(arr.Length == 0){
return 0;
}
return (exclude==0?0:arr[0]) + SumArray(arr[1..], exclude-1);
}
The ternary operator checks if the skip index is 0, and if it isn't it will decrement the skip index for the next recursive call. The array is reduced using the slice, which should be more performant than SubArray. (Someone fact check me on the latter)
EDIT: As the other answer has suggested, this causes a bloating of stack frames due to a lack of tail call recursion. The below solution would mitigate the issue by using tail call optimisation, adding the sum variable to the function instead. This means the recursive call can use the same stack frame rather than creating a new one to await the return value before completing the sum.
public static int SumArray(int[] arr, int exclude, int sum=0){
if(arr.Length == 0){
return sum;
}
return SumArray(arr[1..], exclude-1, sum + (exclude==0?0: arr[0]));
}

Implementing Custom Int+Range List Solution

I'm wondering if anyone can come up with a way to implement an array of numbers in a more memory efficient manner that will auto-organise itself into ranges. Example;
List testList = new List{1,2,3,4,5,6,7...};
vs
List<Range> testList = new List<Range>{1-3000,3002,4000-5000...};
Previously, I have asked a question just to confirm about whether or not this would in fact be a more memory efficient alternative. This question however pertains to actual application, how to implement this range list solution.
Index Array Storage Memory
I imagine this would perhaps need to be a custom list solution that would be a mix of ints and ranges. I'm picturing being able to .Add([int]) to the list, at which point it would determine if the value would cause a range to be added or to simply add the int value to the list.
Example
RangeList rangeList = new RangeList{1, 4, 7-9};
rangeList.Add(2);
//rangeList -> 1-2, 4, 7-9
rangeList.Add(3);
//rangeList -> 1-3, 4, 7-9
Details specific to my implementation
In my particular case, I'm analysing a very large document, line by line. Lines that meet a certain criteria need to be identified and then the overall list of line indexes need to be presented to the user.
Obviously displaying "Lines 33-32019 identified" is preferable to "Lines 33,34,35...etc". For this case, numbers will always be positive.
The first thing I would do is make a class which represents your range. You can provide some convenience like formatting as a string, and having an implicit cast from an int (This helps later implementation of the range list)
public class Range
{
public int Start{get; private set;}
public int End{get; private set;}
public Range(int startEnd) : this(startEnd,startEnd)
{
}
public Range(int start, int end)
{
this.Start = start;
this.End = end;
}
public static implicit operator Range(int i)
{
return new Range(i);
}
public override string ToString()
{
if(Start == End)
return Start.ToString();
return String.Format("{0}-{1}",Start,End);
}
}
You can then begin a simple implementation of the RangeList. By providing an Add method you can use a list initializer similar to List<T>:
public class RangeList : IEnumerable<Range>
{
private List<Range> ranges = new List<Range>();
public void Add(Range range)
{
this.ranges.Add(range);
}
public IEnumerator<Range> GetEnumerator()
{
return this.ranges.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator(){
return this.GetEnumerator();
}
}
At this point you can write some test code:
var rangeList = new RangeList(){
new Range(1,10),
15
};
foreach(var range in rangeList)
Console.WriteLine(range);
// Outputs:
// 1-10
// 15
Live example at this point: http://rextester.com/NCZSA71850
The next thing to do is provide an overload of Add which takes an int and finds the right range or adds a new one. A naive implemntation might look like the below (Assuming the addition of an Update method on range)
public void Add(int i)
{
// is it within or contiguous to an existing range
foreach(var range in ranges)
{
if(i>=range.Start && i<=range.End)
return; // already in a range
if(i == range.Start-1)
{
range.Update(i,range.End);
return;
}
if(i == range.End + 1)
{
range.Update(range.Start,i);
return;
}
}
// not in any ranges
ranges.Add(i);
}
Live example at this point: http://rextester.com/CHX64125
However this suffers from a few deficiencies
Does not merge ranges (say you already have 1-10 and 12-20 and you Add(11))
Does not re-order so if you have 1-5 and 20-25 and Add(7) this will be at the end not in the middle.
You can solve both problems by applying a sort after each addition, and some logic to determine if you should merge ranges
private void SortAndMerge()
{
ranges.Sort((a,b) => a.Start - b.Start);
var i = ranges.Count-1;
do
{
var start = ranges[i].Start;
var end = ranges[i-1].End;
if(end == start-1)
{
// merge and remove
ranges[i-1].Update(ranges[i-1].Start,ranges[i].End);
ranges.RemoveAt(i);
}
} while(i-- >1);
}
This needs to be called after every change to the list.
public void Add(Range range)
{
this.ranges.Add(range);
SortAndMerge();
}
public void Add(int value)
{
// is it within or contiguous to an existing range
foreach(var range in ranges)
{
if(value>=range.Start && value<=range.End)
return; // already in a range
if(value == range.Start-1)
{
range.Update(value,range.End);
SortAndMerge();
return;
}
if(value == range.End + 1)
{
range.Update(range.Start,value);
SortAndMerge();
return;
}
}
// not in any ranges
ranges.Add(value);
SortAndMerge();
}
Live example here: http://rextester.com/SYLARF47057
There are still some possible edge cases with this, which I urge you to work through.
UPDATE
The below will get this working as expected. This will merge up any added ranges/ints as you would expect and returns them correctly sorted. I've only changed the Add(Range) method, I think this is a fairly clean way of doing this.
public void Add(Range rangeToAdd)
{
var mergableRange = new List<Range>();
foreach (var range in ranges)
{
if (rangeToAdd.Start == range.Start && rangeToAdd.End == range.End)
return; // already exists
if (mergableRange.Any())
{
if (rangeToAdd.End >= range.Start - 1)
{
mergableRange.Add(range);
continue;
}
}
else
{
if (rangeToAdd.Start >= range.Start - 1
&& rangeToAdd.Start <= range.End + 1)
{
mergableRange.Add(range);
continue;
}
if (range.Start >= rangeToAdd.Start
&& range.End <= rangeToAdd.End)
{
mergableRange.Add(range);
continue;
}
}
}
if (!mergableRange.Any()) //Standalone range
{
ranges.Add(rangeToAdd);
}
else //merge overlapping ranges
{
mergableRange.Add(rangeToAdd);
var min = mergableRange.Min(x => x.Start);
var max = mergableRange.Max(x => x.End);
foreach (var range in mergableRange) ranges.Remove(range);
ranges.Add(new Range(min, max));
}
SortAndMerge();
}
Finally, we need if (ranges.Count > 1) in the SortAndMerge() method to prevent an index error when the first range is added.
And with that, I think this fully satisfies my question.

How would I return the lowest value from the list without using shortcuts?

I was given a list of numbers, { 1, 2, 3, 4, 5, 6, 7 }. I was asked to return the lowest value without using shortcuts, e.g. .Min() etc.
I am not going to give you the answer to your homework question for you directly, however to get you started just loop over the list and keep track of the smallest one you found. When you are done the smallest you found is the smallest in the list.
For your second part, it is just basic problem solving. Look at the problem, break it into smaller pieces. For example, for your problem you could break it in to:
How do I loop over a list
How do I remember a value between loops
How do i compare if the remembered value is smaller than the current loop value
How do I replace my remembered value if the current loop value is smaller
Then solve each piece individually.
You can do this in old-fashion imperative way. Works with all comparable types:
public static class MyEnumerableExtensions
{
public static T Min<T>(this IEnumerable<T> list) where T : IComparable<T>
{
if (list == null)
{
throw new ArgumentNullException("list");
}
T min = default (T);
bool initialized = false;
foreach (T elem in list)
{
if (!initialized)
{
min = elem;
initialized = true;
}
else if (min == null) // Do not compare with null, reset min
{
min = elem;
}
else if (elem != null && min.CompareTo(elem) > 0) // Compare only when elem is not null
{
min = elem;
}
}
if (!initialized)
{
throw new InvalidOperationException("list is empty");
}
return min;
}
}
Usage:
var min1 = list.Min();
var min2 = MyEnumerableExtensions.Min(list);
Also, is only Min method is restricted from Linq, additional tricks are possible. Works for numbers only:
var minViaMax = -list.Select(x => -x).Max();
var minViaAggregate = list.Aggregate(Math.Min);

C# Add value to array through user input

I want to add elements to my array through a user input.
I know this can be done very easy using a list but i have to use an array.
The problem with the code is that the array.lenght will always be 1.
I want the array to have the same size as the total amount of elements in it, so
size of the array shouldnt be set when declaring the array.
I thought that if you add an element to an array it will copy the previous values + the added value and create a new array.
UPDATED WITH ANSWER
public static void Add(int x){
if (Item == null) // First time need to initialize your variable
{
Item = new int[1];
}
else
{
Array.Resize<int>(ref Item, Item.Length + 1);
}
Item[Item.Length-1] = x; //fixed Item.Length -> Item.Length-1
}
Use List<int> instead of an explicit array, which will dynamically size for you, and use the Add() method to add elements at the end.
I didn't test in VS. Here you go:
namespace ConsoleApplication1
{
class Program
{
static int[] Item; //Fixed int Item[] to int[] Item
static void Main(string[] args)
{
Add(3);
Add(4);
Add(6);
}
public static void Add(int x){
if (Item == null) // First time need to initialize your variable
{
Item = new int[1];
}
else
{
Array.Resize<int>(ref Item, Item.Length + 1);
}
Item[Item.Length-1] = x; //fixed Item.Length -> Item.Length-1
}
}
}
This should resize your array by one each time and then set the last item to what you are trying to add. Note that this is VERY inefficient.
Lists grow as you add elements to it. Arrays have a constant size. If you must use arrays, the easiest way to do it, is to create an array that is big enough to hold the entered elements.
private int[] _items = new int[100];
private int _count;
public void Add(int x)
{
_items[_count++] = x;
}
You also need to keep track of the number of elements already inserted (I used the field _count here);
As an example, you can then enumerate all the items like this:
for (int i = 0; i < _count; i++) {
Console.WriteLine(_items[i]);
}
You can make the items accessible publicly like this:
public int[] Items { get { return _items; } }
public int Count { get { return _count; } }
UPDATE
If you want to grow the array size automatically, this is best done by doubling the actual size, when the array becomes too small. It's a good compromise between speed and memory efficiency (this is how lists work internally).
private int[] _items = new int[8];
private int _count;
public void Add(int x)
{
if (_count == _items.Lengh) {
Array.Resize(ref _items, 2 * _items.Length);
}
_items[_count++] = x;
}
However, keep in mind that this changes the array reference. So no permanent copy of this array reference should be stored anywhere else.

Categories