链表
Node类
function Node(x){
//节点的值
this.value = x;
//节点的下一个指向
this.next = null;
}
NodeList类
function NodeList(){
//初始化定义首节点
this.head = new Node('head');
//定义find方法,返回查找的节点
this.find = find;
//定义insert方法,在某个节点后插入一个节点
this.insert = insert;
//定义display方法,返回一个Map展示当前链表
this.display = display;
//定义remove方法,根据value值移除一个指定节点
this.remove = remove;
//定义removeByNO方法,根据序号移除一个指定节点
this.removeByNO = removeByNO;
//定义reverse方法,翻转链表
this.reverse = reverse;
}
find方法
function find(target){
//将该链表的首节点赋值给创建的新节点
let currentNode = this.head;
//判断节点的值是不是我们要的
while(currentNode.value != target){
//如果不是,先考虑这是不是最后一个节点
if(currentNode.next == null){
//若为最后一个节点,则查找失败
return 'not find'
}else{
//若不是,继续查找下一个节点
currentNode = currentNode.next;
}
}
//如果查找成功,返回该节点
return currentNode;
}
//创建一个名为nodeList的链表
var nodeList = new NodeList();
nodeList.find('he52ad');//not find
nodeList.find('head');//Node {value: "head", next: null}
insert方法
向链表中插入一个节点的效率很高,需要修改它前面的节点(前驱),使其指向新加入的节点,而将新节点指向原来前驱节点指向的节点即可。下面演示如何在 data2 节点后面插入 data4 节点。
function insert(value,target){
//创建一个新的节点
let newNode = new Node(value);
//利用我们写的find方法,先判断一下指定节点是否存在
if(this.find(target) == 'not find'){
//不存在则直接返回
return 'not find '+target;
}
//若存在,则通过find方法拿到指定的某个节点
let lastNode = this.find(target);
//让新节点指向指定节点的下一个节点
newNode.next = lastNode.next;
//指定节点指向新节点
lastNode.next = newNode;
}
display方法
我喜欢将链表的遍历结果存入一个Map结构中,一个显著好处是对该结果的操作将更为便利和直观,如果你不喜欢这样,你可以自己手写display方法将其存入数组。
function display(){
//新建一个名为nodeListDisplay 的Map结构
let nodeListDisplay = new Map();
//新建一个当前结点,并将该链表的头节点赋值过来
let currentNode = this.head;
//先塞入头节点至Map中
nodeListDisplay.set(0,currentNode.value);
//设定一个变量i,作为序号,因为头节点是0了,所以从1开始递增
let i = 1;
//当下个节点不为空时执行,若为空停止
while(currentNode.next != null){
//拿到下一个节点
currentNode = currentNode.next;
//下一个节点写入Map结构
nodeListDisplay.set(i,currentNode.value);
//序号递增
i++;
};
return nodeListDisplay;
}
var nodeList = new NodeList();
nodeList.insert('first','head');
nodeList.insert('second','first');
nodeList.insert('third','second');
//将返回的map结果存入dis变量
var dis = nodeList.display();
//现在你可以直接遍历了
for (let value of dis.values()) {
console.log(value);
} //head
//fisrt
//second
//third
//或者,利用扩展运算符(...),快速将map结构转为数组
console.log([...dis.keys()]);//[0, 1, 2, 3]
console.log([...dis.values()]);//["head", "first", "second", "third"]
remove方法
从链表中删除一个节点,也很简单。只需将待删节点的前驱节点指向待删节点的,同时将待删节点指向null,那么节点就删除成功了。下图片演示如何从链表中删除 data4 节点。
function remove(target){
//利用我们写的find方法,先判断一下指定节点是否存在
if(this.find(target) == 'not find'){
//不存在则直接返回
return 'not find '+target;
}
//若存在,则创建一个名为deleteNode的变量保存这个要删除的节点
let deleteNode = this.find(target);
//下一步是寻找这个要删除节点的前驱节点,首先从头节点开始找
let previousNode = this.head;
//如果首节点的值等于target
if( previousNode.value === target ){
//即删除首节点,将首节点的下一个值当作新的首节点
this.head = this.head.next;
return;
}
//如果不是删除首节点,则循环判断previousNode节点的下一个节点值是不是等于target
while(previousNode.next.value !== target){
//如果不等,说明previousNode不是target的前驱节点
previousNode = previousNode.next;
}
//当找到时,将要删除节点的下一节点赋值给前驱节点的next,完成删除
previousNode.next = deleteNode.next;
}
removeByNO方法
或者我们更进一步,写一写通过序号删除节点的方法
function removeByNO(number){
let size = this.display().size;
let deleteNode = this.head.next;
let previousNode = this.head;
if( number>size || number<0 ){
return 'out of index'
}
if( number==0 ){
this.head = this.head.next;
return;
}else{
for( let i=1;i<=size;i++ ){
if( i==number ){
previousNode.next = deleteNode.next;
}else{
previousNode = previousNode.next;
deleteNode = deleteNode.next;
}
}
}
}
//测试一下
var nodeList = new NodeList();
nodeList.insert('first','head');
nodeList.insert('second','first');
nodeList.insert('third','second');
console.log(nodeList.display());//Map(4) {0 => "head", 1 => "first", 2 => "second", 3 => "third"}
nodeList.removeByNO(0);
console.log(nodeList.display());//Map(3) {0 => "head", 1 => "second", 2 => "third"}
reverseByValue方法
这一种反转方式实际上只改变了每个节点的值,并没有对节点做移动
function reverse()
{
let currentNode=this.head, arr=[];
while(currentNode!=null){
arr.push(currentNode.value);
currentNode=currentNode.next;
}
currentNode= this.head;
while(currentNode!=null){
currentNode.value = arr.pop();
currentNode= currentNode.next;
}
return this.display();
}
reverse方法
这种反转方式移动了节点
function reverse()
{
let p = this.head;
let q = this.head.next;
this.head.next = null;
while( q!= null){
let r = q.next;
q.next = p;
p = q;
q = r;
}
this.head = p;
return this.display();
}