在写项目的时候会发现,并无使用不少关于链表的东西,大多数状况使用的都是数组,可是因为在准备校招,不少公司都会考到这个问题,因此准备对链表的相关操做进行总结,并对其中的重难点进行强调,最后还会附加几道关于链表的算法题,那么如今就开始吧!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] } }