iOS之数据库及数据结构与算法算法与数据结构移动开发作家群(719776724)分享专题

iOS 数据结构之单向链表

2018-08-04  本文已影响50人  大兵布莱恩特

链表 ,数组 是我们经常碰到的线性数据结构, 是一种真正的动态数据结构 ,而数组是一段连续的内存空间,通过指针偏移去取数组里相邻的数据,而链表是将不同的内存空间,连在在一起,类似于我们生活中常见的火车车厢,每节车厢就可以看做是一个数据,只不过这个数据内部还有个指针指向它下一个节点的数据.

image.png

因此链表需要有个头节点 ,可以方便的进行查询 添加 移除等操作,小编通过学习链表这种数据结构的特点,用 Objective-C 语言实现了一个单向链表,即只有一个头节点 最后一个节点为 NULL.


//
//  LinkedList.h
//  ArrayList
//
//  Created by dzb on 2018/8/3.
//  Copyright © 2018 大兵布莱恩特. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface LinkedList <ObjectType> : NSObject

- (void) addObjectAtFirst:(ObjectType)object;

- (void) addObjectAtLast:(ObjectType)object;

- (void) addObject:(ObjectType)object atIndex:(NSInteger)index;

- (void) updateObject:(ObjectType)object atIndex:(NSInteger)index;

- (BOOL) containObject:(ObjectType)object;

- (ObjectType) objectAtIndex:(NSInteger)index;

- (ObjectType) removeObjectAtIndex:(NSInteger)index;

- (ObjectType) removeFirstObject;

- (ObjectType) removeLastObject;

///count
@property (nonatomic,assign) NSInteger count;
///empty
@property (nonatomic,assign,getter=isEmpty,readonly) BOOL empty;
///firstObject
@property (nonatomic,strong,readonly) ObjectType firstObject;
///lastObject
@property (nonatomic,strong,readonly) ObjectType lastObject;

@end

//
//  LinkedList.m
//  ArrayList
//
//  Created by dzb on 2018/8/3.
//  Copyright © 2018 大兵布莱恩特. All rights reserved.
//

#import "LinkedList.h"

typedef void* AnyObject;

typedef struct node {
    AnyObject data;
    struct node *next;
} Node;

@interface LinkedList ()

///head
@property (nonatomic,assign) Node *dummyHead;
///size
@property (nonatomic,assign) NSInteger size;

@end

@implementation LinkedList

- (instancetype)init
{
    self = [super init];
    if (self) {
        Node * dummyHead = (Node*)malloc(sizeof(Node));
        dummyHead->data = nil;
        dummyHead->next = nil;
        self.dummyHead = dummyHead;
        self.size = 0;
    }
    return self;
}

- (void)addObjectAtFirst:(id)object {
    [self addObject:object atIndex:0];
}

- (void)addObjectAtLast:(id)object {
    [self addObject:object atIndex:self.size];
}

- (void)addObject:(id)object atIndex:(NSInteger)index {
    if (index < 0 || index > self.count) {
        @throw [NSException exceptionWithName:@"LinkedList is out of bounds" reason:@"Add failed. Illegal index." userInfo:nil];
        return;
    }
    Node *prev = self.dummyHead;
    for (int i = 0; i< index; i++) {
        prev = prev->next;
    }
    Node *cur = (Node*)malloc(sizeof(Node));
    cur->data = (__bridge_retained AnyObject)object;
    cur->next = prev->next;
    prev->next = cur;
    self.size++;
}

- (id)objectAtIndex:(NSInteger)index {
    if (index < 0 || index >= self.count) {
        @throw [NSException exceptionWithName:@"LinkedList is out of bounds" reason:@"Add failed. Illegal index." userInfo:nil];
        return nil;
    }
    Node *cur = self.dummyHead->next;
    for (int i = 0; i<index; i++) {
        cur = cur->next;
    }
    return (__bridge_transfer id)cur->data;
}

- (id)firstObject {
    return [self objectAtIndex:0];
}

- (id)lastObject {
    return [self objectAtIndex:self.count-1];
}

- (void)updateObject:(id)object atIndex:(NSInteger)index {
    if (index < 0 || index >= self.count) {
        @throw [NSException exceptionWithName:@"LinkedList is out of bounds" reason:@"Add failed. Illegal index." userInfo:nil];
        return;
    }
    Node *cur = self.dummyHead->next;
    for (int i = 0; i<index; i++) {
        cur = cur->next;
    }
    CFRelease(cur->data);
    cur->data = (__bridge_retained AnyObject)object;
}

- (BOOL)containObject:(id)object {
    Node *cur = self.dummyHead->next;
    while (cur != NULL) {
        id data = (__bridge_transfer id)cur->data;
        if ([data isEqual:object])
            return YES;
        cur = cur->next;
    }
    return NO;
}


- (id) removeObjectAtIndex:(NSInteger)index {
    if (index < 0 || index >= self.count) {
        @throw [NSException exceptionWithName:@"LinkedList is out of bounds" reason:@"Add failed. Illegal index." userInfo:nil];
        return nil;
    }
    Node *prev = self.dummyHead;
    for (int i = 0; i<index; i++) {
        prev = prev->next;
    }
    Node *deleteNode = prev->next;
    prev->next = deleteNode->next;
    id object = (__bridge_transfer id)deleteNode->data;
    free(deleteNode);
    deleteNode = NULL;
    self.size--;
    return object;
}

- (id) removeFirstObject {
    return [self removeObjectAtIndex:0];
}

- (id) removeLastObject {
    return [self removeObjectAtIndex:self.count-1];
}

- (NSInteger)count {
    return self.size;
}

- (NSString *)description {
    
    NSMutableString *string = [NSMutableString stringWithFormat:@"\nLinkedList %p : [ \n" ,self];
    Node *cur = self.dummyHead->next;
    while (cur != nil) {
        [string appendFormat:@"%@ -> \n",cur->data];
        cur = cur->next;
    }
    [string appendString:@"NULL\n"];
    [string appendString:@"]\n"];
    
    return string;
}

- (BOOL)isEmpty {
    return self.count == 0;
}

- (void)dealloc
{
    while (self.count != 0) {
        [self removeFirstObject];
    }
    
}
@end

整个链表才有了头插法往链表里插入一个新的元素,即新来的元素插入到头节点位置, 当创建一个空链表时候 链表的头节点为一个空的 Node ,即 Node->data 和 Node->next 都为 NULL, 这样以后可要根据这个头节点往下查找每个节点的数据,进行增加 删除 修改 和查找的操作. 并管理了对象的引用计数 ,当链表销毁时会对内部的每一个节点进行释放内存的操作,并对节点内管理的对象引用计数进行-1操作,以保证存入链表的 OC 对象能够完美释放内存.

下边是测试用例


- (void) test {
    static int count = 0;
    if (count > 9) {
        [_timer invalidate];
        _timer = nil;
        NSLog(@"time is %@",[_timeArray valueForKeyPath:@"@avg.self"]);
        return;
    }

    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
        int number = 100000;
        Person *p = [Person new];
        LinkedList <Person *> *linked = [[LinkedList alloc] init];
        for (int i = 0; i<number; i++) {
            [linked addObjectAtFirst:p];
        }
        CFAbsoluteTime linkTime = (CFAbsoluteTimeGetCurrent() - startTime);
        CFTimeInterval duration = linkTime * 1000.0f;
        NSLog(@"Linked in %f ms",duration);
        [self->_timeArray addObject:@(duration)];
        count++;
    });
    
}



image.png

往链表里添加10万个 同一个 person 对象 ,实质就是对 person 的引用计数+1 ,当链表销毁时候 再对同一个 person 对象执行 移除操作 ,使其引用计数为 0 ,Person 对象才会立马销毁

好了,我是大兵布莱恩特,欢迎加入博主技术交流群,iOS 开发交流群

QQ20180712-0.png
上一篇下一篇

猜你喜欢

热点阅读