JavaScriptでチェーン操作を実現する-10 Move Node In-place


TL;DR
一つのチェーンの最初のノードを別のチェーンに移動します.(チェーンの参照を変えません.)シリーズのディレクトリは前書きとディレクトリに会います.
需要
一つのmoveNode()関数を実現して、ソースチェーンの頭の接合点をターゲットチェーンの先頭に移動します.二つのチェーンの参照は修正できないことが要求されます.
var source = 1 -> 2 -> 3 -> null
var dest = 4 -> 5 -> 6 -> null
moveNode(source, dest)
source === 2 -> 3 -> null
dest === 1 -> 4 -> 5 -> 6 -> null
以下の場合は異常を投げ出すべきです.
  • ソースチェーンはnull
  • です.
  • ターゲットチェーンはnull
  • です.
  • ソース・チェーンは空のノードであり、data属性がnullのノードは空のノードとして定義されている.
  • 前のkataとは違って、このkataは引用を変えずに2つのチェーン自体を修正しました.したがって、moveNode()関数は、戻り値を必要としない.また、このkataは空ノードの概念も提案している.空ノードは、ターゲットチェーンが空の場合(参照を保持するため)に使用され、関数が実行されると、ターゲットチェーンは空ノードから一つのノードを含むチェーンテーブルに変化します.
    最初のkataのpushメソッドを使用することができます.
    最良の案
    このアルゴリズムは、リンクノードの挿入と削除を考える.基本的にはsourceとdestだけを一回ずつ操作しますので、再帰と循環を区別する必要はありません.大体の考えは次の通りです
  • は、sourceに対して、ノードを削除する動作を行う.ノードが一つしかないなら、そのまま空にします.複数のノードがある場合は、第2のノードの値をヘッドノードに割り当て、その後、第3のノードをノードの先頭にノードを指す.
  • は、destにノードを挿入する動作をする.頭の結点が空なら直接に値を付けます.そうでないと、頭の結点をコピーして、第二のノードとしてチェーンに挿入して、新しい値を頭の結点に割り当てます.
  • コードは以下の通りです
    function moveNode(source, dest) {
      if (!source || !dest || source.data === null) throw new Error("invalid arguments")
    
      const data = source.data
    
      if (source.next) {
        source.data = source.next.data
        source.next = source.next.next
      } else {
        source.data = null
      }
    
      if (dest.data === null) {
        dest.data = data
      } else {
        dest.next = new Node(dest.data, dest.next)
        dest.data = data
      }
    }
    再帰案
    これは私が最初に考えたスキームであり、違いはdestにどのように新しいノードを挿入する処理に再帰的に使用されたかである.考え方は、すべてのノードのdataを後に1つ移動し、すなわち、新しい値を第1のノードに割り当て、第1のノードの値を第2のノードに与え、第2のノードの値を第3のノードに割り当て、これに類する.しかし、実際の動作の順序は逆でなければならない.最後のノードに最後のノードの値を与え、最後の3番目のノードの値を最後の2番目のノードに与えている.しかし、面白い再帰的な用例として、私はそれを上に置いてきました.
    コードは以下の通りです.主にdestを見ます.
    function moveNodeV2(source, dest) {
      if (source === null || dest === null || source.isEmpty()) {
        throw new Error('invalid arguments')
      }
    
      pushInPlaceV2(dest, source.data)
    
      if (source.next) {
        source.data = source.next.data
        source.next = source.next.next
      } else {
        source.data = null
      }
    }
    
    function pushInPlaceV2(head, data) {
      if (!head) return new Node(data)
    
      if (!head.isEmpty()) head.next = pushInPlaceV2(head.next, head.data)
      head.data = data
      return head
    }
    締め括りをつける
    再帰性を常に使用すると慣性が発生し、データ構造の基本特性を無視する結果となる.チェーンの特性は挿入と削除の便利さです.引用を変更すればいいです.
    アルゴリズムに関するコードとテストは全部GitHubに置いています.もしあなたに助けがあれば、いい評価をお願いします.
    参考資料
    Codewars Kata GitHubのコードはGitHubのテストを実現します.