1. 程式人生 > >js資料結構與演算法--單鏈表的實現與應用思考

js資料結構與演算法--單鏈表的實現與應用思考

連結串列是動態的資料結構,它的每個元素由一個儲存元素本身的節點和一個指向下一個元素的引用(也稱指標或連結)組成。

連結串列結構示意圖

現實中,有一些連結串列的例子。

第一個就是尋寶的遊戲。你有一條線索,這條線索是指向尋找下一條線索的地點的指標。你順著這條連結去下一個地點,得到另一條指向下一處的線索。得到列表中間的線索的唯一辦法,就是從起點(第一條線索)順著列表尋找。

第二個例子是火車。一列火車是由一些車廂組成的。每節車廂都是相互連線。你很容易分離一節車皮,改變它的位置,新增或移除它。每節車廂都是列表的元素,車廂間的連線就是指標。

連結串列的實現

連結串列有多種不同的型別,單鏈表,雙向連結串列,迴圈連結串列等。

我們先實現單鏈表。單鏈表是一種鏈式存取的資料結構。

linkednode.js檔案,裡面包含了連結串列中節點的項


/**

 * 連結串列節點,連結串列中的項,連結串列中的節點

 */

export class Node {

  constructor(element, next = null) {

    this.element = element // 連結串列中節點的值

    this.next = next // 指向列表中下一個節點項的指標

  }

}

linkedlist.js檔案,連結串列各種方法的實現


import { Node } from './linkednode'



/**

 * 連結串列類

 */

export default class LinkedList {

  constructor() {

    this.length = 0 // 儲存連結串列中列表項的數量

    this.head = null // 儲存連結串列中第一個節點的引用

  }



  /**

   * 向列表尾部新增一個新的項

   * @param {*} element 需要新增至連結串列中的節點項

   */

  append(element) {

    let node = new Node(element) // 將新項建立為符合連結串列結構的列表項

    if (this.head === null) {

      // 連結串列中的元素為空

      this.head = node

    } else {

      let current = this.head // 將第一個節點的引用賦值給當前項

      // 迴圈列表,直到找到最後一項

      while (current.next) {

        current = current.next

      }

      // 找到最後一項,將其next賦為node,建立連結

      current.next = node

    }

    this.length++ // 更新連結串列的長度

  }



  /**

   * 向列表的特定位置插入一個新的項

   * @param {*} position 插入連結串列中的位置

   * @param {*} element 需要新增的節點

   */

  insert(position, element) {

    let node = new Node(element)

    // 檢查越界

    if (position > -1 && position <= this.length) {

      let current = this.head

      let previous

      let index = 0



      // 在第一個位子新增

      if (position === 0) {

        node.next = current

        this.head = node

      } else {

        // 需要找到特定的位子,將想要插入的元素放在previous節點和current節點之間

        while (index++ < position) {

          // previous 將是對想要插入新元素的位置之前一個元素的引用

          previous = current

          // current 對想要插入新元素的位置之後一個元素的引用

          current = current.next

        }

        node.next = current

        previous.next = node

      }

      this.length++

      return true

    } else {

      return false

    }

  }

  /**

   * 移除指定位置的節點元素,並返回移除的項

   * 如果超出了連結串列的範圍,則返回null

   * @param {Int32Array} position 連結串列中的位置

   */

  removeAt(position) {

    // 檢查越界

    if (position > -1 && position < this.length) {

      let current = this.head

      let previous // 先前一個節點

      let index = 0 // 當前節點的位子



      // 移除第一項

      if (position === 0) {

        this.head = current.next

      } else {

        while (index++ < position) {

          previous = current

          current = current.next

        }

        // 將previous 與 current 的下一項鍊接起來:跳過current,從而移除它

        // 當前元素會丟棄在計算機記憶體中,等待GC清除

        previous.next = current.next

      }

      this.length-- // 連結串列元素數量減1

      return current.element // 返回移除的項

    } else {

      return null // 如果超出了連結串列的範圍,則返回null

    }

  }



  /**

   * 從列表中移除一項

   * 先找出元素的索引項,再根據索引移除元素

   * @param {*} element 列表中的元素

   */

  remove(element) {

    let index = this.indexOf(element)

    return this.removeAt(index)

  }



  /**

   * 返回元素在列表中的索引。如果列表中沒有該元素則返回-1

   * @param {*} element 元素

   */

  indexOf(element) {

    let current = this.head

    let index = 0 // 計算位置數

    while (current) {

      if (element === current.element) {

        return index

      }

      index++

      current = current.next

    }

    return -1

  }



  /**

   * 判斷是否為空連結串列

   * 空連結串列返回true,非空(連結串列長度大於0)返回false

   */

  isEmpty() {

    return this.size() === 0

  }



  /**

   * 返回連結串列包含的元素個數。與陣列的length屬性類似

   */

  size() {

    return this.length

  }



  /**

   * 獲取連結串列的表頭節點

   * head變數是LinkedList類的私有變數。

   * 但是,我們需要實現在類的外部迴圈訪問列表。

   * 此時,就需要提供獲取類的第一個元素的方法

   */

  getHead() {

    return this.head

  }



  /**

   * 由於列表項使用了Node類,需要重寫toString方法,讓其只輸出元素的值。

   */

  toString() {

    let current = this.head

    let string = ''

    while (current) {

      string += current.element + (current.next ? '-->' : '')

      current = current.next

    }

    return string

  }

}

連結串列的應用思考

我們先比較下JavaScript中連結串列與陣列的區別:

  1. 連結串列中的元素是不連續的,而陣列中的元素是連續的。

  2. 連結串列新增或移除元素的時候不需要移動其他元素,而陣列需要。

  3. 連結串列需要指標,而陣列不需要。

  4. 連結串列需要從表頭開始迭代列表直到找到所需要的元素。陣列則可以直接訪問任何位置的任何元素。

  5. 兩者都具有動態性。關於陣列動態性。陣列在js中是一個可以修改的物件,新增移除元素,它會動態的變化,但是成本很高,需要移動元素。在大多數語言中(比如C和Java),陣列的大小是固定的,想新增元素就要建立一個全新的陣列,不能簡單地往其中新增所需的元素。

要儲存多個元素,陣列可能是最常用的資料結構。但是,如果要儲存資料,並且會有移除或者新增大量資料時候,連結串列比陣列更實用。

相關推薦

資料結構演算法——單鏈逆轉(C語言)(不間斷更新)

題目來源:浙大程式設計類實驗輔助教學平臺 本題要求實現一個函式,將給定的單鏈表逆轉。 函式介面定義: List Reverse( List L ); 其中List結構定義如下: typedef struct Node *PtrToNode; stru

資料結構複習------------迴圈單鏈實現約瑟夫問題

用連結串列求約瑟夫問題: 前面小編試過用順序表來實現約瑟夫問題,用的是連用起始結點加報數然後球餘出列,這次利用迴圈單鏈表來實現。可能思考不周,但歡迎各路大神賜教! 演算法思路 : 由於約瑟夫問題是n個人圍坐一圈,所以採用迴圈連結串列實現,又由於報數可

資料結構---列隊(單鏈實現

一、理論知識 待續 二、程式碼實現 1.節點結構體、棧頂、尾指標結構體定義 typedef int ElemType; typedef struct node { ElemType data; struct node* pNext; }node,*pNode;

js資料結構演算法--單鏈實現應用思考

連結串列是動態的資料結構,它的每個元素由一個儲存元素本身的節點和一個指向下一個元素的引用(也稱指標或連結)組成。 現實中,有一些連結串列的例子。 第一個就是尋寶的遊戲。你有一條線索,這條線索是指向尋找下一條線索的地點的指標。你順著這條連結去下一個地點,得到另一條指向下一處的線索。得到列表中間的線索的唯一辦法

資料結構演算法——單鏈(一)

單鏈表的頭插法,插入時就是逆序。 InsertList()還不完善。 #include<stdio.h> #include<stdlib.h> #define ERROR 0 #define OK 1 typedef int Status ; typedef int

資料結構演算法-單鏈-線性錶轉置

問題:《資料結構與演算法分析(C++語言版)》p58 五、2 已知一個如下圖所示的帶頭結點的單鏈表head(注:若頭指標名是head,則把單鏈表稱為表head),其儲存結構為: typedef struct Lnode{ ElemType dat

考研資料結構演算法----單鏈的建立和讀取(1)

    先來個簡單的,晚上再把整表刪除神馬的加上,懶得註釋了,貼出來就是給同樣考研的同志們做個參考。     話說現在大學折騰的越來越水,當年我們學資料結構的時候單鏈表就算是五個實驗裡面第二難的了,最難的是一個二叉樹的,最後反正是都沒做出來直接往上抄的。其實現在回頭看過來倒

資料結構 筆記:單鏈的具體實現

LinkList設計要點 -類模板,通過頭結點訪問後繼結點 -定義內部結點型別Node,用於描述資料域和指標域 -實現線性表的關鍵操作(增,刪,查,等) template<typename T> class LinkList : public List<T>

資料結構 筆記:單鏈的遍歷優化

如何遍歷單鏈表中的每一個數據元素? 為單鏈表提供新的方法,線上性時間內完成遍歷 設計思路(遊標) -在單鏈表的內部定義一個遊標(Node* m_current) -遍歷開始前將遊標指向位置為0的資料元素 -獲取遊標指向的資料元素 -通過結點中的next指標移動遊標 提供一

資料結構】無頭單鏈各個介面的實現

以下是無頭單鏈表的增刪查改等介面的實現 SList.h #pragma once #include <assert.h> #include <stdio.h> #include <stdlib.h> #include <malloc.h> t

資料結構之迴圈單鏈(C++實現)

基本的概念與連結串列相同,不同的是 最後一個鏈結點的指標指向頭部 形成了迴圈連結串列#include <iostream> using namespace std; class Node { public: Node *next; int data;

Javascript資料結構演算法--棧的實現用法

棧資料結構 棧是一種遵從後進先出(LIFO)原則的有序集合。新新增的或者待刪除的元素都儲存在棧的同一端,稱作棧頂,另一端就叫棧底。在棧裡,新元素都靠近棧頂,舊元素都接近棧底。 我們在生活中常能看到棧的例子。整齊堆起來的書,廚房堆起的盤子等 棧也被用在程式語言的編譯器和記憶體中儲存變數、方法呼叫等。 /**

資料結構之靜態單鏈

靜態連結串列L儲存 遊標 cur 5 2 3 4 0 6 7 .... 1 資料 data   A

學好資料結構演算法 —— 線性

線性表   線性表表示一種線性結構的資料結構,顧名思義就是資料排成像一條線一樣的結構,每個線性表上的資料只有前和後兩個方向。比如:陣列、連結串列、棧和佇列都是線性表,今天我們分別來看看這些線性資料結構。 陣列 陣列是一種線性表資料結構,用一組連續的記憶體空間來儲存一組具有相同型別的資料。 記憶體分

資料結構實驗三單鏈學生資訊

#include<iostream> #include<stdlib.h> using namespace std; class Student {private: struct Node {char name[20]; char age[4]; int nu

資料結構演算法--線性

順序線性表 三個基本屬性 儲存空間的起始位置data 線性表的最大儲存量maxSize 線性表的當前長度length Python實現 # Python 2.7 class seqList(object): # 初始化 def

JS資料結構演算法 --- 棧

概念:表頭進行插入和刪除操作的線性表 核心思想:先進後出 作用:在程式語言的編譯器和記憶體中儲存變數、方法呼叫 操作方法:1)push() 進棧,即向棧裡新增元素                 &n

JS資料結構演算法 --- 連結串列

概念:性質類似於陣列,是計算機的一種儲存結構。連結串列由一系列結點組成,每個結點裡包含了本結點的資料域和指向下一個結點的指標(裡面儲存著下一個結點)。 作用:按一定順序儲存資料,允許在任意位置插入和刪除結點。 分類:雙向連結串列、迴圈連結串列 應用場景:對線性表的長度或者規模難

JS資料結構演算法 --- 佇列

概念:只允許在表的前端(front)進行刪除操作,在表的後端(rear)進行插入操作的一種特殊線性表 核心思想:先進先出 分類:1)迴圈佇列:普通佇列的首尾相接形成圓環,這樣的佇列稱為迴圈佇列(Circular Queue)         &

資料結構作業5--單鏈

6-1 帶頭結點的單鏈表就地逆置 (10 分) 本題要求編寫函式實現帶頭結點的單鏈線性表的就地逆置操作函式。L是一個帶頭結點的單鏈表,函式ListReverse_L(LinkList &L)要求在不新開闢節點的前提下將單鏈表中的元素進行逆置,如原單鏈表元素依次為1,