链表

数据结构和算法,和语言是无关的

单向链表

  • 既然有数组为什么用链表
    • 数组的创建需要申请一段连续的内存空间(一整块的内存),并且大小是固定的(大多数编程语言数组都是固定的),所以如果当前数组不能满足容量需求时,需要扩容。(一般情况是申请一个更大的数组,比如2倍,然后将原数组中的元素复制过去)
    • 而且在数组开头或中间位置插入数据的成本很高,需要进行大量元素位移
    • 为了解决上面的问题,我们需要链表这种数据结构
  • 特点
    • 不同于数组,链表中的元素在内存中不必是连续的空间
    • 链表的每个元素由一个存储元素本身的节点,和一个指向下一个元素的引用(有些语言称为指针)组成
  • 相较于数组的优点
    • 内存空间不必是连续的,可以充分利用计算机的内存。实现灵活的动态管理
    • 链表不必在创建时就确定大小,并且大小可以无限的延伸下去
    • 链表在插入和删除数据时,时间复杂度可以达到O(1),相对数组效率高很多
  • 相较于数组的缺点
    • 链表访问任何一个位置的元素,都需要从头开始访问。(无法跳过第一个元素访问任何其他元素)
    • 无法通过下标直接访问元素,需要从头一个个访问,直到找到对应元素
  • 单向链表封装
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    /**
    * 声明节点对象
    */
    function Node(element) {
    // 保存元素
    this.element = element;
    // 保存指针(指向下一个节点)
    this.next = null;
    }
    /**
    * 声明链表
    */
    function LinkedList() {
    // 链表头
    this.head = null;
    // 链表长度
    this.length = 0;
    // append(element) 向链表尾部追加元素
    this.append = function(element) {
    // 1.根据element创建Node对象
    var newNode = new Node(element);
    // 2.追加到最后
    if (!this.head) {
    // 节点不存在的时候
    this.head = newNode;
    } else {
    // 节点存在的时候,从Head依次找到最后一个节点
    var current = this.head;
    while(current.next) {
    current = current.next;
    }
    // 将最后一个节点的next指向新创建的Node就可以
    current.next = newNode;
    }
    // length
    this.length++;
    }
    // insert(position, element) 向链表的特定位置插入某一个元素
    this.insert = function (position, element) {
    // 1.判断越界
    if (position < 0 || position > this.length) {
    return false;
    }
    // 2. 创建新的节点
    var newNode = new Node(element);
    // 3. 插入元素
    if (position === 0) {
    // 插入到头部的时候
    newNode.next = this.head;
    this.head = newNode;
    } else {
    var index = 0;
    var current = this.head;
    var previous = null;
    while(index++ < position) {
    previous = current;
    current = current.next;
    }
    previous.next = newNode;
    newNode.next = current;
    }
    this.length++;
    return true;
    }
    // get(position) 获取对应位置的元素
    this.get = function (position) {
    // 1.判断越界
    if (position < 0 || position > this.length - 1) {
    return null;
    }
    // 2. 查找元素
    var index = 0;
    var current = this.head;
    while (index++ < position) {
    current = current.next;
    }
    return current.element;
    }
    // indexOf(element) 返回元素在列表中的索引。如果列表中没有该元素,则返回-1
    this.indexOf = function (element) {
    // 1. 获取第一个元素
    var current = this.head;
    var index = 0;
    while(current) {
    if (current.element === element) {
    return index;
    }
    current = current.next;
    index++;
    }
    return -1;
    }
    // update(position, element) 修改某个位置的元素
    this.update = function (position, element) {
    // 1.remove
    var result = this.removeAt(position);
    // 2.insert
    this.insert(position, element);
    return result;
    }
    // removeAt(position) 从列表指定位置移除一项
    this.removeAt = function (position) {
    // 1.判断越界
    if (position < 0 || position > this.length - 1) {
    return null;
    }
    // 2.删除元素
    var current = this.head;
    var previous = null;
    var index = 0;
    if (position === 0) {
    this.head = current.next;
    } else {
    while (index++ < position) {
    previous = current;
    current = current.next;
    }
    // 到这里说明已经找到要删除的元素
    previous.next = current.next;
    }
    this.length--;
    // 返回删除的元素
    return current.element;
    }
    // remove(element) 从列表中移除一项
    this.remove = function (element) {
    // 1.获取删除元素的位置
    var index = this.indexOf(element);
    if (index === -1) return;
    // 2.删除元素
    var result = this.removeAt(index);
    return result
    }
    // isEmpty() 链表不包含任何元素,返回true
    this.isEmpty = function () {
    return this.length === 0;
    }
    // size() 链表中元素个数
    this.isEmpty = function () {
    return this.length;
    }
    }

双向链表