浅谈iOS 数据结构之链表

链表(Linked List)是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的,表现形式如下图所示:

单链表

双链表

数组和链表区别:

  • 数组:数组元素在内存上连续存放,可以通过下标查找元素;插入、删除需要移动大量元素,比较适用于元素很少变化的情况
  • 链表:链表中的元素在内存中不是顺序存储的,查找慢,插入、删除只需要对元素指针重新赋值,效率高

Objective-C 里没有现成的链表结构,下面我实现了非线程安全的单链表和双链表,以下都是具体的实现细节,完整代码可以在这儿下载

单链表

单链表提供了插入、删除、查询、反转等操作,具体实现如下:

BBSingleLinkedList.h

#import <Foundation/Foundation.h>

@interface BBSingleLinkedNode : NSObject <NSCopying>

@property (nonatomic, strong) NSString *key;
@property (nonatomic, strong) NSString *value;
@property (nonatomic, strong) BBSingleLinkedNode *next;

- (instancetype)initWithKey:(NSString *)key
      value:(NSString *)value;

+ (instancetype)nodeWithKey:(NSString *)key
      value:(NSString *)value;

@end

@interface BBSingleLinkedList : NSObject

- (void)insertNode:(BBSingleLinkedNode *)node;
- (void)insertNodeAtHead:(BBSingleLinkedNode *)node;
- (void)insertNode:(BBSingleLinkedNode *)newNode beforeNodeForKey:(NSString *)key;
- (void)insertNode:(BBSingleLinkedNode *)newNode afterNodeForKey:(NSString *)key;

- (void)bringNodeToHead:(BBSingleLinkedNode *)node;

- (void)removeNode:(BBSingleLinkedNode *)node;

- (BBSingleLinkedNode *)nodeForKey:(NSString *)key;
- (BBSingleLinkedNode *)headNode;
- (BBSingleLinkedNode *)lastNode;

- (NSInteger)length;
- (BOOL)isEmpty;

- (void)reverse;
- (void)readAllNode;

@end

BBSingleLinkedList.m

#import "BBSingleLinkedList.h"

@implementation BBSingleLinkedNode

- (instancetype)initWithKey:(NSString *)key
      value:(NSString *)value
{
 if (self = [super init]) {
  _key = key;
  _value = value;
 }
 return self;
}

+ (instancetype)nodeWithKey:(NSString *)key
      value:(NSString *)value
{
 return [[[self class] alloc] initWithKey:key value:value];
}

#pragma mark - NSCopying
- (id)copyWithZone:(nullable NSZone *)zone
{
 BBSingleLinkedNode *newNode = [[BBSingleLinkedNode allocWithZone:zone] init];
 newNode.key = self.key;
 newNode.value = self.value;
 newNode.next = self.next;
 return newNode;
}

@end

@interface BBSingleLinkedList ()

@property (nonatomic, strong) BBSingleLinkedNode *headNode;
@property (nonatomic, strong) NSMutableDictionary *innerMap;

@end

@implementation BBSingleLinkedList

- (instancetype)init
{
 self = [super init];
 if (self) {
  _innerMap = [NSMutableDictionary new];
 }
 return self;
}

#pragma mark - public
- (void)insertNodeAtHead:(BBSingleLinkedNode *)node
{
 if (!node || node.key.length == 0) {
  return;
 }

 if ([self isNodeExists:node]) {
  return;
 }

 _innerMap[node.key] = node;
 if (_headNode) {
  node.next = _headNode;
  _headNode = node;
 } else {
  _headNode = node;
 }
}

- (void)insertNode:(BBSingleLinkedNode *)node
{
 if (!node || node.key.length == 0) {
  return;
 }

 if ([self isNodeExists:node]) {
  return;
 }

 _innerMap[node.key] = node;

 if (!_headNode) {
  _headNode = node;
  return;
 }
 BBSingleLinkedNode *lastNode = [self lastNode];
 lastNode.next = node;
}

- (void)insertNode:(BBSingleLinkedNode *)newNode beforeNodeForKey:(NSString *)key
{
 if (key.length == 0 || !newNode || newNode.key.length == 0) {
  return;
 }

 if ([self isNodeExists:newNode]) {
  return;
 }

 if (!_headNode) {
  _headNode = newNode;
  return;
 }

 BBSingleLinkedNode *node = _innerMap[key];
 if (node) {
  _innerMap[newNode.key] = newNode;
  BBSingleLinkedNode *aheadNode = [self nodeBeforeNode:node];
  if (aheadNode) {
   aheadNode.next = newNode;
   newNode.next = node;
  } else {
   _headNode = newNode;
   newNode.next = node;
  }

 } else {
  [self insertNode:newNode]; //insert to tail
 }
}

- (void)insertNode:(BBSingleLinkedNode *)newNode afterNodeForKey:(NSString *)key
{
 if (key.length == 0 || !newNode || newNode.key.length == 0) {
  return;
 }

 if ([self isNodeExists:newNode]) {
  return;
 }

 if (!_headNode) {
  _headNode = newNode;
  return;
 }

 BBSingleLinkedNode *node = _innerMap[key];
 if (node) {
  _innerMap[newNode.key] = newNode;
  newNode.next = node.next;
  node.next = newNode;
 } else {
  [self insertNode:newNode]; //insert to tail
 }
}

- (void)removeNode:(BBSingleLinkedNode *)node
{
 if (!node || node.key.length == 0) {
  return;
 }
 [_innerMap removeObjectForKey:node.key];

 if (node.next) {
  node.key = node.next.key;
  node.value = node.next.value;
  node.next = node.next.next;
 } else {
  BBSingleLinkedNode *aheadNode = [self nodeBeforeNode:node];
  aheadNode.next = nil;
 }
}

- (void)bringNodeToHead:(BBSingleLinkedNode *)node
{
 if (!node || !_headNode) {
  return;
 }

 if ([node isEqual:_headNode]) {
  return;
 }

 BBSingleLinkedNode *aheadNode = [self nodeBeforeNode:node];
 aheadNode.next = node.next;
 node.next = _headNode;
 _headNode = node;
}

- (BBSingleLinkedNode *)nodeForKey:(NSString *)key
{
 if (key.length == 0) {
  return nil;
 }
 BBSingleLinkedNode *node = _innerMap[key];
 return node;
}

- (BBSingleLinkedNode *)headNode
{
 return _headNode;
}

- (BBSingleLinkedNode *)lastNode
{
 BBSingleLinkedNode *last = _headNode;
 while (last.next) {
  last = last.next;
 }
 return last;
}

- (void)reverse
{
 BBSingleLinkedNode *prev = nil;
 BBSingleLinkedNode *current = _headNode;
 BBSingleLinkedNode *next = nil;

 while (current) {
  next = current.next;
  current.next = prev;
  prev = current;
  current = next;
 }

 _headNode = prev;
}

- (void)readAllNode
{
 BBSingleLinkedNode *tmpNode = _headNode;
 while (tmpNode) {
  NSLog(@"node key -- %@, node value -- %@", tmpNode.key, tmpNode.value);
  tmpNode = tmpNode.next;
 }
}

- (NSInteger)length
{
 NSInteger _len = 0;
 for (BBSingleLinkedNode *node = _headNode; node; node = node.next) {
  _len ++;
 }
 return _len;
}

- (BOOL)isEmpty
{
 return _headNode == nil;
}

#pragma mark - private
- (BBSingleLinkedNode *)nodeBeforeNode:(BBSingleLinkedNode *)node
{
 BBSingleLinkedNode *targetNode = nil;
 BBSingleLinkedNode *tmpNode = _headNode;
 while (tmpNode) {
  if ([tmpNode.next isEqual:node]) {
   targetNode = tmpNode;
   break;
  } else {
   tmpNode = tmpNode.next;
  }
 }
 return targetNode;
}

- (BOOL)isNodeExists:(BBSingleLinkedNode *)node
{
 BBSingleLinkedNode *tmpNode = _headNode;
 while (tmpNode) {
  if ([tmpNode isEqual:node]) {
   return YES;
  }
  tmpNode = tmpNode.next;
 }
 return false;
}

@end

双链表

双链表提供了插入、删除、查询操作,具体实现如下:

BBLinkedMap.h

#import <Foundation/Foundation.h>

@interface BBLinkedNode : NSObject <NSCopying>

@property (nonatomic, strong) NSString *key;
@property (nonatomic, strong) NSString *value;
@property (nonatomic, strong) BBLinkedNode *prev;
@property (nonatomic, strong) BBLinkedNode *next;

- (instancetype)initWithKey:(NSString *)key
      value:(NSString *)value;

+ (instancetype)nodeWithKey:(NSString *)key
      value:(NSString *)value;

@end

@interface BBLinkedMap : NSObject

- (void)insertNodeAtHead:(BBLinkedNode *)node;
- (void)insertNode:(BBLinkedNode *)node;
- (void)insertNode:(BBLinkedNode *)newNode beforeNodeForKey:(NSString *)key;
- (void)insertNode:(BBLinkedNode *)newNode afterNodeForKey:(NSString *)key;
- (void)bringNodeToHead:(BBLinkedNode *)node;

- (void)readAllNode;
- (void)removeNodeForKey:(NSString *)key;
- (void)removeTailNode;

- (NSInteger)length;
- (BOOL)isEmpty;

- (BBLinkedNode *)nodeForKey:(NSString *)key;
- (BBLinkedNode *)headNode;
- (BBLinkedNode *)tailNode;

@end

BBLinkedMap.m

#import "BBLinkedMap.h"

@implementation BBLinkedNode

- (instancetype)initWithKey:(NSString *)key
      value:(NSString *)value
{
 if (self = [super init]) {
  _key = key;
  _value = value;
 }
 return self;
}

+ (instancetype)nodeWithKey:(NSString *)key
      value:(NSString *)value
{
 return [[[self class] alloc] initWithKey:key value:value];
}

#pragma mark - NSCopying
- (id)copyWithZone:(nullable NSZone *)zone
{
 BBLinkedNode *newNode = [[BBLinkedNode allocWithZone:zone] init];
 newNode.key = self.key;
 newNode.value = self.value;
 newNode.prev = self.prev;
 newNode.next = self.next;
 return newNode;
}

@end

@interface BBLinkedMap ()

@property (nonatomic, strong) BBLinkedNode *headNode;
@property (nonatomic, strong) BBLinkedNode *tailNode;
@property (nonatomic, strong) NSMutableDictionary *innerMap;

@end

@implementation BBLinkedMap

- (instancetype)init
{
 self = [super init];
 if (self) {
  _innerMap = [NSMutableDictionary new];
 }
 return self;
}

#pragma mark - public
- (void)insertNodeAtHead:(BBLinkedNode *)node
{
 if (!node || node.key.length == 0) {
  return;
 }

 if ([self isNodeExists:node]) {
  return;
 }

 _innerMap[node.key] = node;

 if (_headNode) {
  node.next = _headNode;
  _headNode.prev = node;
  _headNode = node;
 } else {
  _headNode = _tailNode = node;
 }
}

- (void)insertNode:(BBLinkedNode *)node
{
 if (!node || node.key.length == 0) {
  return;
 }

 if ([self isNodeExists:node]) {
  return;
 }

 if (!_headNode && !_tailNode) {
  _headNode = _tailNode = node;
  return;
 }

 _innerMap[node.key] = node;

 _tailNode.next = node;
 node.prev = _tailNode;
 _tailNode = node;
}

- (void)insertNode:(BBLinkedNode *)newNode beforeNodeForKey:(NSString *)key
{
 if (key.length == 0 || !newNode || newNode.key.length == 0) {
  return;
 }

 if ([self isNodeExists:newNode]) {
  return;
 }

 if (!_headNode && !_tailNode) {
  _headNode = _tailNode = newNode;
  return;
 }

 BBLinkedNode *node = _innerMap[key];
 if (node) {
  _innerMap[newNode.key] = newNode;
  if (node.prev) {
   node.prev.next = newNode;
   newNode.prev = node.prev;
  } else {
   _headNode = newNode;
  }
  node.prev = newNode;
  newNode.next = node;
 } else {
  [self insertNode:newNode]; //insert to tail
 }

}

- (void)insertNode:(BBLinkedNode *)newNode afterNodeForKey:(NSString *)key
{
 if (key.length == 0 || !newNode || newNode.key.length == 0) {
  return;
 }

 if ([self isNodeExists:newNode]) {
  return;
 }

 if (!_headNode && !_tailNode) {
  _headNode = _tailNode = newNode;
  return;
 }

 BBLinkedNode *node = _innerMap[key];
 if (node) {
  _innerMap[newNode.key] = newNode;
  if (node.next) {
   newNode.next = node.next;
   node.next.prev = newNode;
  } else {
   _tailNode = newNode;
  }
  newNode.prev = node;
  node.next = newNode;
 } else {
  [self insertNode:newNode]; //insert to tail
 }
}

- (void)bringNodeToHead:(BBLinkedNode *)node
{
 if (!node) {
  return;
 }
 if (!_headNode && !_tailNode) {
  _headNode = _tailNode = node;
  return;
 }

 if ([_headNode isEqual:node]) {
  return;
 }

 if ([_tailNode isEqual:node]) {
  _tailNode = node.prev;
  _tailNode.next = nil;
 } else {
  node.prev.next = node.next;
  node.next.prev = node.prev;
 }

 _headNode.prev = node;
 node.next = _headNode;
 node.prev = nil;
 _headNode = node;
}

- (void)removeNodeForKey:(NSString *)key
{
 if (key.length == 0) {
  return;
 }

 BBLinkedNode *node = _innerMap[key];
 if (!node) {
  return;
 }

 [_innerMap removeObjectForKey:key];

 if ([_headNode isEqual:node]) {
  _headNode = node.next;
 } else if ([_tailNode isEqual:node]) {
  _tailNode = node.prev;
 }

 node.prev.next = node.next;
 node.next.prev = node.prev;

}

- (void)removeTailNode
{
 if (!_tailNode || _tailNode.key.length == 0) {
  return;
 }

 [_innerMap removeObjectForKey:_tailNode.key];
 if (_headNode == _tailNode) {
  _headNode = _tailNode = nil;
  return;
 }

 _tailNode = _tailNode.prev;
 _tailNode.next = nil;
}

- (BBLinkedNode *)nodeForKey:(NSString *)key
{
 if (key.length == 0) {
  return nil;
 }
 BBLinkedNode *node = _innerMap[key];
 return node;
}

- (BBLinkedNode *)headNode
{
 return _headNode;
}

- (BBLinkedNode *)tailNode
{
 return _tailNode;
}

- (void)readAllNode
{
 BBLinkedNode *node = _headNode;
 while (node) {
  NSLog(@"node key -- %@, node value -- %@", node.key, node.value);
  node = node.next;
 }
}

- (NSInteger)length
{
 NSInteger _len = 0;
 for (BBLinkedNode *node = _headNode; node; node = node.next) {
  _len ++;
 }
 return _len;
}

- (BOOL)isEmpty
{
 return _headNode == nil;
}

#pragma mark - private
- (BOOL)isNodeExists:(BBLinkedNode *)node
{
 BBLinkedNode *tmpNode = _headNode;
 while (tmpNode) {
  if ([tmpNode isEqual:node]) {
   return YES;
  }
  tmpNode = tmpNode.next;
 }
 return false;
}

@end

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 浅谈iOS 数据结构之链表

    链表(Linked List)是一种物理存储单元上非连续.非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的,表现形式如下图所示: 单链表 双链表 数组和链表区别: 数组:数组元素在内存上连续存放,可以通过下标查找元素:插入.删除需要移动大量元素,比较适用于元素很少变化的情况 链表:链表中的元素在内存中不是顺序存储的,查找慢,插入.删除只需要对元素指针重新赋值,效率高 Objective-C 里没有现成的链表结构,下面我实现了非线程安全的单链表和双链表,以下都是具体的实现细节,

  • 浅谈iOS开发中static变量的三大作用

    (1)先来介绍它的第一条也是最重要的一条:隐藏 当我们同时编译多个文件时,所有未加static前缀的全局变量和函数都具有全局可见性.为理解这句话,我举例来说明.我们要同时编译两个源文件,一个是a.c,另一个是main.c. 下面是a.c的内容 char a = 'A'; // global variable void msg() { printf("Hello\n"); } 下面是main.c的内容 int main(void) { extern char a; // extern v

  • 浅谈iOS应用中的相关正则及验证

    1.手机号码的验证正则 正则表达式: ^((13[0-9])|(15[^4,\\D])|(18[0,0-9]))\\d{8}$ 详细解释 解释: •^...$: ^:开始 $:结束 中间为要处理的字串 •(13[0-9]): 以13开头接下来一位为0-9之间的数 13 : 以13开头 [0-9]:分割语法,13后面是0-9之间的数 •| : 或(or), 将前后两个匹配条件进行or运算 • (15[^4\\D]) : 以15开头接下来一位是除4之外的0-9数字 15 : 以15开头 [^4\\D

  • 浅谈iOS中几个常用协议 NSCopying/NSMutableCopying

    1.几点说明 说到NSCopying和NSMutableCopying协议,不得不说的就是copy和mutableCopy. 如果类想要支持copy操作,则必须实现NSCopying协议,也就是说实现copyWithZone方法; 如果类想要支持mutableCopy操作,则必须实现NSMutableCopying协议,也就是说实现mutableCopyWithZone方法; iOS系统中的一些类已经实现了NSCopying或者NSMutableCopying协议的方法,如果向未实现相应方法的系

  • 浅谈Java数据结构之稀疏数组知识总结

    稀疏数组 当一个数组中的元素大多为0或者相同元素的时候,可以用稀疏数组来压缩 稀疏数组只记录 行row 列col 值value 将下列的二维数组转为稀疏数组,如下两图所示 1.实现二维数组转为稀疏数组的步骤: 遍历数组,得到数组中 不为0的个数,并记录为sum,作为稀疏数组第0行的 value 遍历数组,将数组中不为0的数的行和列和值分别写入稀疏数组的 row col val 中 代码实现: public class SparseArray { public static void main(S

  • 浅谈IOS屏幕刷新ADisplayLink

    什么是CADisplayLink 我们在应用中创建一个新的CADisplayLink对象,把它添加到一个runloop中,并给它提供一个target和selector在屏幕刷新的时候调用. 一但CADisplayLink以特定的模式注册到runloop之后,每当屏幕需要刷新的时候,runloop就会调用CADisplayLink绑定的target上的selector,这时target可以读到CADisplayLink的每次调用的时间戳,用来准备下一帧显示需要的数据.例如一个视频应用使用时间戳来计

  • 浅谈IOS如何对app进行安全加固

    防止 tweak 依附 通常来说,我们要分析一个 app,最开始一般是砸壳, $ DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib /path/to/XXX.app/XXX 然后将解密之后的二进制文件扔给类似 hopper 这样的反编译器处理.直接将没有砸壳的二进制文件扔个 hopper 反编译出来的内容是无法阅读的(被苹果加密了).所以说砸壳是破解分析 app 的第一步.对于这一步的防范,有两种方式. 1.限制二进制文件头内的段 通过在 Xcode 里面工程配

  • 浅谈iOS中三种生成随机数方法

    ios 有如下三种随机数方法: //第一种 srand((unsigned)time(0)); //不加这句每次产生的随机数不变 int i = rand() % 5; //第二种 srandom(time(0)); int i = random() % 5; //第三种 int i = arc4random() % 5 ; 注: ① rand()和random()实际并不是一个真正的伪随机数发生器,在使用之前需要先初始化随机种子,否则每次生成的随机数一样. ② arc4random() 是一个

  • 浅谈IOS中AFNetworking网络请求的get和post步骤

    1.首先通过第三方:CocoaPods下载AFNetworking 1.1.先找到要查找的三方库:pod search + AFNetworking 1.2.出来一堆列表页面,选择三方库最新版本命令,例如: pod 'MBProgressHUD','~>0.8'  (:q 返回) 1.3.创建工程,进入工程: cd + 工程路径 1.4.编辑工程的Podfile文件: vim Podfile 1.5.(platform :iOS, '8.0'
target "工程名" do
po

  • 浅谈iOS中的锁的介绍及使用

    在平时的开发中经常使用到多线程,在使用多线程的过程中,难免会遇到资源竞争的问题,那我们怎么来避免出现这种问题那? 线程安全是什么? 当一个线程访问数据的时候,其他的线程不能对其进行访问,直到该线程访问完毕.简单来讲就是在同一时刻,对同一个数据操作的线程只有一个.只有确保了这样,才能使数据不会被其他线程影响.而线程不安全,则是在同一时刻可以有多个线程对该数据进行访问,从而得不到预期的结果. 比如写文件和读文件,当一个线程在写文件的时候,理论上来说,如果这个时候另一个线程来直接读取的话,那么得到的结

随机推荐