Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/117.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c 使用leftChild和rightChild实现二叉树是一种不好的做法吗?_Objective C_Ios - Fatal编程技术网

Objective c 使用leftChild和rightChild实现二叉树是一种不好的做法吗?

Objective c 使用leftChild和rightChild实现二叉树是一种不好的做法吗?,objective-c,ios,Objective C,Ios,我已经很长时间没有实现二进制了,最近有了这样的需求(为了演示一些代码),我开始使用: @interface NSNode : NSObject @property (strong, nonatomic) NSNode *leftChild; @property (strong, nonatomic) NSNode *rightChild; 但后来,似乎每当我需要对两个节点都做一些事情时,我都需要写两次——一次是为左子节点写,一次是为右子节点写,除非我将需要做的事情放到一个额外的方法中,并小心

我已经很长时间没有实现二进制了,最近有了这样的需求(为了演示一些代码),我开始使用:

@interface NSNode : NSObject

@property (strong, nonatomic) NSNode *leftChild;
@property (strong, nonatomic) NSNode *rightChild;
但后来,似乎每当我需要对两个节点都做一些事情时,我都需要写两次——一次是为左子节点写,一次是为右子节点写,除非我将需要做的事情放到一个额外的方法中,并小心地传递适当的参数——为了完成这一点,会有很多额外的方法

如果是使用NSMutableArray完成的

typedef enum {
    NSNodeLeft = 0,
    NSNodeRight
} NSNodeLeftOrRightSide;

@interface NSNode : NSObject

@property (strong, nonatomic) NSMutableArray *children;
然后,我可以始终使用循环对两个节点执行某些操作:

for (NSNode *node in self.children) {
    // do something
}
或者,如果需要索引来判断它是左子级还是右子级:

[self.children enumerateObjectsUsingBlock:
    ^(NSNode *node, NSUInteger nodeIndex, BOOL *stop) {
        // do something
    }
];
可以使用
nodeIndex
来确定它是左子级还是右子级


更重要的是,这个类可以很容易地扩展到一个有N个子树的树。这实际上是更好的做法吗?除了使用阵列的性能非常小之外,还有什么缺点吗?(我选择了
NSMutableArray
而不是
NSArray
,因为如果我们需要制作这个N-children,我们不需要把它到处改成
NSMutableArray

首先,你应该使用名称
NSNode
。苹果保留
NS
前缀供自己使用

其次,只需给
节点
类提供自己的枚举消息

@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
}
@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;
}
您可以像这样实现
NSFastEnumeration

for (Node *child in parentNode) {
    // do something with child
}
@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;
}
@接口节点:NSObject
...
@实现节点
-(nsInteger)countByEnumeratingWithState:(NSFastEnumerationState*)状态对象:(id*)stackbuf count:(nsInteger)stackbufCount{
//编译器在for…in循环开始时将state->state初始化为0。
//我用它来追踪哪些孩子被送回了。
//0=尚未返回任何子项
//1=返回的留守儿童
//2=两个孩子都回来了
state->itemsPtr=stackbuf;
state->mutationsPtr=(u桥无符号长*)self;
NSUInteger count=0;//我在这次呼叫中返回的孩子数
如果(状态->状态<1&&count状态;
}
如果(状态->状态<2&&count状态;
}
返回计数;
}

查看本文了解有关快速枚举的更多信息:

首先,您应该不要使用名称
NSNode
。苹果保留
NS
前缀供自己使用

其次,只需给
节点
类提供自己的枚举消息

@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
}
@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;
}
您可以像这样实现
NSFastEnumeration

for (Node *child in parentNode) {
    // do something with child
}
@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;
}
@接口节点:NSObject
...
@实现节点
-(nsInteger)countByEnumeratingWithState:(NSFastEnumerationState*)状态对象:(id*)stackbuf count:(nsInteger)stackbufCount{
//编译器在for…in循环开始时将state->state初始化为0。
//我用它来追踪哪些孩子被送回了。
//0=尚未返回任何子项
//1=返回的留守儿童
//2=两个孩子都回来了
state->itemsPtr=stackbuf;
state->mutationsPtr=(u桥无符号长*)self;
NSUInteger count=0;//我在这次呼叫中返回的孩子数
如果(状态->状态<1&&count状态;
}
如果(状态->状态<2&&count状态;
}
返回计数;
}

有关快速枚举的更多信息,请参阅本文:

当您需要对两个孩子都做一些事情时,您始终可以使用数组

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

如果您想让它更简单,您可以定义一个方法
-(NSArray*)children
,它返回
@[self.leftChild,self.righchild]
。但是将可变属性保留为不同的子级是有用的,因为它明确地编码了这样一个事实,即您的节点只有2个子级,而不是无限数量的子级。

当您需要对两个子级都做些什么时,您始终可以使用数组

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

如果您想让它更简单,您可以定义一个方法
-(NSArray*)children
,它返回
@[self.leftChild,self.righchild]
。但是,将可变属性保留为不同的子级是有用的,因为它显式地编码了这样一个事实,即您的节点只有2个子级,而不是无限数量的子级。

使用供应商的前缀作为类名的前缀是比这更糟糕的做法……您使用了吗?我经常看到人们做
UINodeView
之类的事情。。。如果不加前缀。。。或者它应该加什么前缀(只有在向公众发布以避免名称冲突时才加?@JeremyL:你应该给你的类加前缀,但你需要选择一个唯一的前缀。苹果拥有NS、CF、CA、UI和其他一些前缀。人们经常使用他们的首字母缩写,因此JL可能是您的一个不错的选择。@JeremyL他绝对肯定,我也是。:“避免在您自己的符号名中使用任何指定的前缀。”@JeremyL是的,我肯定。那个家伙也在使用坏习惯。在你的类名前面加上供应商的前缀是比这更糟糕的习惯…你在使用吗?我经常看到人们做
UINodeView
之类的事情。。。如果不加前缀。。。或者它应该加什么前缀(只有在向公众发布以避免名称冲突时才加?@JeremyL:你应该给你的类加前缀,但你需要选择一个唯一的前缀。苹果拥有NS,