Stackoverflow only with very large ArrayLists - c#

I'm using a recursive version of the insertion sort algorithm to sort 5000 objects based upon a randomly generated integer property, but I've been getting a stackoverflow exception only at an ArrayList of this size while working fine for ArrayLists of other sizes.
I used Console.WriteLine to see what the "position" integer goes up to in one of my methods and it ends up at `4719 before skipping a line and giving a stackoverflow exception. How should I get around this?
I should also mention that when testing an iterative version of insertion sort in the same Visual Studio solution and using an ArrayList of the same size of objects I do not get a stackoverflow exception.
My code for the recursive insertion sort is below (AL is the ArrayList):
public void IS()
{
ISRM(0);
}
private void ISRM(int position)
{
if (position == AL.Count)
return;
Console.WriteLine(position);
int PositionNext = position + 1;
ISRMNext(position, PositionNext);
ISRM(position + 1);
}
private void ISRMNext(int position, int PositionNext)
{
if ((PositionNext == 0) || (PositionNext == AL.Count))
return;
Webpage EntryNext = (Webpage)AL[PositionNext];
Webpage EntryBefore = (Webpage)AL[PositionNext - 1];
if (EntryBefore.getVisitCount() < EntryNext.getVisitCount())
{
Webpage temp = EntryBefore;
AL[PositionNext - 1] = AL[PositionNext];
AL[PositionNext] = temp;
}
ISRMNext(position, PositionNext - 1);
}

Well, first of all, sorting through recursive call is a bad idea for several reasons.
As you've already found out, this easily leads to a stack overflow due to limited size of the stack.
It will have poor performance by definition since function call and accompanying allocation of local function context on the stack is much more expensive operation compared to something like while or for operators iterating through plain collection.
These are two reasons why #Zer0 probably suggested it, but there's more to it.
There's ready ArrayList.Sort() method waiting for you that takes custom comparator. All you need is to write said comparator for your custom objects according to whatever rules you want and call Sort(your_comparator). That's it. You do not need to re-invent the wheel implementing your own sorting method itself - unless implementing sorting method is the actual goal of your program... but I honestly doubt it.
So, It could be something like this (not tested!):
class MyComparer : IComparer
{
public int Compare(object x, object y)
{
var _x = ((Webpage) x).getVisitCount();
var _y = ((Webpage) y).getVisitCount();
if (_x < _y)
{
return -1;
}
if (_x > _y)
{
return 1;
}
return 0;
}
}
Usage:
var myAL = new ArrayList();
// ... filling up the myAL
myAL.Sort(new MyComparer());

Related

How to check whether a collection of ints contains an element within a certain range of another given int?

I'm trying to see if any element in a list of integers is within, say, 0.5 of a given int in either direction.
In the interest of accounting for the XY Problem, the program is for editing Midi files; I'm trying to make it so the end point of any note is not too close to the start point of any other note in the file.
Currently what I have (or rather a simplified representation what I have) is this:
List<Note> notesCache = {...};
List<int> noteStartPointsCache = {...};
static bool CheckForElementWithinRange(int endPoint, float range)
{
foreach (int startPoint in noteStartPointsCache)
{
if (Math.Abs(startPoint - endPoint) < range)
return true;
}
return false;
}
void ProcessAllNotes()
{
foreach (Note note in notesCache)
{
if (CheckForElementWithinRange(note.endPoint, 0.5f))
{
ShortenNote(note);
}
}
}
But this feels quite expensive for a check - especially since the functions used to calculate the ints in my actual code are rather expensive themselves. Is there any more graceful way to do this, or is this as good as it's gonna get?
Only other solution I was thinking of was this:
int val = noteStartPointsCache.First(x => Math.Abs(x - note.endTime) < 0.5);
if (val != null)
ShortenNote();
But the logic is kind of the same as the first method; I don't think it would save me anything in terms of performance.

Why is this printing out the numbers from highest to lowest?

I'm currently taking a intermediate course on Udemy for C# and I'm trying to do one of the exercises. I've looked in the Q&A for students to see other peoples solutions, I've even copied and pasted other peoples solutions to see if theirs works and they do, I don't see any difference between mine and other peoples but for some reason my code prints out the numbers from highest to lowest and no where in the code should this happen. The idea of the exercise was to create a stack, we have 3 methods: Push(), Pop(), and Clear(). The push method adds objects to an ArrayList, the pop method removes the number from the top of the stack and returns the number. The clear method is self explanatory. Here's my code:
Stack Class:
public class Stack {
private ArrayList _arrayList = new ArrayList();
public void Push(object obj) {
if (obj is null) {
throw new InvalidOperationException();
}
else {
_arrayList.Add(obj);
}
}
public object Pop() {
if (_arrayList is null) {
throw new InvalidOperationException();
}
else {
var top = _arrayList.Count;
_arrayList.Remove(top);
return top;
}
}
public void Clear() {
for (int i = 0; i < _arrayList.Count; i++) {
_arrayList.Remove(i);
}
}
}
Program Class:
class Program {
static void Main(string[] args) {
var stack = new Stack();
stack.Push(5);
stack.Push(1);
stack.Push(2);
stack.Push(4);
stack.Push(3);
Console.WriteLine(stack.Pop());
Console.WriteLine(stack.Pop());
Console.WriteLine(stack.Pop());
Console.WriteLine(stack.Pop());
Console.WriteLine(stack.Pop());
}
}
var top = _arrayList.Count;
_arrayList.Remove(top);
return top;
You aren't printing the values, you're printing the number of elements stored.
Try changing your values to be something other than the first few positive integers to catch this kind of mistake more easily.
PS: There's been no reason to use ArrayList for over a decade. The generic collection classes such as List<int> are better in every way -- faster, less wasted memory, type safety.
var top = _arrayList.Count;
_arrayList.Remove(top);
return top;
top is assigned the value of the size of the list, and is never reassigned. Thus it looks like it prints highest to lowest because its just printing the size of the stack (which of course is 5, then 4, then 3, and so on). It only looks like you printed the contents of your list because you happened to push the same numbers. Some different test data would have made this bug more obvious.
I think what you actually wanted was
var top = _arrayList[_arrayList.Count -1];
Note that your code would fail miserably if there was a duplicate element in the list (due to removing based on the item value and not on the index). You also really shouldn't be using ArrayList at all; that's a .NET 1.0 class that's just an awful collection interface. Use a generic like List<T>.
You are returning
var top = _arrayList.Count;
Not the value in that position.
_arrayList(top-1);
You should be getting an index out of range error on that remove.
_arrayList.Remove(top);

Which data structure allows adding from both sides, but enforces a capacity?

I require a data structure that has a capacity, but also that allows adding an item from either the front or the back. Each time an item is added, one item must be removed from the opposite end. My first thought was that this sound very similar to a Deque.
Is there an existing data structure that provides this functionality, or do I have to create it myself? If it does exist, does the .Net library have an implementation?
Thanks
I would suggest that you use a LinkedList, which gives you all the functionality you need. There are AddFirst and AddLast methods that let you add items at the front or back, and RemoveFirst and RemoveLast methods that let you remove from the front and back.
And, of course, there's a Count property that tells you how many items are in the list, so you can enforce your capacity requirement.
Not tested but something like this I think would work
public class Stack<T>
{
private T[] arr;
readonly int m_Size;
int m_StackPointer = 0;
public T this[int i]
{
get
{
if (i >= m_Size)
throw new IndexOutOfRangeException();
int pointer = i + m_StackPointer;
if (pointer >= (m_Size)) pointer -= m_Size;
return arr[pointer];
}
}
public void AddStart(T addItem)
{
m_StackPointer--;
if (m_StackPointer < 0) m_StackPointer = m_Size - 1;
arr[m_StackPointer] = addItem;
}
public void AddEnd(T addItem)
{
arr[m_StackPointer] = addItem;
m_StackPointer++;
if (m_StackPointer >= m_Size) m_StackPointer = 0;
}
public Stack()
: this(100)
{ }
public Stack(int size)
{
m_Size = size;
arr = new T[size];
}
}
I have decided that the best option is to use an array of T for the backing structure, and have a reference Front and a reference Back to represent the virtual start and end of the structure. I will also store a direction enum that will effectively indicate which direction the structure is facing(whether the last add operation was at the Front or the Back or a default if no add operations have been performed). This way, I can also implement an indexer with O(1) complexity, rather than iterating the collection.
Thanks for all of the responses. For some reason, I thought that I would need to move the data around in the backing structure. I didn't realize that this option is possible in C#.

Can I retrieve the stored value x in a hashset given an object y where x.Equals(y)

[TestFixture]
class HashSetExample
{
[Test]
public void eg()
{
var comparer = new OddEvenBag();
var hs = new HashSet<int>(comparer);
hs.Add(1);
Assert.IsTrue(hs.Contains(3));
Assert.IsFalse(hs.Contains(0));
// THIS LINE HERE
var containedValue = hs.First(x => comparer.Equals(x, 3)); // i want something faster than this
Assert.AreEqual(1, containedValue);
}
public class OddEvenBag : IEqualityComparer<int>
{
public bool Equals(int x, int y)
{
return x % 2 == y % 2;
}
public int GetHashCode(int obj)
{
return obj % 2;
}
}
}
As well as checking if hs contains an odd number, I want to know what odd number if contains. Obviously I want a method that scales reasonably and does not simply iterate-and-search over the entire collection.
Another way to rephrase the question is, I want to replace the line below THIS LINE HERE with something efficient (say O(1), instead of O(n)).
Towards what end? I'm trying to intern a laaaaaaaarge number of immutable reference objects similar in size to a Point3D. Seems like using a HashSet<Foo> instead of a Dictionary<Foo,Foo> saves about 10% in memory. No, obviously this isn't a game changer but I figured it would not hurt to try it for a quick win. Apologies if this has offended anybody.
Edit: Link to similar/identical post provided by Balazs Tihanyi in comments, put here for emphasis.
The simple answer is no, you can't.
If you want to retrieve the object you will need to use a HashSet. There just isn't any suitable method in the API to do what you are asking for otherwise.
One optimization you could make though if you must use a Set for this is to first do a contains check and then only iterate over the Set if the contains returns true. Still you would almost certainly find that the extra overhead for a HashMap is tiny (since essentially it's just another object reference).

Get the last entry position easily?

What is the best or easier container I could use to retrieve the the last entry position ?
Or there are not better or easier than using Count ? is it ok to rely on count ?
Example:
List<Class> myList = new List<Class>();
int lastEntry = myList.Count - 1;
Message.Box(myList[lastEntry].Name);
There is no concurrent write to this list mainly reading.
Using Count is fine for List<T> -- or anything else that implements ICollection<T> or ICollection -- but you have an off-by-one error in your code. It should be...
int lastEntry = myList.Count - 1; // index is zero-based
Count is going to be the most performant, though since list indexing is zero-based you'll want to use count - 1 to retrieve the last entry in the list.
If you really want you can use Linq and do something like:
myList.Last()
or, if your worried about empty lists
myList.LastOrDefault()
But that is going to most likely be slower (depending on how Last() is implemented)
You could take advantage of the Last() extension method like so:
Message.Box(myList.Last().Name);
You can also use Last, which can help you avoid erros like the one you made.
On a side-note: Last is optimised for IList implementations to use exactly the same method as you did: access with index. Sure it is probably slower than doing it manually (optimisation requires additional cast), but unless it really is a bottleneck I wouldn't worry too much.
If you're interested to investigate this topic deeper, here's part of Jon Skeet's excellent series: Reimplementing LINQ to Objects: Part 11 - First/Single/Last and the ...OrDefault versions
If you just need to access the last item in the list, you might be better off using a Stack<T> instead. For the code you've written, there's nothing wrong with using Count - bear in mind that you should use .Count - 1
Use a Stack:
Stack<Class> d = new Stack<Class>();
Class last = d.Pop();
Message.Box(last.Name);
or if you don't want to remove:
Class last = d.Peek();
Message.Box(last.Name);
I want to make one point that seems to have been glossed over. Lists are not Queues; you don't always add to the end. You can instead Insert to them. If you want the index of the last-inserted item, you have to get a little more creative:
public class SmartList<T>:List<T>
{
public int LastIndex {get; protected set;}
public new virtual void Add(T obj)
{
base.Add(obj);
lastIndex = Count - 1;
}
public new virtual void AddRange(IEnumerable<T> obj)
{
base.AddRange(obj);
lastIndex = Count - 1;
}
public new virtual void Insert(T obj, int index)
{
base.Insert(obj, index);
lastIndex = index;
}
}
Unfortunately List's methods are not virtual, so you have to hide them and thus you have to use this class as the concrete SmartList; you can't use it as the value of a List-typed variable or parameter.

Categories