Структура данных Angry Liver JavaScript — связанный список (2)

Привыкайте писать вместе! Это 11-й день моего участия в «Новом ежедневном плане Nuggets · Апрельское задание по обновлению», нажмите, чтобы просмотреть подробности мероприятия .

Всем привет, меня зовут Ян Чэнгун.

push В прошлой статье мы представили концепцию связанного списка, а  затем реализовали removeAt два метода. Хотя эти два метода являются лишь основными функциями, идеи реализации очень важны. Поскольку вы понимаете принципы этих двух методов, вы можете понять, как связанный список реализует «упорядоченную коллекцию».

Если у вас все еще кружится голова, сначала прочитайте предыдущую статью: Структура данных Angry Liver JavaScript — связанный список (1)

Код, реализованный в предыдущей статье, выглядит следующим образом:

class Node {
  constructor(value) {
    this.value = value;
    this.next = undefined;
  }
}

class linkedList {
  constructor() {
    this.count = 0;
    this.head = undefined;
  }
  push(item) {
    // 向末尾添加元素
  }
  removeAt(index) {
    // 移除指定位置的元素
  }
}
复制代码

Давайте продолжим эту часть и продолжим улучшать функцию связанного списка.

Метод идеального связанного списка

Методы, которые необходимо реализовать в связанном списке, следующие:

  • getItemAt: Получить элемент в определенной позиции в связанном списке.
  • insert: вставить элемент в определенную позицию в связанном списке.
  • indexOf: возвращает индекс элемента в связанном списке
  • remove: удалить элемент из связанного списка
  • isEmpty: определить, является ли связанный список пустым
  • size: определить длину связанного списка
  • toString: возвращает строку всех элементов связанного списка.

метод getItemAt

Метод getItemAt предназначен для получения элемента под определенным индексом в связанном списке. Он имеет один параметр, indexпредставляющий индекс.

Значение  index представляет собой числовое значение, но диапазон значений должен быть больше или равен нулю и меньше или равен длине связанного списка, чтобы индекс мог быть допустимым индексом в связанном списке.

На самом деле, этот метод относительно прост, если он зацикливается до тех пор, пока не будет найден целевой элемент.

getItemAt(index) {
  if(index >= 0 && index <= this.count) {
    let current = this.head
    for(let i = 0; i < index; i++) {
      current = current.next
    }
    return current
  }
  return undefined;
}
复制代码

Если элемент не найден, вернуть undefined напрямую.

метод вставки

Роль метода вставки заключается в том, чтобы вставить элемент в любую позицию связанного списка. Он имеет два параметра, первый параметр itemуказывает элемент, который нужно вставить, а второй параметр indexуказывает позицию для вставки элемента.

indexИндекс здесь такой же, как индекс в методе getItemAt выше, и логика оценки также такая же.Убедитесь, что параметр индекса находится в допустимом диапазоне.

Код реализации выглядит следующим образом:

insert(item, index) {
  if(index >= 0 && index <= this.count) {
    let node = new Node(item)
    let current = this.head;
    if(index == 0) {
      node.next = current
      this.head = node
    } else {
      let previous = this.getItemAt(index - 1)
      current = previous.next
      node.next = current
      previous.next = node
    }
    this.count++;
    return true;
  }
  return false;
}
复制代码

代码中,发现和上一篇的 removeAt 方法有一个共同点,就是先要判断 index 是否为 0,然后再分情况处理。

如果为零,则只需要新建一个元素,将新元素的 next 指向原来的表头,然后再将 head 属性赋值为新元素即可。

如果大于零,则需要获取当前元素 current 和前一个元素 previous。前一个元素直接用上面写的 getItemAt 方法获取即可。

接着将新元素的 next 指向索引位置的元素,再将前一个元素的 next 属性指向新元素,这样就在两个元素 previous 和 current 之间链接了新元素。

最后,再将表示链表长度的 count 属性自增一。

indexOf 方法

indexOf 方法与数组的同名方法作用是一样的,参数是一个元素,然后在链表中寻找这个元素的位置,找到就返回索引,找不到返回 -1

这里有一个关键点:元素参数要与链表中的参数做对比,判断是否相等。如果元素是基本类型,那直接判断等于即可。如果元素是引用类型,则不同数据的判断方式不同,就要自定义判断的方法了。

所以我们要修改下 linkedList 类,添加一个自定义方法,接受类初始化时的传参:

class linkedList {
  constructor(whereFn) {
    let defun = (value, next)=> value === next;
    this.equalFn = whereFn || defun
  }
}
复制代码

这里的参数 whereFn 就是一个自定义的对比元素的函数。

有了 equalFn 属性,indexOf 方法就好实现了:

indexOf(item) {
  let current = this.head;
  for(let i = 0; i < this.count; i++) {
    if(this.equalFn(item, current.value)) {
      return i;
    }
    current = current.next;
  }
  return -1;
}
复制代码

循环便利,用自定义的方法判断两个元素是否相等,相等则终止循环返回索引。

remove 方法

remove 方法的作用是删除一个元素,参数直接是这个元素,需要我们在链表中找到并删除。

有了上面的 indexOf 方法,remove 方法实现起来就更简单了:

remove(item) {
  let index = this.indexOf(item);
  return this.removeAt(index)
}
复制代码

isEmpty, size 方法

这几个方法更简单:

isEmpty() {
  return this.count == 0
}
size() {
  return this.count;
}
复制代码

метод toString

Метод toString, как и одноименный метод массива, помещает все элементы в строку, разделенную запятыми.

Вот реализация кода:

toString() {
  if(!this.head) {
    return ''
  }
  let current = this.head
  let string = current.value
  for(let i = 0; i < this.count; i++) {
    string += `,${current.value}`
    current = current.next
  }
  return string
}
复制代码

На самом деле, логика также заключается в длине кругового связанного списка, а затем в склеивании строк.

использовать связанный список

Полный код связанного списка относительно длинный, я поместил его в онлайн-адрес, пожалуйста, нажмите онлайн- тест

Сначала создайте экземпляр, добавьте два элемента:

let linked = new linkedList();
linked.push("北京");
linked.push("上海");
console.log(linked.toString()); // 北京,上海
复制代码

Затем вставьте Shenzhen в 1позицию :

linked.insert('深圳', 1)
console.log(linked.toString()); // 北京,深圳,上海
复制代码

Затем посмотрите на индекс элемента:

console.log(linked.indexOf('上海')); // 2
console.log(linked.indexOf('武汉')); // -1
复制代码

Наконец удалите элемент:

linked.remove('深圳');
console.log(linked.toString()); // 北京,上海
复制代码

Получилось идеально, и все готово!

Подведем итог

После прочтения этой статьи связанный контент связанного списка закончился. Фактически, после изучения связанных списков связанные списки являются очень хорошей альтернативой проблемам производительности массивов, с которыми мы сталкивались ранее.

Размещенный в тексте код рекомендуется набирать вручную, чтобы уловить суть.

Источником статьи является официальный аккаунт: Programmer Success . Это 10-я статья по изучению структур данных и алгоритмов JavaScript. Эта серия будет обновляться в течение месяца подряд. Добро пожаловать, чтобы обратить внимание на официальный аккаунт и нажмите « Добавить группу », чтобы присоединиться к нашей учебной команде ~

рекомендация

отjuejin.im/post/7085747191805345800