鏈表存儲有序的元素集合,但不一樣於數組,鏈表中的元素在內存中並非連續放置的。每一個 元素由一個存儲元素自己的節點和一個指向下一個元素的引用(也稱指針或連接)組成。下面是一個鏈表的基本結構: 數組
例如尋寶遊戲。你有一條線索,這條線索是指向尋找下一條線索的地點的指針。你順着這條連接去下一個地點,獲得另外一條指向再下一處的線索。獲得列表中間的線索的惟一辦法,就是從起點(第一條線索)順着列表尋找。也就是鏈表只有給你頭結點,你就能夠找到剩下的元素。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