0

I haven't implemented binary for a long time, and recently got a requirement to do that (to demonstrate some code), and I started using:

@interface NSNode : NSObject

@property (strong, nonatomic) NSNode *leftChild;
@property (strong, nonatomic) NSNode *rightChild;

but later on, it seems that whenever I need to do something to both nodes, I need to write it twice -- once for the left child and once for the right child, unless if I make what needs to be done into an extra method, and pass the proper arguments carefully -- there will be a lot of extra methods just to accomplish this.

If it had been done by using an NSMutableArray

typedef enum {
    NSNodeLeft = 0,
    NSNodeRight
} NSNodeLeftOrRightSide;

@interface NSNode : NSObject

@property (strong, nonatomic) NSMutableArray *children;

then I can always just use a loop to do something to both nodes:

for (NSNode *node in self.children) {
    // do something
}

Or if an index is needed to tell whether it is left or right child:

[self.children enumerateObjectsUsingBlock:
    ^(NSNode *node, NSUInteger nodeIndex, BOOL *stop) {
        // do something
    }
];

and the nodeIndex can be used to determined whether it is left or right child.

And what's more, this class can be easily extend to a tree with N-children. Is this actually a better practice? Is there any disadvantage except for a very small performance for using array? (I chose NSMutableArray instead of NSArray because if we ever need to make this N-children, we don't need to change it to NSMutableArray all over the place).

4

2 に答える 2

3

両方の子供に何かをする必要があるときは、とにかくいつでも配列を使用できます

for (Node *node in @[self.leftChild, self.rightChild]) {
    // ...
}

また、もっと簡単にしたい場合は、- (NSArray *)childrenを返すメソッドを定義するだけ@[self.leftChild, self.rightChild]です。ただし、可変プロパティを個別の子として保持すると、ノードに無制限の数の子ではなく2つの子しかないという事実が明示的にエンコードされるため、便利です。

于 2012-09-08T05:58:28.537 に答える
2

まず、名前を使用しないでくださいNSNode。AppleNSは、独自に使用するためにプレフィックスを予約しています。

次に、Nodeクラスに独自の列挙メッセージを与えるだけです。

@interface Node : NSObject

- (void)enumerateChildrenUsingBlock:(void (^)(Node *child, NSUInteger childIndex, BOOL *stop))block;

// I prefer this shorter name style in my own classes:
- (void)forEachChild:(void (^)(Node *child, NSUInteger childIndex, BOOL *stop))block;

それを実装するのは簡単です:

@implementation Node

- (void)enumerateChildrenUsingBlock:(void (^)(Node *child, NSUInteger childIndex, BOOL *stop))block {
    BOOL stop = NO;
    block(self.leftChild, 0, &stop);
    if (!stop) {
        block(self.rightChild, 1, &stop);
    }
}

プロトコルを実装する場合はNSFastEnumeration、次のようにfor/inループを作成することもできます。

for (Node *child in parentNode) {
    // do something with child
}

NSFastEnumeration次のように実装できます。

@interface Node : NSObject <NSFastEnumeration>
...

@implementation Node

- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)stackbufCount {
    // The compiler initializes state->state to 0 at the start of the for...in loop.
    // I use it to track which children have been returned.
    // 0 = no children returned yet
    // 1 = left children returned
    // 2 = both children returned

    state->itemsPtr = stackbuf;
    state->mutationsPtr = (__bridge unsigned long *)self;

    NSUInteger count = 0; // number of children I'm returning on this call
    if (state->state < 1 && count < stackbufCount) {
        stackbuf[count++] = self.leftChild;
        ++state->state;
    }
    if (state->state < 2 && count < stackbufCount) {
        stackbuf[count++] = self.rightChild;
        ++state->state;
    }

    return count;
}

高速列挙の詳細については、この記事を参照してください:http: //www.mikeash.com/pyblog/friday-qa-2010-04-16-implementing-fast-enumeration.html

于 2012-09-08T05:58:19.543 に答える