单向链表
单向链表是链表的一种,其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始;链表是使用指针进行构造的列表;又称为结点列表,因为链表是由一个个结点组装起来的;其中每个结点都有指针成员变量指向列表中的下一个结点;
链表是由结点构成,head指针指向第一个成为表头结点,而终止于最后一个指向NULL的指针。
链表的优点
相比较普通的线性结构,链表结构的可以总结一下:
(1)单个节点创建非常方便,普通的线性内存通常在创建的时候就需要设定数据的大小
(2)节点的删除非常方便,不需要像线性结构那样移动剩下的数据
(3)节点的访问方便,可以通过循环或者递归的方法访问到任意数据,但是平均的访问效率低于线性表
单链表的实现
function linkList() {
function node(data) {
this.data = data;
this.next = null;
}
this.head = null;
this.length = 0;
}
添加节点
linkList.prototype.append = function(data) {
// 新增节点
let newNode = new node(data);
// 如果链表为空
if (this.length === 0) {
this.head = newNode;
} else {
// 找到最后节点,再指向newNode
let current = this.head;
while (current.next) {
current = current.next; // 循坏找到最后一个节点
}
current.next = newNode;
}
this.length += 1;
};
insert方法
linkList.prototype.insert = function(index, data) {
// 边界问题
if (index < 0 || index > this.length) return false;
let newNode = new node(data);
// 添加的是第一个
if (index === 0) {
// 将newNode设置为head节点 并指向之前的head节点
let head = this.head;
this.head = newNode;
newNode.next = head;
} else {
// 向中间添加 ----- 也满足最后一个添加
let j = 0;
let current = this.head;
let pre = null;
while (j++ < index) { // j++ 先比较j 再+=1 ++j 先+= 1 再比较
pre = current; // 找到前一个节点
current = current.next; // 找到index后一个节点
}
// 前一个节点指向新的节点 新的节点指向index后的一个节点
pre.next = newNode;
newNode.next = current;
}
this.length += 1;
return true;
};
findNode方法
// 通过index找到当前的值
linkList.prototype.findNode = function(index) {
if (index < 0 || index >= this.length) return null;
let j = 0;
let current = this.head;
while (j < index) {
// 和j++ < index 一样
current = current.next;
j++;
}
return current.data;
};
indexOf方法
// indexOf方法,通过值找到下标
linkList.prototype.IndexOf = function(data) {
let current = this.head;
let index = 0;
while (current) {
if (current.data === data) {
return index;
}
current = current.next;
index += 1;
}
return -1;
};
update方法
// 修改某个元素
linkList.prototype.update = function(j, data) {
if (j < 0 || j >= this.length) return false;
let newNode = new node(data);
let current = this.head;
for (let i = 0; i < this.length; i++) {
if (i === j) {
current.data = newNode;
}
current = current.next;
}
return true;
};
linkList.prototype.update = function(j, data) {
if (j < 0 || j >= this.length) return false;
let newNode = new node(data);
let current = this.head;
let index = 0;
// <j ,index++,即找到下标为j的node;
while (index++ < j) {
current = current.next;
}
current.data = newNode;
return true;
};
removeAt()
linkList.prototype.removeAt = function(j) {
// 边界问题
if (j < 0 || j >= this.length) return false;
let current = this.head;
if (j === 0) {
this.head = current.next; // head的节点指向之前head的下一个节点
} else {
let index = 0;
let pre = null;
while (index++ < j) {
pre = current;
current = current.next;
}
// 删除的前一个节点指向删除的下一个节点
pre.next = current.next;
this.length -= 1;
return true;
}
};
remove方法
// 根据data删除节点
linkList.prototype.remove = function(data) {
let index = this.IndexOf(data); // 找到下标
return this.removeAt(index);
};
toString方法
linkList.prototype.toString = function() {
let current = this.head;
let res = "";
while (current) {
res += current.data + " ";
current = current.next;
}
return res;
};
let list = new linkList();
list.append(1);
list.append(2);
list.append(3);
// list.insert(0, 9); // 9,1,2,3
// list.insert(1, 10); // 1,10,2,3
// list.insert(3,100); // 1,2,3,100,
// let node = list.findNode(0); // 1
// console.log(node, "node");
// let index = list.IndexOf(2);
// console.log(index,'index') // 1
// list.update1(2, 400); // 1,2,400
// list.removeAt(2); // 1,2
// list.remove(1); // 2,3