首页 > hot资讯 > 动态数组的实现和功能

动态数组的实现和功能

更新时间:2020-10-16 17:30 浏览198次 来源:动力节点

我们都知道数组(Array)是有序的元素序列,而在某种程度上,数组又可以划分为动态数组和静态数组。动态数组是指在声明时没有确定数组大小的数组,即忽略圆括号中的下标;当要用它时,可随时用ReDim语句重新指出数组的大小。本文就来和大家一起来探讨动态数组的相关知识。


Objective-C中的NSMutableArray就是一个动态数组,不用指定数组的长度就可以放心向里边添加元素,不需要考虑溢出的问题。实现动态数据的方式非常多,例如对静态数组进行封装扩容或者链表,甚至多种方式混合使用,根据数据量的大小来动态改变自己的数据结构。这里就使用最简单的根据静态数据动态扩容的方式,来实现一个动态数组。

为了实现一套完整的自定义数据结构,这里对静态数组的封装,使用的是之前自定义静态数组,因为Objective-C并没有封装好的静态数组可用,实际上就是一个可以存放指针并且内部维持Objective-C引用计数的指针数组。


自定义动态数组的效果

JKRArrayList *array = [JKRArrayList new];

for (NSUInteger i = 0; i < 60; i++) {

[array addObject:[Person personWithAge:i]];

}

NSLog(@"添加后 %@", array);

打印:

--- 扩容: 16 -> 24 ---

--- 扩容: 24 -> 36 ---

--- 扩容: 36 -> 54 ---

--- 扩容: 54 -> 81 ---

添加后 size=60, {

...

}

[array removeAllObjects];

NSLog(@"清空后 %@", array);

打印:

dealloc

dealloc

dealloc

...

dealloc

清空后 size=0, {

}


上面说的是动态数组的具体实现,下面我们一起来看动态数组的基本功能。

动态数组的应该提供的功能仿照NSMutableArray来设计,由于之后还会用多种链表来实现动态数组,所以还会有很多相同的处理逻辑和接口,这里先定义一个动态数组的基类:

@interface JKRBaseList: NSObject {

@protected

// 记录动态数组的当前长度

NSUInteger _size;

}

- (NSUInteger)count;

- (void)rangeCheckForAdd:(NSUInteger)index;

- (void)rangeCheckForExceptAdd:(NSUInteger)index;

- (void)addObject:(nullable ObjectType)anObject;

- (BOOL)containsObject:(nullable ObjectType)anObject;

- (nullable ObjectType)firstObject;

- (nullable ObjectType)lastObject;

- (void)removeFirstObject;

- (void)removeLastObject;

- (void)removeObject:(nullable ObjectType)anObject;

- (_Nullable ObjectType)objectAtIndexedSubscript:(NSUInteger)idx;

- (void)setObject:(_Nullable ObjectType)obj atIndexedSubscript:(NSUInteger)idx;

@end

@interface JKRBaseList(JKRBaseList)

- (void)insertObject:(nullable ObjectType)anObject atIndex:(NSUInteger)index;

- (void)removeObjectAtIndex:(NSUInteger)index;

- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(nullable ObjectType)anObject;

- (nullable ObjectType)objectAtIndex:(NSUInteger)index;

- (NSUInteger)indexOfObject:(nullable ObjectType)anObject;

- (void)removeAllObjects;

- (void)enumerateObjectsUsingBlock:(void (^)(_Nullable ObjectType obj, NSUInteger idx, BOOL *stop))block;

@end


JKRBaseList是所有动态数组的基类,之所以有一部分在扩展里边写,是为了便于区分,扩展内的接口是需要子类实现的,而扩展之外的接口则是不同方式实现的动态数组都相同的处理,不需要子类重写,只要JKRBaseList自己实现即可。把不需要JKRBaseList实现的方法写在扩展的好处就是不需要在JKRBaseList.m里边写接口的具体实现,如果定义成它的方法声明而不去实现的话,编译器会报警告。另外分成两部分写,也便于区分哪些是子类需要实现的。

系统的NSArray和NSMutableArray都允许存放nil,这里为了扩容功能,所以允许传入并保存nil到数据中。

首先先看一下JKRBaseList里边的成员变量:NSUInteger _size; 这个变量是所有动态数组都需要的,它负责记录当前动态数组的长度。因为动态数组对外部可见的长度和内部真实的长度是不一定一致的,比如现在我们要实现的通过静态数组封装的动态数组,刚刚开始初始化的时候,动态数组对象内部保存的静态数组长度可能是16,而外部展示的长度则为0,因为还没有添加任何元素。如果用链表来实现动态数组的话,同样需要记录数组长度,否则每次都要遍历链表所有节点来累加计算数组长度。


以上就是我们对动态数组的实现和功能的简单介绍,实际上,动态数组可以在任何时候改变大小,在灵活、方便的同时也有助于有效管理内存。是不是已经感受到了动态数组的神奇和强大的能力了?其实,数组的魅力远不止如此,‘’欲穷千里目,更上一层楼。‘’,观看本站的Java零基础教程,领略更加奥妙的数组风情吧!


热门课程推荐

全部班型支持免费试学

动力节点在线报名表(此信息已加密,请放心填写)

返回顶部