链表存储有序的元素集合,但不一样于数组,链表中的元素在内存中并非连续放置的。每一个 元素由一个存储元素自己的节点和一个指向下一个元素的引用(也称指针或连接)组成。下面是一个链表的基本结构: 数组
例如寻宝游戏。你有一条线索,这条线索是指向寻找下一条线索的地点的指针。你顺着这条连接去下一个地点,获得另外一条指向再下一处的线索。获得列表中间的线索的惟一办法,就是从起点(第一条线索)顺着列表寻找。也就是链表只有给你头结点,你就能够找到剩下的元素。bash
function linkedList() {
const Node = function (ele) {
this.ele = ele;
this.next = null;
}
const length = 0;
const head = null;
// 向列表尾部添加一个新的项。
this.append = (ele) => {}
// 向列表的特定位置插入一个新的项。
this.insert = (position, ele) => {}
// 从列表的特定位置移除一项。
this.removeAt = (position) => {}
// 返回元素在列表中的索引。若是列表中没有该元素则返回-1。
this.indexOf = (ele) => {}
// 从列表中移除一项。
this.remove = (ele) => {}
// 若是链表中不包含任何元素,返回true,若是链表长度大于0则返回false。
this.isEmpty = () => {}
// 返回链表包含的元素个数。与数组的length属性相似。
this.size = () => {}
// 因为列表项使用了Node类,就须要重写继承自JavaScript对象默认的toString方法,让其只输出元素的值。
this.toString = () => {}
// 打印全部节点
this.print = () => {}
}
复制代码
逐个实现各个方法app
向LinkedList对象尾部添加一个元素时,可能有两种场景:列表为空,添加的是第一个元 素,或者列表不为空,向其追加元素。函数
this.append = (ele) => {
const newNode = new Node(ele);
let current; // 当前节点对象
if (head === null) { // 无头结点
head = newNode;
} else {
let head = current;
while(current.next) {
current = current.next;
}
current.next = newNode;
}
return ++length;
}
复制代码
// 向列表的特定位置插入一个新的项。
this.insert = (position, ele) => {
if (position < 0 || position > length) {
return false;
}
const newNode = new Node(ele);
let current = head;
let prevNode;
// let
if (position === 0) { // 插入的位置是 0 头节点的位置
NewNode.next = current;
head = newNode;
} else {
while(index < position) {
prevNode = current;
current = current.next;
index++;
}
prevNode.next = newNode;
newNode.next = current;
}
length++;
return true;
}
复制代码
// 从列表的特定位置移除一项。
this.removeAt = (position) => {
if (position < 0 || position > length) {
return false;
}
const newNode = new Node();
let current = head;
let prevNode;
let index = 0;
if (position === 0) {
head = newNode;
} else {
while (index++ < position) {
prevNode = current;
current = current.next;
}
prevNode.next = current.next; // 跳过当前current
}
length--;
return true;
}
复制代码
// 移除指定节点
this.remove1 = function(ele) {
const index = this.indexOf(ele);
return this.removeAt(index);
}
this.remove = (ele) => {
let index = 0;
let current = head;
let prevNode;
while (current) {
if (current.ele === ele) {
break;
}
prevNode = current;
current = current.next;
}
if (current.ele !== ele) {
return false;
}
prevNode.next = current.next;
return true;
}
复制代码
function linkedList() {
const Node = function (ele) {
this.ele = ele;
this.next = null;
}
const length = 0; // 链表的长度
const head = null; // 头节点
// 向列表尾部添加一个新的项。向LinkedList对象尾部添加一个元素时,可能有两种场景:列表为空,添加的是第一个元 素,或者列表不为空,向其追加元素。
this.append = (ele) => {
const newNode = new Node(ele);
let current; // 当前节点对象
if (head === null) { // 无头节点
head = newNode;
} else {
let head = current;
while(current.next) {
current = current.next;
}
current.next = newNode;
}
return ++length;
}
// 向列表的特定位置插入一个新的项。第一种场景: 须要在列表的起点添加一个元素,也就是第一个 位置。第二种场景: 在列表中间或尾部添加一个元素。
this.insert = (position, ele) => {
if (!this.inRange(position)) {
return false;
}
const newNode = new Node(ele);
let current = head;
let prevNode;
// let
if (position === 0) { // 插入的位置是 0 头节点的位置
NewNode.next = current;
head = newNode;
} else {
while(index < position) {
prevNode = current;
current = current.next;
index++;
}
prevNode.next = newNode;
newNode.next = current;
}
length++;
return true;
}
// 从列表的特定位置移除一项。状况1: 咱们要从列表中移除第一个元素(position === 0); 状况2:移除列表的最后一项或者中间某一项
this.removeAt = (position) => {
if (!this.inRange(position)) {
return false;
}
const newNode = new Node();
let current = head;
let prevNode;
let index = 0;
if (position === 0) {
head = newNode;
} else {
while (index++ < position) {
prevNode = current;
current = current.next;
}
prevNode.next = current.next; // 跳过当前current
}
length--;
return true;
}
// 返回元素在列表中的索引。若是列表中没有该元素则返回-1。
this.indexOf = (ele) => {
let current = head;
let index = -1;
while (current) {
if (current.ele === ele) {
return index;
}
current = current.next;
index++;
}
return -1;
}
// 从列表中移除一项。
this.remove = (ele) => {
let index = 0;
let current = head;
let prevNode;
while (current) {
if (current.ele === ele) {
break;
}
prevNode = current;
current = current.next;
}
if (current.ele !== ele) {
return false;
}
prevNode.next = current.next;
return true;
}
this.remove1 = function(ele) {
const index = this.indexOf(ele);
return this.removeAt(index);
}
// 若是链表中不包含任何元素,返回true,若是链表长度大于0则返回false。
this.isEmpty = () => length === 0;
// 返回链表包含的元素个数。与数组的length属性相似。
this.size = () => length;
// 因为列表项使用了Node类,就须要重写继承自JavaScript对象默认的toString方法,让其只输出元素的值。
this.toString = () => {
let current = head;
let resultStr = '';
while (current) {
resultStr += current;
}
return resultStr;
}
// 打印全部节点
this.print = () => {
let current = head;
let results = [];
while (current) {
results.push(current.ele);
}
console.log(results);
return results;
}
this.inRange = (position) => {
return position >= 0 && position <=length;
}
}
复制代码
双向链表和普通链表的区别在于,在链表中, 一个节点只有链向下一个节点的连接,而在双向链表中,连接是双向的:一个链向下一个元素, 另外一个链向前一个元素;普通链表只有一个next指针指向后一个元素, 而双向链表则后面的节点有一个prev指向前面节点的指针ui
循环链表能够像链表同样只有单向引用,也能够像双向链表同样有双向引用。循环链表和链表之间惟一的区别在于,最后一个元素指向下一个元素的指针(tail.next)不是引用null, 而是指向第一个元素(head),以下图所示。this