数据结构与算法之链表(三)

111 阅读3分钟
原文链接: www.jianshu.com
一 链表

链表是一种链式存储的线性表,所有元素的内存地址不一定是连续的

特点

  • 动态数组有个明显的缺点,可能会造成内存空间的大量浪费
  • 链表可以做到用到多少内存就申请多少内存
image.png
二 自定义链表的实现

定义一个数据结构基本操作的基类

  • List.h - 主要声明了数据操作的一些基本方法,只声明,实现交由子类完成
/// 数据结构基类
@interface List : NSObject

/**
 * 清除所有元素
 */
- (void)clear;

/**
 * 元素的数量
 * @return int
 */
- (int)size;

/**
 * 是否为空
 * @return bool
 */
- (bool)isEmpty;

/**
 * 是否包含某个元素
 * @param element
 * @return bool
 */
- (bool)contains:(id)element;

/**
 * 添加元素到尾部
 * @param element
 */
- (void)add:(id)element;

/**
 * 获取index位置的元素
 * @param index
 * @return id
 */
- (id)get:(NSUInteger)index;

/**
 * 设置index位置的元素
 * @param index
 * @param element
 * @return 原来的元素ֵ
 */
- (id)set:(NSUInteger)index element:(id)element;

/**
 * 在index位置插入一个元素
 * @param index
 * @param element
 */
- (void)add:(NSUInteger)index element:(id)element;

/**
 * 删除index位置的元素
 * @param index
 * @return
 */
- (id)remove:(NSUInteger)index;

/**
 * 查看元素的索引
 * @param element
 * @return
 */
- (NSUInteger)indexOf:(id)element;

链表的基类 - 主要完成链表的一些公共操作,继承自List

  • AbstractList.h
/// 链表 抽象基类
@interface AbstractList : List

/** size*/
@property(nonatomic,assign)NSUInteger size;

/// 越界查询
- (bool)rangeCheck:(NSUInteger)index;

/// 添加元素越界检查
- (bool)rangeCheckForAdd:(NSUInteger)index;

@end
  • AbstractList.m
/// 数量
- (NSUInteger)size {
    return _size;
}

/// 是否为空
- (bool)isEmpty {
    return _size == 0;
}

/// 是否包含某个元素
- (bool)contains:(id)element {
    return [self indexOf:element] != NSNotFound;
}

/// 添加元素到尾部
- (void)add:(id)element {
    [self add:_size element:element];
}

#pragma mark - pprivate

- (void)outOfBounds:(NSUInteger)index {
    NSLog(@"index:%lu, size:%lu",(unsigned long)index,(unsigned long)_size);
}

/// 越界查询
- (bool)rangeCheck:(NSUInteger)index {
    if (index < 0 || index >= _size) {
        [self outOfBounds:index];
        return YES;
    }
    return NO;
}

- (bool)rangeCheckForAdd:(NSUInteger)index {
    if (index < 0  || index > _size) {
        [self outOfBounds:index];
        return YES;
    }
    return NO;
}

声明一个链表

  • LinkedList.h
/// 链表
@interface LinkedList : AbstractList

/** first*/
@property(nonatomic,strong)LinkNode *first;

/** last*/
@property(nonatomic,strong)LinkNode *last;

/**
 * 获取index位置对应的节点对象
 * @param index
 * @return
 */
- (LinkNode *)node:(NSUInteger)index;

@end
  • LinkedList.m
- (void)clear {
    self.size = 0;
    _first = nil;
}

- (id)get:(NSUInteger)index {
    return [self node:index];
}

- (id)set:(NSUInteger)index element:(id)element {
    LinkNode *node = [self node:index];
    id oldElement  = node.element;
    node.element = element;
    return oldElement;
}

- (void)add:(NSUInteger)index element:(id)element {
    if (index == 0) {
        _first = [[LinkNode alloc] initWithElement:element next:_first];
    } else {
        LinkNode *prevNode = [self node:index - 1];
        prevNode.next = [[LinkNode alloc] initWithElement:element next:prevNode.next];
    }
    self.size++;
}

- (id)remove:(NSUInteger)index {
    LinkNode *node = _first;
    if (index == 0) {
        _first = _first.next;
    } else {
        LinkNode *prev = [self node:index - 1];
        node = prev.next;
        prev.next = node.next;
    }
    self.size--;
    return node.element;
}

- (NSUInteger)indexOf:(id)element {
    if (element == nil) {   // 返回节点中第一个出现元素为空的节点
        LinkNode *node = _first;
        for (NSUInteger i = 0; i < self.size; i++) {
            if (node.element == nil) {
                return i;
            }
            node = node.next;
        }
    } else {
        LinkNode *node = _first;
        for (NSUInteger i = 0; i < self.size; i++) {
            if (node.element == element) {
                return i;
            }
            node = node.next;
        }
    }
    
    return NSNotFound;
}

///  获取index位置对应的节点对象
- (LinkNode *)node:(NSUInteger)index {
    if ([self rangeCheck:index]) {
        return nil;
    }
    
    LinkNode *node = _first;
    for (int i = 0; i < index; i++) {
        node = node.next;
    }
    
    return node;
}

/// 打印整个链表
- (NSString *)toString {
    NSMutableString *strM = [NSMutableString string];
    [strM appendString:[NSString stringWithFormat:@"size = %lu",self.size]];
    [strM appendString:@" ["];
    
    LinkNode *node = _first;
    for (int i = 0; i < self.size; i++) {
        if (i != 0) {
            [strM appendString:@", "];
        }
        [strM appendString:[NSString stringWithFormat:@"%@",node.element]];
        node = node.next;
    }
    [strM appendFormat:@"]"];
    return strM.copy;
}

/// 重新系统的方法
- (NSString *)description {
    [super description];
    NSMutableString *strM = [NSMutableString string];
    [strM appendString:[NSString stringWithFormat:@"size = %lu",self.size]];
    [strM appendString:@" ["];
    
    LinkNode *node = _first;
    for (int i = 0; i < self.size; i++) {
        if (i != 0) {
            [strM appendString:@", "];
        }
        [strM appendString:[NSString stringWithFormat:@"%@",node.element]];
        node = node.next;
    }
    [strM appendFormat:@"]"];
    return strM.copy;
}
@end

测试验证

- (void)linkedListText {
    LinkedList *list = [[LinkedList alloc] init];
    [list add:@20];
    [list add:0 element:NULL];
    [list add:@30];
    [list add:[list size] element:@40];
    [list remove:1];
    NSLog(@"%@",list.description);
    
    [list clear];
    NSLog(@"%@",list.description);
}

运行结果

image.png
三 重要方法解释说明
3.1 添加元素
- (void)add:(id)element;
image.png
3.2 删除元素
- (id)remove:(NSUInteger)index;
image.png

本文参考 MJ老师的 恋上数据结构与算法


本人技术水平有限,如有错误欢迎指正。
书写整理不易,您的打赏点赞是对我最大的支持和鼓励,欢迎点赞打赏。


项目连接链接 - 03_LinkedList