JavaScriptのデータ構造[シリーズ] 05- LinkedListのリスト

JavaScriptのデータ構造[シリーズ] 05- LinkedListのリスト

CoderMonkeyコードは、道路の労働者
再現は、著者とソースを明記してください



1.鎖構造認識(単独でリンクされたリスト)

また、線形鎖構造、

  • リンクされたリストのノード構成
  • 各ノードは、ポインタフィールドと、データストレージフィールドを含みます
  • 領域表現によってノードポインタとの間の関係

以下のテクスチャappendメソッドのリファレンスリスト構造図

配列、リンクされたリストと比較すると:

  • 初期サイズを指定する必要がありません
  • 容量拡張を縮小する必要はありません
  • 高いメモリ使用量
  • 要素の挿入や削除のしやすさ

-

  • 下付き、1つの必須のプローブによって1直接アクセスすることはできません

2.一般的な方法のリスト

我々は、次の一般的なメソッドを実装します。

方法 説明
追記(データ) リストに要素を追加します。
インサート(位置データ) 指定された位置に要素を挿入するには
削除(データ) 要素を削除します
removeAt(位置) 指定された場所の要素を削除します。
アップデート(位置データ) 指定された場所の要素を更新します
getItem(位置) 指定された場所の要素を探します
indexOf(データ) 要素の位置を取得します。
サイズ() リストのサイズを取得します。
isEmpty() リストが空であるかどうかの判定
晴れ() 空のリスト
toString() 文字列化

注:現時点では、参照型の複雑さを考慮しています

3.コードの実装 

注:
ES6バージョンコードの実装は、NPMパッケージデータ構造体-jsのコードをチェックアウトがある
見つけることができるのGithub / Giteeに

NPMデータ構造体-JSをインストール

包装objectlist

/**
 * 链表:单向链表
 */
function LinkedList() {
  // 记录链表首个元素
  this.__head = null
  // 记录链表元素个数
  this.__count = 0

  // 用Node表示链表内部元素
  function Node(data) {
    this.data = data
    this.next = null

    Node.prototype.toString = function () {
      return this.data.toString()
    }
  }
}

3.1追記(データ)

分析を実現します:

  1. 空のリストに挿入すると:

新しいノードへ1.1 HEADポイントは挿入
ポイントNullに1.2次に新しいノードを

LinkedList.append1.png

  1. 非空のリストに挿入すると:

新しい要素に要素点のリストの末尾に次2.1
ヌル新しい要素次に2.2ポイント

LinkedList.append2.png

LinkedList.prototype.append = function (data) {
  // 1.创建新元素
  var newNode = new Node(data)

  // 2.1链表为空时,直接添加到末尾
  if (this.__count === 0) {
    this.__head = newNode
  }
  // 2.2链表非空时,探查到末尾元素并添加新元素
  else {
    var current = this.__head
    while (current.next) {
      current = current.next
    }
    current.next = newNode
  }

  // 3.内部计数加1
  this.__count += 1

  return true
}

注:
添加元素方法,记得最后给元素个数记录加1
通过上图示例,体会:HEAD 概念和元素节点的 Next 指向修改

3.2 insert(position, data)

实现分析:

  • 插入方法接收两个参数:位置,数据
  • 可插入位置的范围:0~length
  • 插入目标位置:0 的情况
    • 新元素的 next 指向原首位元素
    • 将HEAD指向新元素
  • 循环到指定位置
    • 期间记录上一个元素及当前元素
    • 在上一个元素与当前元素中间加入要插入的元素
    • (修改相关指向,具体参考下面代码)
  • 插入元素方法,记得最后给元素个数记录加1
LinkedList.prototype.insert = function (position, data) {
  // 1.边界检查(插入位置)
  if (position < 0 || position > this.__count) return false

  // 2.创建新元素
  var newNode = new Node(data)

  // 3.1插入到链表头部
  if (position === 0) {
    newNode.next = this.__head
    this.__head = newNode
  }
  // 3.2以外(包括插入到末尾)
  else {
    var previous = null
    var current = this.__head
    var index = 0
    while (index < position) {
      previous = current
      current = current.next
      index++
    }
    previous.next = newNode
    newNode.next = current
  }
  // 4.内部计数加1
  this.__count += 1

  return true
}

注:只有在 insert 时的 position 检查规则与其它不同

3.3 remove(data)

实现分析:

  • 删除元素方法接收一个参数:数据
  • 根据指针循环查找
  • 将从参数收到的数据与当前元素的数据进行比较
    #复杂引用类型的时候通过传入自定义比较的回调函数来解决
  • 找到指定元素后,修改上一元素的 next 指向

注意当删除第一个元素时的特殊情况(修改HEAD指向)

删除元素完成后,记得最后给元素个数记录减1

LinkedList.prototype.remove = function (data) {
  var current = this.__head
  var previous = null

  while (current) {
    // 找到指定数据的元素,让当前元素不再被引用
    if (current.data == data) {
      if (previous == null) {
        // 没有前元素,要删除的是首元素,修改 Head 指针
        this.__head = current.next
      } else {
        // 修改前元素内部指针
        previous.next = current.next
      }
      // 内部计数减1
      this.__count -= 1
      // 处理完成,返回 true
      return true
    }
    previous = current
    current = current.next
  }
  // 查找到最后没有找到指定数据的元素,返回 false
  return false

  // 注:
  // 也可以通过调用 indexOf 获取下标后再调用 removeAt 来实现
  // 只是返回值会不同,看实际需要
}

3.4 removeAt(position)

实现分析:

  • 删除指定位置元素,接收一个参数:位置下标值
  • 基于元素指向循环查找
  • 到达指定下标元素时,将其前后元素关联,即达到删除效果

删除元素完成后,记得最后给元素个数记录减1

LinkedList.prototype.removeAt = function (position) {
  // 1.边界检查
  if (position < 0 || position >= this.__count) return false

  var index = 0
  var previous = null
  var current = this.__head

  // 2.找到指定位置元素
  while (index++ < position) {
    previous = current
    current = current.next
  }
  // 3.使当前元素不再被引用
  if (previous == null) {
    // position=0 删除首元素的时候
    this.__head = current.next
  } else {
    previous.next = current.next
  }

  // 4.内部计数减1
  this.__count -= 1

  return current.data
}

3.5 update(position, data)

实现分析:参看注释

LinkedList.prototype.update = function (position, data) {
  // 1.边界检查
  if (position < 0 || position >= this.__count) return false

  var current = this.__head
  var index = 0

  // 2.找到指定位置元素
  while (index++ < position) {
    current = current.next
  }
  // 3.修改当前元素数据
  current.data = data

  // 4.修改完成,返回 true
  return true
}

3.6 getItem(position)

获取指定位置元素的值

LinkedList.prototype.getItem = function (position) {
  // 边界检查
  if (position < 0 || position >= this.__count) return

  var index = 0
  var current = this.__head

  while (index < position) {
    current = current.next
    index += 1
  }
  return current.data
}

3.7 indexOf(data)

实现分析:

  • 获取元素所在位置下标值方法,接收一个参数:元素的数据
  • 根据元素 next 指向循环查找
  • 找到时返回当前下标
  • 找不到时返回 -1
LinkedList.prototype.indexOf = function (data) {
  var current = this.__head
  var index = 0

  while (current) {
    if (current.data == data) {
      return index
    }
    current = current.next
    index += 1
  }
  return -1
}

3.8 size()

查看元素个数方法

    LinkedList.prototype.size = function () {
        return this.__count
    }

3.9 isEmpty()

判空方法

LinkedList.prototype.isEmpty = function () {
  return this.__count === 0
}

3.10 clear()

实现分析:
Head指向置空
计数清零

LinkedList.prototype.clear = function () {
  this.__head = null
  this.__count = 0
}

3.11 toString()

为了方便查看实现的字符串化方法

LinkedList.prototype.toString = function () {
  var str = '[HEAD] -> '
  var current = this.__head
  while (current) {
    str += current.data + ' -> '
    current = current.next
  }
  if (str === '[HEAD] -> ') {
    str = '[HEAD] -> Null'
  }
  return str
}

总结两点:

  • 位置指標値に関連するオペレーションと、
    それはサイクルを通じてインデックス値を見つけることです、

添字なしリスト構造の配列自体とは異なり。

  • 全ての方法は、インデックス値は、受信
    前記インサートが等しい長さであってもよい場合、境界をチェックするために行われるべきです

3.12完全なコード

/**
 * 链表:单向链表
 */
function LinkedList() {
  // 记录链表首个元素
  this.__head = null
  // 记录链表元素个数
  this.__count = 0

  // 用Node表示链表内部元素
  function Node(data) {
    this.data = data
    this.next = null

    Node.prototype.toString = function () {
      return this.data.toString()
    }
  }

  /**
   * 添加节点
   */
  LinkedList.prototype.append = function (data) {
    // 1.创建新元素
    var newNode = new Node(data)

    // 2.1链表为空时,直接添加到末尾
    if (this.__count === 0) {
      this.__head = newNode
    }
    // 2.2链表非空时,探查到末尾元素并添加新元素
    else {
      var current = this.__head
      while (current.next) {
        current = current.next
      }
      current.next = newNode
    }

    // 3.内部计数加1
    this.__count += 1

    return true
  }

  /**
   * 插入节点
   */
  LinkedList.prototype.insert = function (position, data) {
    // 1.边界检查(插入位置)
    if (position < 0 || position > this.__count) return false

    // 2.创建新元素
    var newNode = new Node(data)

    // 3.1插入到链表头部
    if (position === 0) {
      newNode.next = this.__head
      this.__head = newNode
    }
    // 3.2以外(包括插入到末尾)
    else {
      var previous = null
      var current = this.__head
      var index = 0
      while (index < position) {
        previous = current
        current = current.next
        index++
      }
      previous.next = newNode
      newNode.next = current
    }
    // 4.内部计数加1
    this.__count += 1

    return true
  }

  /**
   * 删除节点
   */
  LinkedList.prototype.remove = function (data) {
    var current = this.__head
    var previous = null

    while (current) {
      // 找到指定数据的元素,让当前元素不再被引用
      if (current.data == data) {
        if (previous == null) {
          // 没有前元素,要删除的是首元素,修改 Head 指针
          this.__head = current.next
        } else {
          // 修改前元素内部指针
          previous.next = current.next
        }
        // 内部计数减1
        this.__count -= 1
        // 处理完成,返回 true
        return true
      }
      previous = current
      current = current.next
    }
    // 查找到最后没有找到指定数据的元素,返回 false
    return false

    // 注:
    // 也可以通过调用 indexOf 获取下标后再调用 removeAt 来实现
    // 只是返回值会不同,看实际需要
  }

  /**
   * 删除指定位置节点
   */
  LinkedList.prototype.removeAt = function (position) {
    // 1.边界检查
    if (position < 0 || position >= this.__count) return false

    var index = 0
    var previous = null
    var current = this.__head

    // 2.找到指定位置元素
    while (index++ < position) {
      previous = current
      current = current.next
    }
    // 3.使当前元素不再被引用
    previous.next = current.next

    // 4.内部计数减1
    this.__count -= 1

    return current.data
  }

  /**
   * 更新节点
   */
  LinkedList.prototype.update = function (position, data) {
    // 1.边界检查
    if (position < 0 || position >= this.__count) return false

    var current = this.__head
    var index = 0

    // 2.找到指定位置元素
    while (index++ < position) {
      current = current.next
    }
    // 3.修改当前元素数据
    current.data = data

    // 4.修改完成,返回 true
    return true
  }

  /**
   * 获取指定位置节点
   */
  LinkedList.prototype.getItem = function (position) {
    // 边界检查
    if (position < 0 || position >= this.__count) return

    var index = 0
    var current = this.__head

    while (index < position) {
      current = current.next
      index += 1
    }
    return current.data
  }

  /**
   * 获取节点位置下标
   */
  LinkedList.prototype.indexOf = function (data) {
    var current = this.__head
    var index = 0

    while (current) {
      if (current.data == data) {
        return index
      }
      current = current.next
      index += 1
    }
    return -1
  }

  /**
   * 获取链表长度
   */
  LinkedList.prototype.size = function () {
    return this.__count
  }

  /**
   * 是否为空链表
   */
  LinkedList.prototype.isEmpty = function () {
    return this.__count === 0
  }

  /**
   * 清空链表
   */
  LinkedList.prototype.clear = function () {
    this.__head = null
    this.__count = 0
  }

  LinkedList.prototype.toString = function () {
    var str = '[HEAD] -> '
    var current = this.__head
    while (current) {
      str += current.toString() + ' -> '
      current = current.next
    }
    if (str === '[HEAD] -> ') {
      str = '[HEAD] -> Null'
    }
    return str
  }
}

4.テスト

// ---------------------------------------------
// Test: LinkedList
// ---------------------------------------------
console.log('----Test: LinkedList----')

var lst = new LinkedList()

lst.append('a')
lst.append('b')
lst.append('c')
console.log(lst.toString())
lst.insert(1, 'insert-1')
console.log(lst.toString())
lst.insert(4, 'insert-4')
console.log(lst.toString())
lst.insert(0, 'insert-0')
console.log(lst.toString())
lst.remove('c')
console.log(lst.toString(), 'remove-c')
console.log('indexOf-b : ', lst.indexOf('b'))
lst.update(3, 'b-updated')
console.log('update-b : ', lst.toString())
lst.removeAt(3)
console.log('after removeAt(3) : ', lst.toString())
lst.clear()
console.log('after clear : ', lst.toString())

出力を表示します。

----Test: LinkedList----
[HEAD] -> a -> b -> c -> 
[HEAD] -> a -> insert-1 -> b -> c -> 
[HEAD] -> a -> insert-1 -> b -> c -> insert-4 -> 
[HEAD] -> insert-0 -> a -> insert-1 -> b -> c -> insert-4 -> 
[HEAD] -> insert-0 -> a -> insert-1 -> b -> insert-4 ->  remove-c
indexOf-b :  3
update-b :  [HEAD] -> insert-0 -> a -> insert-1 -> b-updated -> insert-4 -> 
after removeAt(3) :  [HEAD] -> insert-0 -> a -> insert-1 -> insert-4 -> 
after clear :  [HEAD] -> Null

結果は正しいです。
一日、それを呼び出します。


NPMは、ツールキットを行いdata-struct-js
、ES6が実装JavaScriptのデータ構造に基づいて
小さな車輪がほとんど使用されませんが、
おそらく少しの助けになりますJavaScriptを学ぶため、初心者のために。
単にあなたが、興味のある缶はまたに行くことができるか、インストール
のGitHub / Giteeのソースコードを見て。(スター表のサポート〜)

npm install data-struct-js --save-dev

https://github.com/CoderMonkie/data-struct-js
https://gitee.com/coder-monkey/data-struct-js

最後に、〜読書とサポートに感謝します


-終わり-

おすすめ

転載: www.cnblogs.com/CoderMonkie/p/js-data-struct-linkedlist.html