在前面,我们已经实现了列表的数据结构,当时使用的是数组作为底层存储,今天我们要来实现另外一种列表:链表。
数组的缺点
- 在数组中间,删除和增加元素非常麻烦,需要整体移动数组元素(JavaScript不存在该问题,split方法)
- 数组被填满时,再要加入新的元素会非常困难(JavaScript不存在该问题,动态数组)
- JavaScript数组的主要问题是,数组被实现成了对象,这将导致数组的效率相对其他语言(java/c)非常的低
链表
如果在某一个场景下,不需要对元素进行随机访问,或者发现数组的效率过低,则可以考虑使用链表来代替数组。链表是由多个节点组成的,每个节点都有一个对象的引用next指向后一个元素(后继),指向的这个引用叫做链。如下图:
数组元素依靠的是下标位置进行引用,链表元素则是通过互相之间的链接关系进行引用。向链表中插入或者删除元素效率都是很高的,只需要对被操作元素的前后链接进行改变就行,其他的元素完全不需要动。链表的最后一个节点指向null,下面看插入和删除的图示。
插入:
删除:
接下来,来看具体的代码实现。
//定义链表节点元素,具有存储的值属性,和链属性
function Node ( element ) {
this.element = element;
this.next = null;
}
//定义一个链表构造函数,里面包含一个头结点,和一些相关的方法
function LinkList () {
this.head = new Node( "head" );
this.find = find;
this.insert = insert;
this.remove = remove;
this.display = display;
this.findpre = findpre;
}
//遍历链表,找到目标节点
function find ( item ) {
var currNode = this.head;
while( currNode.element != item ) {
currNode = currNode.next;
}
return currNode;
}
//在item 后面插入newElment 节点,最后返回this是为了能够实现链式调用
function insert( newElment , item ) {
var newNode = new Node( newElment );
var currNode = this.find( item );
newNode.next = currNode.next;
currNode.next = newNode;
return this;
}
//找到item 的前一个节点
function findpre ( item ) {
var currNode = this.head;
while ( currNode.next != null && currNode.next.element != item ) {
currNode = currNode.next;
}
return currNode;
}
//遍历链表,删除目标节点
function remove ( element ) {
var pre = this.findpre( element );
if( pre.next != null ) {
pre.next = pre.next.next;
}
return this;
}
//遍历链表打印所有元素
function display () {
var currNode = this.head;
while( currNode.next != null ) {
console.log(currNode.next.element);
currNode =currNode.next;
}
return this;
}
var cities = new LinkList();
cities.insert("1","head").insert("2","1").insert("3","2").display().remove("2").display();