在寫項目的時候會發現,並無使用不少關於鏈表的東西,大多數狀況使用的都是數組,可是因爲在準備校招,不少公司都會考到這個問題,因此準備對鏈表的相關操做進行總結,並對其中的重難點進行強調,最後還會附加幾道關於鏈表的算法題,那麼如今就開始吧!node
瞭解過鏈表的同窗應該都知道,鏈表有幾個特色:ios
能夠將鏈表中的每一個節點當作是一個對象,這個對象中有兩個屬性,一個是該節點的值,一個是該節點的下一個節點的地址(若是是雙鏈表,還要添加前一個節點地址的屬性)算法
function LinkedList(){ //輔助類:表示要加入鏈表的項 let node = function(element){ this.element = element; this.next = null;//這個節點的下一個節點暫時爲空 } let length = 0; let head = null; this.append() = function(element){};//向鏈表的尾部添加節點 this.insert() = function(position,element){};//在指定的位置添加節點 this.remove = function(element){};//將指定的節點刪除掉 this.removeAt = function(position){};//將指定位置的節點刪除 this.searchElement = function(element){};//查找指定元素的位置 this.searchPosition = function(position){};//查找指定位置的元素 }
上面代碼中包含了不少要實現的操做,包括最基本的增刪以及查詢。下面咱們就來一一的實現上面列舉的方法:數組
function append(element){ let node = new Node(element);//1 let current;//2 //3 if(head === null){ head = node }else{ current = head while(current.next){ current = current.next } current.next = node } length++;//4 }
將這個位置的前一個節點的next屬性賦值爲這個節點,並將它原先的下一個節點保存下來,賦值給如今這個節點的next屬性app
function insert(position,element){ if(position >=0 && position <= length){ //當position爲length時,表示在尾節點處添加,包含了append方法 let node = new Node(element); let current = head; let previous;//當前節點的前一個節點,在position處添加節點,就是在previos和current之間添加 if(position = 0){ node.next = head; head = node; }else{ for(let i = 0;i< position;i++){ pervious = current; current = current.next; } pervious.next = node; node.next = current; } length++; return true; }else{ return false; } }
基本思路:刪除節點的操做就是將目標節點前面的那個節點的指針指向目標節點的有一個節點post
function removed(element){ let node = new Node(element); let pervious; let nextNode; let current = head; if(head != null){ while (current != node){ pervious = current; current = current.next; nextNode = current.next; } pervious.next = nextNode; length--; return true; }else{ return false; } }
function removedAt(position){ //判斷所給位置是否溢出 if(position > -1 && position < length){ let current = head; let pervious; let nextNode; let i = 0; while(i < position){ pervious = current; current = current.next; nextNode = current.next; } pervious.next = nextNode; length--; return true; }else{ return false; } }
其實查詢節點和刪除節點差很少,都是經過遍歷,找到相應的節點或是相應的位置,而後進行操做,提及來比刪除節點還要簡單this
function searchElement(element){ //輸入元素,找到該元素後返回該元素的位置 if(head != null){ let node = new Node(element); let current; let index = 0; if(head == node){ return 0; }else{ current = head; while(current != node){ current = current.next; index++; } return index; } }else{ return -1; } }
function searchPosition(position){ //查找某一個位置的元素是什麼 if(position > -1 && position < length){ let i = 0; let current = head; while(i< position){ current = current.next; i++; } return current; }else{ return null; } }
關於鏈表的操做還有不少,複雜一點的鏈表還有雙鏈表(在初始化節點的時候增長一個前節點)和循環鏈表(尾節點的下一個節點是頭節點),這些鏈表的操做也是可使用js實現的,這裏就很少說了。總結一下,鏈表的核心在於spa
這裏總結幾道在牛客網上的劍指offer中刷到的幾道關於鏈表的算法題,這些題在筆試中仍是頗有可能遇到的,接着往下看吧!指針
1. 輸入一個鏈表,按鏈表值從尾到頭的順序返回一個ArrayList。code
思路:(1)將鏈表值從頭至尾輸出到一個數組中,而後將這個數組進行反轉獲得ArrayList
(2)使用數組的unshift方法,將鏈表值倒序放進數組
(3)先使用棧存放順序遍歷的結果,利用棧先進後出的特性,出棧的時候用數組保存
//使用思路2的方法 function Node(element){ this.val = element this.next = null } function logList(head){ if(head != null){ let ArrayList = []; while(head){ ArrayList.unshift(head.element); head = head.next; } return ArrayList; }else{ return []; } }
2. 輸入一個鏈表,輸出該鏈表中倒數第k個結點。
思路:(1)查找倒數第k個節點,能夠看作是查找正序第length-k個節點
(2)能夠根據第一題的結果取數組的第k-1個節點
//使用思路2 function Node(element){ this.element = element; this.next = null; } function FindKthToTail(head, k) { let array = [] while(head != null){ array.unshift(head) head = head.next; } return array[k-1]; }
3. 輸入一個鏈表,反轉鏈表後,輸出新鏈表的表頭。
思路:把倒序後的鏈表放進一個數組中,而後將這個數組的每一位的next屬性指向下一位
function ListNode(x){ this.val = x; this.next = null; } function ReverseList(pHead) { if(pHead){ let arr = []; while(pHead){ arr.unshift(pHead); pHead = pHead.next; } for(let i =0;i< arr.length;i++){ arr[i].next = arr[i+1] } return arr[0] } }