要存储多个元素,数组多是最经常使用的数据结构。这种数据结构很是方便,可是有一个缺点:从数组的起点或者中间插入或移除项的成本很是高,由于须要移动元素(好比你插入一个元素后面的全部的元素都移动了“位置”)。javascript
链表存储有序的元素集合,可是不一样于数组,链表中的元素在内存中并非连续放置的。每一个元素都是由一个存储元素自己的节点和一个指向下一元素的引用(也叫指针或者连接)组成。java
相比于数组来讲,链表的好处在于添加或者删除元素的时候不须要移动其余元素。可是操做链表须要使用指针。数组的一个优势是能够直接访问任何位置的任何元素,可是要是想访问链表中的某一元素,则是必须从起点开始迭代直到找到目标元素。node
建立一个链表数组
function LinkedList() { var Node = function(element) { this.element = element; this.next = null; } //各类方法 }
Node表示要加入列表的项,它包含一个element属性以及一个next属性,element表示要添加到列表的值,next表示指向列表下一个节点项的指针。数据结构
当一个Node元素被建立时,它的next指针老是nullapp
向链表尾部追加元素学习
列表为空,添加的是第一个元素。列表不为空,向其追加元素。this
要循环访问列表中的全部元素,就须要有一个起点,就是headspa
this.append = function(element) { var node = new Node(element), //传入值建立Node项 current; if(head === null) { //若是为空链表 head = node; //设置node为head(head为第一个节点的引用) } else { current = head; //从表头开始 while(current.next) { //循环列表,找到最后一项(列表最后一个节点的下一个元素始终是null) current = current.next; } //使当前最后一项的指针指向node current.next = node; } length++; //更新列表长度 };
使用append指针
var list = new LinkedList(); list.append(15); list.append(10);
从链表移除元素
输入位置,从特定位置移除一个元素
this.removeAt = function(position) { if(position > -1 && position < length) { //有效性检测 var current = head, //用current来循环列表 previous, index = 0; if(position === 0) { head = current.next; //移除第一个元素,直接把head指向下一个元素 } else { while(index++ < position) { //循环列表找到知足条件的那个元素 previous = current; // current = current.next; //把下一个变量覆给current } //跳过current,将当前要移除的元素的上一个与下一项直接链接起来。 previous.next = current.next; } length --; return current.element; } else { return null; } }
在任意位置插入一个元素
this.insert = function (position, element) { if(position >= 0 && position <= length) { var node = new Node(element), current = head; //经过current从head位置开始迭代 previous, index = 0; if(position === 0) { //第一个位置 node.next = current; //此时current = head,指向head那么node就成了第一个 head = node; //node指向为head } else { while (index++ < position ) { //循环迭代到目标位置 previous = current; current = current.next; } node.next = current; // node的下一个为current previous.next = node; // node的上一个位置为previous } length++; return true; } else { return false; } }
把LinkedList对象转换成一个字符串。
this.toString = function() { var current = head, string = ''; while(current) { //循环访问列表 string += current.element + (current.next ? '\n' : ''); current = current.next; } return string; //返回字符串 }
返回元素的位置
this.indexOf = function(element) { var current = head, index = 0; while(current) { if(element === current.element) { return index; //找到返回当前位置 } index ++; current = current.next; } return -1; //找不到返回-1 }
输入元素,移除该元素
this.remove = function(element) { var index = this.indexOf(element); //获得元素的位置 return this.removeAt(index); //移除该元素 }
判断是否为空 获得长度 获得第一个元素
this.isEmpty = function () { return length === 0; } this.size = function () { return length; } this.getHead = function () { return head; }
他和普通链表的区别,在双向链表中,连接是双向的,一个链向下一个元素一个链向上一个元素。在操做双向链表的时候既要像普通链表同样考虑next,也要考虑prev。
双向列表提供了两种迭代列表的方法:从头至尾迭代,或者反过来。
建立一个双向列表
function DoublyLinkedList() { var Node = function(element) { this.element = element; this.next = null; this.prev = null; //新指针 }; var length = 0; var head = null; var tail = null; //对列表最后一项的引用 //各类方法 }
在任意位置插入一个新元素
this.insert = function(position, element) { if(position >= 0 && position <= length) { var node = new Node(element), current = head, previous, index = 0; if(position === 0) { //在第一个位置添加 if(!head) { //若是head不存在即链表为空 head = node; tail = node; } else { //链表不为空 node.next = current; current.prev = node; head = node; } } else if(position === length) { //在最后一个位置添加 current = tail; current.next = node; node.prev = current; tail = node; } else { while(index++ < position) { //在列表中间添加 previous = current; //循环迭代 current = current.next; } node.next = current; previous.next = node; current.prev = node; node.prev = previous; } length ++; //更新列表长度 return true; } else { return false; } }
从任意位置移除元素
this.removeAt = function(position) { if(position > -1 && position < length) { //检查越界值 var current = head, previous, index = 0; if(position === 0) { //第一个位置 head = current.next; if(length === 1) { //若是链表只有一项 tail = null; } else { //也就至关于把current.next.prev = null head.prev = null; } } else if(position === length -1) { //最后一项 current = tail; //tail的引用赋给current变量 tail = current.prev; //上一项指向tail tail.next = null; //最后一项的next都是指向null的 } else { while(index++ < position) { //从中间位置移除 previous = current; current = current.next; } previous.next = current.next; //直接跳过current链接上一项和下一项 current.next.prev = previous; } length --; return current.element; } else { return null; } }
单向循环链表和链表惟一去别在于:最后一个元素指向下一个元素的指针(tail.next)不是引用null而是指向第一个元素(head)
双向循环链表有指向head的tail.next,也有指向tail的head.prev