Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 日韩美女一级毛片,www一区二区,91精品久久久久久久久久

          整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          數據結構中的鏈表,你知道如何使用Javascript

          數據結構中的鏈表,你知道如何使用Javascript來實現嗎?

          不管是在前端還是后端開發面試過程中,關于數據結構部分的問題是必不可少的,比如像鏈表,棧,隊列,圖等等。今天這篇文章,我們站在前端開發人員的角度,看看如何使用Javascript來實現數據結構中的鏈表結構。

          今天這篇文章中的代碼已經放到Github上了,感興趣的可以自取,Github地址為:

          https://github.com/zhouxiongking/article-pages/blob/master/articles/LinkedList/LinkedList.js

          Javascript

          鏈表

          鏈表和數組是數據結構中用于存儲多個元素,比較常用的數據結構。數組中的元素在內存中占用連續的內存空間,而在鏈表中各個元素不是占有連續的內存空間,元素之間通過引用關系連接。

          通過下面這張圖可以很容易看清鏈表結構。

          鏈表結構

          相比于數組,鏈表在添加或移除元素時不會移動元素,只需要改變引用指向即可。但是如果想要訪問鏈表中的某個元素時,必須從表頭開始尋找,這是在使用上比數組劣勢的地方。

          下面我們看看如何通過代碼來實現一個鏈表結構,由于我們會采用類的結構來組織代碼,因此采用ES6的語法來寫。

          • 鏈表節點

          首先我們需要如上圖所示的鏈表節點。

          鏈表節點

          • 追加元素

          追加元素是在鏈表的末尾添加元素,動態的修改next引用的指向并修改鏈表的長度。

          追加元素

          • 任意位置插入元素

          在任意位置插入元素時,我們需要建立一個臨時索引,從表頭開始往后迭代,直到臨時變量值等于插入位置,即改變插入點的next引用指向。

          任意位置插入元素

          • 移除指定位置元素

          在移除指定位置元素時,首先需要檢查值是否越界,同樣需要建立一個臨時索引,從表頭向后迭代時,動態修改索引值,直到索引值與指定位置值相等,最后修改元素的next引用指向。

          移除指定位置元素

          • 尋找元素索引

          在尋找元素索引時,建立一個臨時變量,從表頭開始向后遍歷,在遍歷過程中動態修改臨時變量值,直到找到需要的元素,返回這個臨時變量即可。

          尋找元素索引

          • 刪除指定元素

          在刪除指定元素時,可以借助上述的尋找元素索引方法,先找到索引再通過移除指定位置元素的方法來刪除。

          刪除指定元素

          • 判空和鏈表長度

          判斷鏈表是否為空以及獲取鏈表的長度,都只需要通過length屬性即可。

          判空和鏈表長度

          • 自定義輸出

          打印鏈表時,我們可以自定義toString()方法,以我們想要的方式進行輸出。

          自定義輸出

          測試

          用Javascript編寫完鏈表結構后,我們通過以下的代碼進行測試。

          測試代碼

          我們可以得到以下結果。

          測試結果

          這也證明了我們實現鏈表結構的正確性。

          結束語

          今天這篇文章主要利用Javascript實現了數據結構中的鏈表,大家學會了嗎?

          不管是在前端還是后端開發面試過程中,關于數據結構部分的問題是必不可少的,比如像鏈表,棧,隊列,圖等等。今天這篇文章,我們站在前端開發人員的角度,看看如何使用Javascript來實現數據結構中的鏈表結構。

          今天這篇文章中的代碼已經放到Github上了,感興趣的可以自取,Github地址為:

          https://github.com/zhouxiongking/article-pages/blob/master/articles/LinkedList/LinkedList.js

          Javascript

          鏈表

          鏈表和數組是數據結構中用于存儲多個元素,比較常用的數據結構。數組中的元素在內存中占用連續的內存空間,而在鏈表中各個元素不是占有連續的內存空間,元素之間通過引用關系連接。

          通過下面這張圖可以很容易看清鏈表結構。

          鏈表結構

          相比于數組,鏈表在添加或移除元素時不會移動元素,只需要改變引用指向即可。但是如果想要訪問鏈表中的某個元素時,必須從表頭開始尋找,這是在使用上比數組劣勢的地方。

          下面我們看看如何通過代碼來實現一個鏈表結構,由于我們會采用類的結構來組織代碼,因此采用ES6的語法來寫。

          • 鏈表節點

          首先我們需要如上圖所示的鏈表節點。

          鏈表節點

          • 追加元素

          追加元素是在鏈表的末尾添加元素,動態的修改next引用的指向并修改鏈表的長度。

          追加元素

          • 任意位置插入元素

          在任意位置插入元素時,我們需要建立一個臨時索引,從表頭開始往后迭代,直到臨時變量值等于插入位置,即改變插入點的next引用指向。

          任意位置插入元素

          • 移除指定位置元素

          在移除指定位置元素時,首先需要檢查值是否越界,同樣需要建立一個臨時索引,從表頭向后迭代時,動態修改索引值,直到索引值與指定位置值相等,最后修改元素的next引用指向。

          移除指定位置元素

          • 尋找元素索引

          在尋找元素索引時,建立一個臨時變量,從表頭開始向后遍歷,在遍歷過程中動態修改臨時變量值,直到找到需要的元素,返回這個臨時變量即可。

          尋找元素索引

          • 刪除指定元素

          在刪除指定元素時,可以借助上述的尋找元素索引方法,先找到索引再通過移除指定位置元素的方法來刪除。

          刪除指定元素

          • 判空和鏈表長度

          判斷鏈表是否為空以及獲取鏈表的長度,都只需要通過length屬性即可。

          判空和鏈表長度

          • 自定義輸出

          打印鏈表時,我們可以自定義toString()方法,以我們想要的方式進行輸出。

          自定義輸出

          測試

          用Javascript編寫完鏈表結構后,我們通過以下的代碼進行測試。

          測試代碼

          我們可以得到以下結果。

          測試結果

          這也證明了我們實現鏈表結構的正確性。

          結束語

          今天這篇文章主要利用Javascript實現了數據結構中的鏈表,大家學會了嗎?

          篇文章給大家帶來的內容是關于JavaScript中鏈表的詳細介紹,有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。

          鏈表和數組

          大家都用過js中的數組,數組其實是一種線性表的順序存儲結構,它的特點是用一組地址連續的存儲單元依次存儲數據元素。而它的缺點也正是其特點而造成,比如對數組做刪除或者插入的時候,可能需要移動大量的元素。

          這里大致模擬一下數組的插入操作:

          insert(arr, index, data){

          for(let i=index + 1; i < arr.length; i++){

          arr[i]=arr[i - 1];

          }

          arr[index]=data;

          }

          從上面的代碼可以看出數組的插入以及刪除都有可能會是一個O(n)的操作。從而就引出了鏈表這種數據結構,鏈表不要求邏輯上相鄰的元素在物理位置上也相鄰,因此它沒有順序存儲結構所具有的缺點,當然它也失去了數組在一塊連續空間內隨機存取的優點。

          單向鏈表

          單向鏈表的特點:

          • 用一組任意的內存空間去存儲數據元素(這里的內存空間可以是連續的,也可以是不連續的)
          • 每個節點(node)都由數據本身和一個指向后續節點的指針組成
          • 整個鏈表的存取必須從頭指針開始,頭指針指向第一個節點
          • 最后一個節點的指針指向空(NULL)

          鏈表中的幾個主要操作

          • 創建節點
          • 插入節點
          • 搜索/遍歷節點
          • 刪除節點
          • 合并

          初始化節點

          • 指針指向空
          • 存儲數據

          class Node {

          constructor(key) {

          this.next=null;

          this.key=key;

          }

          }

          初始化單向鏈表

          • 每個鏈表都有一個頭指針,指向第一個節點,沒節點則指向NULL

          class List {

          constructor() {

          this.head=null;

          }

          }

          創建節點

          static createNode(key) {

          return new createNode(key);

          }

          這里說明一下,這一塊我是向外暴露了一個靜態方法來創建節點,而并非直接把它封裝進插入操作里去,因為我感覺這樣的邏輯會更加正確一些。 從創建一個鏈表 -> 創建一個節點 -> 將節點插入進鏈表中。可能你會遇到一些文章介紹的方式是直接將一個數據作為參數去調用insert操作,在insert內部做了一個創建節點。

          插入節點(插入到頭節點之后)

          插入操作只需要去調整節點的指針即可,兩種情況:

          • head沒有指向任何節點,說明當前插入的節點是第一個
          • head指向新節點
          • 新節點的指針指向NULL
          • head有指向的節點
          • head指向新的節點
          • 新節點的指針指向原本head所指向的節點

          insert(node) {

          // 如果head有指向的節點

          if(this.head){

          node.next=this.head;

          }else {

          node.next=null;

          }

          this.head=node;

          }

          搜索節點

          • 從head開始查找
          • 找到節點中的key等于想要查找的key的時候,返回該節點

          find(key) {

          let node=this.head;

          while(node !==null && node.key !==key){

          node=node.next;

          }

          return node;

          }

          刪除節點

          這里分三種情況:

          • 所要刪除的節點剛好是第一個,也就是head指向的節點
          • 將head指向所要刪除節點的下一個節點(node.next)
          • 要刪除的節點為最后一個節點
          • 尋找到所要刪除節點的上一個節點(prevNode)
          • 將prevNode中的指針指向NULL
          • 在列表中間刪除某個節點
          • 尋找到所要刪除節點的上一個節點(prevNode)
          • 將prevNode中的指針指向當前要刪除的這個節點的下一個節點

          delete(node) {

          // 第一種情況

          if(node===this.head){

          this.head=node.next;

          return;

          }

          // 查找所要刪除節點的上一個節點

          let prevNode=this.head;

          while (prevNode.next !==node) {

          prevNode=prevNode.next;

          }

          // 第二種情況

          if(node.next===null) {

          prevNode.next=null;

          }

          // 第三種情況

          if(node.next) {

          prevNode.next=node.next;

          }

          }

          單向鏈表整體的代碼

          class ListNode {

          constructor(key) {

          this.next=null;

          this.key=key;

          }

          }

          class List {

          constructor() {

          this.head=null;

          this.length=0;

          }

          static createNode(key) {

          return new ListNode(key);

          }

          // 往頭部插入數據

          insert(node) {

          // 如果head后面有指向的節點

          if (this.head) {

          node.next=this.head;

          } else {

          node.next=null;

          }

          this.head=node;

          this.length++;

          }

          find(key) {

          let node=this.head;

          while (node !==null && node.key !==key) {

          node=node.next;

          }

          return node;

          }

          delete(node) {

          if (this.length===0) {

          throw 'node is undefined';

          }

          if (node===this.head) {

          this.head=node.next;

          this.length--;

          return;

          }

          let prevNode=this.head;

          while (prevNode.next !==node) {

          prevNode=prevNode.next;

          }

          if (node.next===null) {

          prevNode.next=null;

          }

          if (node.next) {

          prevNode.next=node.next;

          }

          this.length--;

          }

          }

          雙向鏈表

          如果你把上面介紹的單向列表都看明白了,那么這里介紹的雙向列表其實差不多。

          從上面的圖可以很清楚的看到雙向鏈表和單向鏈表的區別。雙向鏈表多了一個指向上一個節點的指針。

          初始化節點

          • 指向前一個節點的指針
          • 指向后一個節點的指針
          • 節點數據

          class ListNode {

          this.prev=null;

          this.next=null;

          this.key=key;

          }

          初始化雙向鏈表

          • 頭指針指向NULL

          class List {

          constructor(){

          this.head=null;

          }

          }

          創建節點

          static createNode(key){

          return new ListNode(key);

          }

          插入節點((插入到頭節點之后)

          • 看上圖中head后面的第一個節點可以知道,該節點的prev指向NULL
          • 節點的next指針指向后一個節點, 也就是當前頭指針所指向的那個節點
          • 如果head后有節點,那么原本head后的節點的prev指向新插入的這個節點(因為是雙向的嘛)
          • 最后將head指向新的節點

          insert(node) {

          node.prev=null;

          node.next=this.head;

          if(this.head){

          this.head.prev=node;

          }

          this.head=node;

          }

          搜索節點

          這里和單向節點一樣,就直接貼代碼了

          search(key) {

          let node=this.head;

          while (node !==null && node.key !==key) {

          node=node.next;

          }

          return node;

          }

          刪除節點

          和之前單向鏈表一樣,分三種情況去看:

          • 刪除的是第一個節點
          • head指向所要刪除節點的下一個節點
          • 下一個節點的prev指針指向所要刪除節點的上一個節點
          • 刪除的是中間的某個節點
          • 所要刪除的前一個節點的next指向所要刪除的下一個節點
          • 所要刪除的下一個節點的prev指向所要刪除的前一個節點
          • 刪除的是最后一個節點
          • 要刪除的節點的上一個節點的next指向null(也就是指向刪除節點的next所指的地址)

          delete(node) {

          const {prev,next}=node;

          delete node.prev;

          delete node.next;

          if(node===this.head){

          this.head=next;

          }

          if(next){

          next.prev=prev;

          }

          if(prev){

          prev.next=next;

          }

          }

          雙向鏈表整體代碼

          class ListNode {

          constructor(key) {

          // 指向前一個節點

          this.prev=null;

          // 指向后一個節點

          this.next=null;

          // 節點的數據(或者用于查找的鍵)

          this.key=key;

          }

          }

          /**

          * 雙向鏈表

          */

          class List {

          constructor() {

          this.head=null;

          }

          static createNode(key) {

          return new ListNode(key);

          }

          insert(node) {

          node.prev=null;

          node.next=this.head;

          if (this.head) {

          this.head.prev=node;

          }

          this.head=node;

          }

          search(key) {

          let node=this.head;

          while (node !==null && node.key !==key) {

          node=node.next;

          }

          return node;

          }

          delete(node) {

          const { prev, next }=node;

          delete node.prev;

          delete node.next;

          if (node===this.head) {

          this.head=next;

          }

          if (prev) {

          prev.next=next;

          }

          if (next) {

          next.prev=prev;

          }

          }

          }

          總結

          這里做一個小總結吧,可能有一部分人讀到這里還不是特別的明白,我的建議是先好好看懂上面的單向鏈表。 其實只要你明白了鏈表的基礎概念,就是有一個head,然后在有好多的節點(Node),然后用一個指針把他們串起來就好了,至于里面的插入操作也好,刪除也好,其實都是在調整節點中指針的指向。

          以上就是JavaScript中鏈表的詳細介紹的詳細內容,更多請關注其它相關文章!

          更多技巧請《轉發 + 關注》哦!


          主站蜘蛛池模板: 亚洲熟妇AV一区二区三区宅男| 久99精品视频在线观看婷亚洲片国产一区一级在线 | 果冻传媒董小宛一区二区| 在线播放偷拍一区精品| 中文字幕一精品亚洲无线一区| 在线观看中文字幕一区| 国产精品一区二区不卡| 亚洲伦理一区二区| 另类免费视频一区二区在线观看| 国产伦精品一区二区三区免费下载 | 精品国产一区二区三区色欲| 三上悠亚一区二区观看| 一区二区三区杨幂在线观看| 午夜性色一区二区三区不卡视频| 亚洲国产激情在线一区| 久久久久人妻一区二区三区| 亚洲AV无码一区二区三区DV| 久久久精品日本一区二区三区| 激情啪啪精品一区二区| 国产精品一区二区三区高清在线| 亚洲欧美成人一区二区三区| 亚洲Av永久无码精品一区二区 | 久久久久国产一区二区三区| 无码精品人妻一区二区三区免费 | 久久久久无码国产精品一区| 亚洲AV乱码一区二区三区林ゆな| 91精品一区国产高清在线| 中文字幕日韩人妻不卡一区| 久久精品一区二区| 亚洲天堂一区二区三区四区| 国产一区二区久久久| 国产微拍精品一区二区| 国产日韩综合一区二区性色AV| 日韩精品无码Av一区二区 | 国产精品一区二区资源| 乱人伦一区二区三区| 亚洲综合无码精品一区二区三区| 熟女精品视频一区二区三区| 91一区二区视频| 视频精品一区二区三区| 中文字幕在线一区|