目录
一、什么是链表?
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。
二、链表的封装
function linkedList(){
// 封装一个内部类
function Node(data){
this.data = data;
this.next = null;
}
// 属性,声明一个链表头和链表的长度
this.head = null;
this.length = 0;
}
三、追溯方法append(element)
向链表尾部添加一个新的项。
linkedList.prototype.append = function(data){
// 1、创建新节点
var newNode = new Node(data);
// 2、判断链表是否为空
if(this.length == 0){ //2.1 链表为空
this.head = newNode;
}else{ //2.2 链表不为空
// 找到最后一个节点
var current = this.head;
while(current.next){
current = current.next;
}
// 最后的节点的Next指向新的节点
current.next = newNode;
}
// 3、长度要加1
this.length += 1;
}
四、toString()
由于链表项使用了Node类,就需要重写继承自JavaScript对象默认的toString方法,让其只输出元素的值。
linkedList.prototype.toString = function(){
// 1、先定义变量
var current = this.head;
var listString = '';
// 将每次遍历的结果组成字符串
while(current){
listString += current.data + ' ';
// 加完一个元素后,指向下一个元素
current = current.next;
}
// 返回字符串
return listString;
}
append方法与toString方法测试
// 测试代码
// 创建linkedList
var list = new linkedList();
list.append('a');
list.append('b');
list.append('c');
list.append('d');
alert(list); // a b c d
五、inset(position, element)
向队列的特定位置插入一个新的元素。
这种方法与append不同的是,在任何一个有效的地方插入一个元素,首先需要给定的参数是位置(position)和值(data)
1、利用原型,给整个类添加一个方法
// 三、inset方法
linkedList.prototype.inset = function(position, data){
}
2、需要先限制position的有效范围。
假设链表中有四个元素,那么position的值就不能为负数,且不可以超过链表的长度。
if (position < 0 || position > this.length) return false;
3、根据data创建linkedList
var newNode = new Node(data);
4、判断所插入的节点位置是否在0的位置。
4.1如果是,先让新节点的next指向head,再将head指向新节点。注意:这里的顺序不可颠倒。
if(position == 0){ //当所插入的节点位置在0的位置时
// 先让新节点的next指向head
newNode.next = this.head;
// 再将head指向新节点
this.head = newNode;
}
4.2如果不是,则需寻找到相应位置插入。
这里先定义三个变量,分别是index、current和previous
index变量:等于0,从第一个节点的位置开始
current变量:指向head;
previous变量:指向空,表示第一个节点之前没有节点。
var index = 0; //指向第一个节点的位置
var current = this.head; //将current变量指向head
var previous = null; //将变量previous指向空,表示第一个节点之前没有节点
在找到相应位置之前,每一次操作都保存两个位置。
while(index++ < position){ //相比较后++
previous = current; //只要满足条件,就将current的赋予previous,表示保存需要插入节点位置的上一个位置
current = current.next; //然后current指向下一个节点继续查找
}
5、插入节点
//插入节点
newNode.next = current; //先让新节点的next指向查找到的位置上的节点
previous.next = newNode; //再将保存的上一个节点的next指向新节点
6、链表长度加1
// 6、length+1
this.length += 1;
7、完整代码
linkedList.prototype.inset = function(position, data){
if (position < 0 || position > this.length) return false;
var newNode = new Node(data);
if(position == 0){
newNode.next = this.head;
this.head = newNode;
}else {
var index = 0;
var current = this.head;
var previous = null;
while(index++ < position){
previous = current;
current = current.next;
}
newNode.next = current;
previous.next = newNode;
}
this.length += 1;
return true;
}
8、测试代码
// 测试代码
// 创建linkedList
var list = new linkedList();
list.append('a');
list.append('b');
list.append('c');
list.append('d');
alert(list); // a b c d
list.inset(2,'e');
alert(list); // a b e c d
六、get(position)
获取对应位置的元素。
以变量index去寻找到对应的位置并返回data
linkedList.prototype.get = function(position){
// 越界判断
if (position < 0 || position >= this.length) return false;
var index = 0;
var current = this.head;
while(index++ < position){
current = current.next;
}
return current.data;
}
测试代码
// 测试代码
// 创建linkedList
var list = new linkedList();
list.append('a');
list.append('b');
list.append('c');
list.append('d');
alert(list.get(2)); // c
alert(list.get(3)); // d
alert(list.get(4)); //false
alert(list.get(-4)); //false
七、indexOf(element)
返回元素在链表中的索引。
linkedList.prototype.indexOf = function(data){
//定义变量
var index = 0;
var current = this.head;
//当current不指向空时判断数据是否相同
while(current){
if (current.data == data) return index;
current = current.next;
index += 1;
}
return false;
}
代码测试
// 测试代码
// 创建linkedList
var list = new linkedList();
list.append('a');
list.append('b');
list.append('c');
list.append('d');
alert(list.indexOf('a')); //0
alert(list.indexOf('b')); //1
alert(list.indexOf('c')); //2
alert(list.indexOf('d')); //3
alert(list.indexOf('tt')); //false
八、upDate(position, element)
修改某个位置的元素。
upDate方法其实跟get方法类似,只是将其数据更改。
linkedList.prototype.upDate = function(position, data){
// 越界判断
if (position < 0 || position >= this.length) return false;
var index = 0;
var current = this.head;
while(index++ < position){
current = current.next;
}
current.data = data;
return true;
}
测试代码
// 测试代码
// 创建linkedList
var list = new linkedList();
list.append('a');
list.append('b');
list.append('c');
list.append('d');
alert(list); //a b c d
list.upDate(1,'e')
alert(list); //a e c d
九、removeAt(position)
从链表中移除特定位置的一项。
removeAt删除一个节点方法与inset方法相似,只是操作不同。
1、利用原型,给整个类添加一个方法
linkedList.prototype.removeAt = function(position){
}
2、限制position的有效范围
if (position < 0 || position > this.length) return false; //position小于0或者大于链表长度时删除失败
3、判断所删除的节点位置是否在0的位置。
3.1 如果是,head直接指向第一个节点的next
if(position == 0){ //3.1当所删除的节点位置在0的位置时
this.head = this.head.next;
}
3.2如果不是,则需寻找到相应位置删除。
这里先定义三个变量,分别是index、current和previous
index变量:等于0,从第一个节点的位置开始
current变量:指向head;
previous变量:指向空,表示第一个节点之前没有节点。
var index = 0; //指向第一个节点的位置
var current = this.head; //将current变量指向head
var previous = null; //将变量previous指向空,表示第一个节点之前没有节点
在找到相应位置之前,每一次操作都保存两个位置。
while(index++ < position){
previous = current;
current = current.next;
}
4、删除节点
// 4、删除节点
// 前一个节点的next指向,current的next指向
previous.next = current.next;
5、链表长度减去1
// 5、length-1
this.length -= 1;
6、完整代码
linkedList.prototype.removeAt = function(position){
if (position < 0 || position > this.length) return null;
var current = this.head;
if(position == 0){
this.head = this.head.next;
}else {
var index = 0;
var previous = null;
while(index++ < position){
previous = current;
current = current.next;
}
previous.next = current.next;
}
this.length -= 1;
return current.data;
}
7、代码检验
// 测试代码
// 创建linkedList
var list = new linkedList();
list.append('a');
list.append('b');
list.append('c');
list.append('d');
alert(list); //a b c d
alert('删除的节点为:' + list.removeAt(1) + ',最终链表为:' + list); //删除的节点为:b,最终链表为:a c d
十、remove(element)
从链表中删除一项。
先确定该元素的位置,然后再利用位置进行删除,其实就是直接调用indexOf()与removeAt()两个方法。
linkedList.prototype.remove = function(data) {
// 1、获取data在链表中的位置
var position = this.indexOf(data);
// 2、根据位置,删除节点
return this.removeAt(position);
}
测试代码
// 测试代码
// 创建linkedList
var list = new linkedList();
list.append('a');
list.append('b');
list.append('c');
list.append('d');
alert(list); //a b c d
alert('删除的节点为:' + list.remove('a') + ',最终链表为:' + list); //删除的节点为:a,最终链表为:b c d
十一、判断链表是否为空
linkedList.prototype.isEmpty = function(){
return this.length === 0;
}
十二、返回链表的长度
linkedList.prototype.size = function(){
return this.length;
}
十一、十二代码测试
// 测试代码
// 创建linkedList
var list = new linkedList();
list.append('a');
list.append('b');
list.append('c');
list.append('d');
alert(list); //a b c d
alert(list.size()); //4
alert(list.isEmpty()); //false