DFS algorithm implementation at Objective C - objective-c

I am trying to implement the Objective C realization of this algorithm. Here the implementation of it:
#implementation DFSAlgorithm
-(void)dfs:(Graph*)g andStartingPosition:(int)s{
[self performDFS:g andPosition:s];
}
-(void)markedArrayInit:(int)capacity{
//0 is for unmarked vertices
//1 is form marked ones
self.marked=[[NSMutableArray alloc]initWithCapacity:capacity];
for(int i=0;i<[self.marked count];i++)
[self.marked replaceObjectAtIndex:i withObject:[NSNumber numberWithInt:0]];
}
-(void)performDFS:(Graph *)g andPosition:(int)v{
[self markedArrayInit:(int)[g numberOfVertices]];
[self.marked replaceObjectAtIndex:v withObject:[NSNumber numberWithInt:1]];
for (NSNumber *vertex in [g.vertices objectAtIndex:v]){
if(1==[self isMarked:v atGraph:g]){
NSLog(#"%d",(int)vertex);
[self performDFS:g andPosition:(int)vertex];
}
}
}
-(int)isMarked:(int)v atGraph:(Graph *)g{
return [self.marked objectAtIndex:v];
}
#end
However, I don't understand why the following error occurs:
[__NSArrayM replaceObjectAtIndex:withObject:]: index 0 beyond bounds for empty array'
How can I correctly initialize the marked array?
Thank you.

An NSMutableArray is created empty, the capacity value you pass is just a hint to the implementation about how large you expect the array to become.
Therefore replaceObjectAtIndex:withObject: does not work for you, as the array is empty you have no objects to replace.
Instead just use addObject: capacity times.

In your markedArrayInit method you create empty mutable array and reserve memory for it to hold at least capasity number of items. But you do not actually add anything to it (for loop in that method does not actually do anything at all). To fix your problem you can add enough number of items in for loop:
for (int i=0;i< initWithCapacity:capacity;i++)
[self.marked addObject: #0];
}
Edit:
Your implementation has several other problems:
you initialize marked array on each call to performDFS:andPosition:, and call that method recursively. You should move initialization to dfs:andStartingPosition: method
In isMarked:atGraph: method you return object from array, not the numeric value it holds - so it will never be 1, you might want to replace it with the following implementation (Note that method name implies we return some boolean value, not an integer that we'll need to interpret later):
-(BOOL)isMarked:(int)v atGraph:(Graph *)g {
return [self.marked[v] intValue] == 1;
}
...
if([self isMarked:v atGraph:g]){
...
}
There're better data structures to store indices of marked nodes, e.g. NSSet or NSIndexSet

You try to replace not existing object inside array. In markedArrayInit use addObject: method from NSMutableArray. [self.marked count] is always 0 in for cycle.

Related

how to chain methods in objective-c

I'm trying to implement a parsing method to turn an XML document into a multi-dimensional array, however it relies on needing to removal objects from an array just after adding that array to the multi-dimensional array, like so:
while (k<blockRowArray.count){ //loops through all rows one by one
NSLog(#"current k is %i", k);
GDataXMLDocument *currentRow = (GDataXMLDocument *) [blockRowArray objectAtIndex:k];
NSArray *arrayOfBlocks = [currentRow nodesForXPath:#"b" error:nil];
j = 0;
while (j <arrayOfBlocks.count) {
NSLog(#"current j is %i",j);
GDataXMLElement *blockElement = (GDataXMLElement *) [arrayOfBlocks objectAtIndex:j];
NSNumber* blockValue = [NSNumber numberWithInt:[[blockElement stringValue] intValue]];
[individualRowOfBlocks addObject:blockValue];
j++;
}
k++;
NSLog (#"Current row of blocks array is %#",individualRowOfBlocks);
[rowBlocks addObject:individualRowOfBlocks];
[individualRowOfBlocks removeAllObjects];
}
However [individualRowOfBlocks removeAllObjects] is clearly running at the same time or before [rowBlocks addObject:individualRowOfBlocks] as I end up with a multi-dimensional array with a set of empty arrays in it, so what I need to do is make sure that [individualRowOfBlocks removeAllObjects] runs after [individualRowOfBlocks removeAllObjects] any methods of doing this?
However [individualRowOfBlocks removeAllObjects] is clearly running at
the same time or before [rowBlocks addObject:individualRowOfBlocks] as
I end up with a multi-dimensional array with a set of empty arrays in
it, so what I need to do is make sure that [individualRowOfBlocks
removeAllObjects] runs after [individualRowOfBlocks removeAllObjects]
any methods of doing this?
Unless there are threads (or queues) involved, Objective-C methods are always going to be executed in the order written in the code unless the methods being called explicitly do stuff in threads/queues in their implementation (which is exceptionally unlikely in that code).
Every time you call [rowBlocks addObject:individualRowOfBlocks];, you are adding a new reference to the same individualRowOfBlocks array. If you subsequently change the contents of individualRowOfBlocks, every slot in rowBlocks will effectively reflect that change because every slot points to the same instance of the array.
It sounds like instead of removeAllObjects, you should create a new instance of NSMutableArray on each pass through the loop, assigning it to individualRowOfBlocks.

Add object to array only if the object is not in already

I want to add object to array only if the array already does not contain that object.
How to do opposite of containsObject method in NSArray ?
Use an NSMutableOrderedSet, whose addObject: method does exactly what you want:
Appends a given object to the mutable ordered set, if it is not already a member.
Here's how I'd do it:
if (![myArray containsObject:objectToAdd]){
[myArray addObject:objectToAdd];
}
More detail here:
https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSArray_Class/NSArray.html
Note that because the containsObject method queries every object in the array there are some performance considerations when using it on larger arrays.
if your object is of NSString* type you can do fast enumeration like this
BOOL found = NO;
for(NSString *object in YourArray)
{
if([object isEqualtoString:#"My text"])
{
found = YES;
}
}
if(!found)
{
//addObject
}
there are many isEqual methods in objective-c for different data types

How to manage memory/usage of a NSMutableArray of NSMutableArrays

I am currently trying to write a class to create faux grid system to keep track of a NSMutableArray of game entities using a NSMutableArray of NSMutableArrays. Given my limited experience with Objective-C programming, I am unsure of how certain things work.
Here is the init method:
#define MAX_BALL_ROWCOUNT 6
#define MAX_BALL_COLCOUNT 4
- (id) initWithMutableArray:(NSMutableArray *)aList {
self = [super init];
if (self != nil) {
ballList = [[NSMutableArray alloc] initWithCapacity: MAX_BALL_ROWCOUNT];
for (int i=0; i<MAX_BALL_ROWCOUNT; i++) {
NSMutableArray *balls = [[NSMutableArray alloc] initWithCapacity:MAX_BALL_COLCOUNT];
[ballList addObject:balls];
[balls release];
}
int x = 0;
for (NSMutableArray *array in ballList) {
for (int i = 0; i<MAX_BALL_COLCOUNT; i++) {
[array addObject:[aList objectAtIndex:x]];
x++;
}
}
}
return self;
}
ballList is the class's NSMutableArray that will store NSMutableArrays.
aList is the NSMutableArray containing the GameEntities I wish to keep track of that is passed into this class.
All the sizes and amount of entities to store are fixed, which is why there is no checks on the sizes of the arrays nor the number of entities to store.
So the first question I have involves freeing memory. This is the dealloc function I currently have:
- (void) dealloc {
[ballList release];
[super dealloc];
}
Does calling a release on ballList cause the release to be called on the NSMutableArrays that it contains (which will subsequently call the release on the objects those NSMutableArrays contain) or do I have to write something like:
for (NSMutableArray *array in ballList) {
[array release];
}
[ballList release];
My second question involves the usage of this array of arrays. Is this the proper way to traverse through ballList?
- (void) update {
for (NSMutableArray *array in ballList) {
for (GameEntity *balls in array) {
(CGPoint) location = [balls getLocation];
[balls setLocation: CGPointMake(location.x+1, location.y+1)];
}
}
}
Lastly, in the code above where it sets the balls location, does it only affect the contents within ballList or does the original aList that is passed into ballList change as well? If the contents in the original aList do not change, how would I write it so that they do?
If people have suggestions for a better way to keep track of the entities in a grid system, I'd be open to those too. Thanks in advance.
First : One release is enough for the NSMutableArray instance to release all it's object.
[ballList release];
Second : Your code for updating GameEntity instance is fine and will also effect to the original aList (which you called) .
When the dealloc of a NSArray or NSMutableArray is called, all its contents gets a release message. So when you release ballList, if there there is no other owner (I guess in this case there is none) then its dealloc is called and you don't need to release the other arrays here.
Your loop traversal is fine. Though for 2D arrays instead of NSArray of NSArray I personally prefer pure C 2D array, at least in most of the cases.
When you are adding object in this way you are adding a reference in the array. So any change via the array's reference will be reflected in all references of the object. If you don't want that then add a copy of the object in the array.

NCSFDictionary, Mutating method sent to immutable object

I have just started to jump into the realm of Objective-C and am slowly getting it all. I have been working on unarchiving a file that was a NSMutableArray and then initializing in my model with that array. The array is filled with various NSMutableDicationary's. From what I have seen it will add those dictionaries as non-mutable, so I went ahead and copied the regular and put them in a mutable and remove the old one. This solution seems to work for every instance except the very first.
I am at a loss as to why it would work for all but the first.
Here is how I am initializing it all
-(id) initWithList:(NSMutableArray *)savedList
{
self = [super init];
if (self)
{
int size=0;
serverList=[[NSMutableArray alloc] initWithArray:savedList copyItems:YES];
size=[serverList count];
for(int i=0;i<size;i++)
{
loginList=[NSMutableDictionary dictionaryWithDictionary:[serverList objectAtIndex:i]];
[serverList addObject:loginList];
[serverList removeObjectAtIndex:i];
}
}
return self;
}
Here is the code that is throwing the error, The value is being read off of a checkbox in a tableview and passed here to change the value.
-(void)setMount:(int)row value:(NSNumber*)boolAsNumber
{
[[serverList objectAtIndex:row] setObject:boolAsNumber forKey:#"mountshare"];
}
Here is the error that it shows when I try and change the first element
2010-12-01 13:38:54.445 Network Share[35992:a0f] *** -[NSCFDictionary setObject:forKey:]: mutating method sent to immutable object
Thanks for your help. If there is a better way please let me know.
This loop code is wrong:
size=[serverList count];
for(int i=0;i<size;i++)
{
loginList=[NSMutableDictionary dictionaryWithDictionary:[serverList objectAtIndex:i]];
[serverList addObject:loginList];
[serverList removeObjectAtIndex:i];
}
When you remove an object, the array is renumbered. After you've processed the 1st object at index 0, the original 2nd object is becoming the 1st object at index 0, but i is now set to index 1, which is where the original 3rd object is! This means you're only processing alternate items from the original array, and the 2nd, 4th, etc items never get swapped, and that's why you get the errors you're seeing.
One way to solve this would be to replace the "i" in the objectAtIndex: and removeObjectAtIndex: calls with "0", so you're always taking items off the front of the array.
The alternate solution would be to create a separate newServerList array and insert your new objects into that. At the end of the loop, release the old serverList and set the variable to point to newServerList.
Your indexes are messed up. As soon as you remove the object at index 0, the next one will take it's place and you will never replace that, because you then carry on with index 1.
{immutable0, immutable1}
i = 0:
addObject:
{immutable0, immutable1, mutable0}
removeObjectAtIndex:
{immutable1, mutable0}
i = 1:
addObject:
{immutable0, mutable0, mutable02}
removeObjectAtIndex:
{immutable0, mutable02}
--> still got the immutable there. Remember to never remove objects from a mutable array you are looping through at the same time.
You could condense the code a bit:
NSMutableArray *serverList = [NSMutableArray arrayWithCapacity:[savedList count]];
for (NSDictionary *dictionary in savedList)
{
mutable = [dictionary mutableCopy];
[serverList addObject:mutable];
[mutable release];
}
Unrelated to your problem: the argument is obviously wrong (NSMutableArray), if you expect an immutable array there; and if you create your serverList that way, there is no need for a deep copy (copyItems:YES).

comparing arrays in objective-c

Ok a pretty simple question.. in c++ it seems to work but in objective-c i seem to struggle with it :S ..
If you want to compare two arrays it should be something like this right
for ( int i = 0; i < [appdelegate.nicearray count]; i++ )
{
if ( appdelegate.nicearray[i] == appdelegate.exercarray[i] )
{
NSLog(#"the same elements in this selection");
}
}
what's the problem exactly ?
These are Cocoa array objects (instances of NSArray), not C arrays or C++ vectors, and remember that Objective-C does not have operator overloading. The only things you can do with an object are pass it around, store it in variables, and send messages to it.
So the array-subscript operator is wrong with Objective-C objects. I don't think it's even linguistically valid to dereference a pointer to an Objective-C object, so this code should be giving you a compiler error. I may be misremembering, though. If it does make it to runtime, that code will crash sooner or later, since you're accessing memory beyond the ends of the array objects.
(EDIT from the year 2013: Objective-C now supports subscripting of objects. This ultimately translates into the appropriate objectAtIndex: or replaceObjectAtIndex:withObject: message. So, the code in the question would actually work now, although it's still not the proper way to simply walk an array, much less to compare two arrays.)
The proper way to retrieve an object from an NSArray object by its index is not to use the array-subscript operator, but to send the array object the objectAtIndex: message:
[myArray objectAtIndex:i]
The proper way to iterate on the elements of an array object, assuming you don't really need the index for something else (such as replacing objects in a mutable array), is to loop on it directly (this is called “fast enumeration”):
for (MyObject *myObject in myArray) {
…
}
NSArray also responds to objectEnumerator and reverseObjectEnumerator, which return a similarly-iterable object. Of the two, reverseObjectEnumerator is the more useful in new code, since you can just iterate on the array directly to iterate forward. Both of them were most useful before fast enumeration existed; that code looked like this:
NSEnumerator *myArrayEnum = [myArray objectEnumerator];
MyObject *myObject;
while ((myObject = [myArrayEnum nextObject])) {
…
}
(Yes, that's an assignment in the condition. Deliberately, hence the extra (). We coded boldly back then, didn't we?)
For what you're doing, though, you more likely want to send one of the arrays an isEqualToArray: message, as Williham Totland suggested:
BOOL theyAreEqual = [myFirstArray isEqualToArray:mySecondArray];
This will make sure both arrays have the same length, then walk them both in lock-step, sending isEqual: to each pair of objects. It'll return YES if every isEqual: message returned YES; NO otherwise. The arrays may contain different objects, but as long as each pair is equal, the arrays themselves are equal.
That assumes you want object equality. Two separate objects are equal if one of them responds with YES when you send it an isEqual: message and pass the other object. If you meant to compare the identities of the objects, then you do need to do the lock-step loop yourself and use ==:
BOOL arraysContainTheSameObjects = YES;
NSEnumerator *otherEnum = [otherArray objectEnumerator];
for (MyObject *myObject in myArray) {
if (myObject != [otherEnum nextObject]) {
//We have found a pair of two different objects.
arraysContainTheSameObjects = NO;
break;
}
}
But that's unlikely. Most of the time, I have wanted to test the objects' equality, not identities, so isEqualToArray: is what I wanted.
You want the isEqualToArray: method. As in:
if ([arrayOne isEqualToArray:arrayTwo]) {
// Do something
}
This will recursively compare the two arrays, while having the advantage of not being needlessly circuitous and not requiring a loop.
Try telling us the result you're getting when you run this code. The approach is correct, but try this one:
for (int i =0; i< appdelegate.nicearray.count; i++)
{
if ([[appdelegate objectAtIndex:i] isEqual: [appdelegate.exercarray objectAtIndex:i]])
{
NSLog(#"the same");
}
}
Here's a little one I put together based on the top ranked example. This merely checks that the arrays contains the same values, irrespective of order and if there are any duplicates. I mainly use this to compare keys of two dictionaries (which often return their allKeys arrays in various sort orders) to see if they contain the same objects. Thanks Peter Hosley for providing the example I adapted this from.
#pragma mark - Arrays
// Check to see if arrays contain the same elements, not necessarily in the same order
// This is different from [array isEqualToArray:responseKeys] which demands the same order in both arrays
// ## Does not compensate for duplicate entries in an array
+ (BOOL)doArraysContainTheSameObjects:(NSArray *)firstArray withArray:(NSArray *)secondArray {
BOOL arraysContainTheSameObjects = YES;
for (id myObject in firstArray) {
if (![secondArray containsObject:myObject]) {
// We have found an object that is not in the other array.
arraysContainTheSameObjects = NO;
break;
}
}
return arraysContainTheSameObjects;
}
I do the following when comparing arrays:
Check to see if any of the arrays are nil when the other is not
Check to see if the lengths are the same
Iterate (using a for loop like you have) over each element checking the matching element in the other array.
To compare elements you need to define what you want to regard as being "equal". Are they equal only if the pointers in the array are equal or can they be equal if the content is equal too.
For the pointer case, you can use ==.
For the deep comparison you might need to use CompareTo or something similar.