本文是博主深感算法方面的不足,做的一系列讀書筆記和源碼分析。
原文地址:學習javascript數據結構(二)——鏈表,以爲有用的話能夠給個star,謝謝啦。
做者:wengjqjavascript
鏈表存儲有序的元素集合,但不一樣於數組,鏈表中的元素在內存中並非連續放置的。每一個元素由一個存儲元素本事的節點和一個指向下一個元素的引用組成。相對於傳統的數組,鏈表的一個好處在於,添加或者刪除元素的時候不須要移動其餘元素。然而,鏈表須要使用指針,所以實現鏈表時須要額外注意。java
數組和鏈表的一個不一樣在於數組能夠直接訪問任何位置的元素,而想要訪問鏈表中的一個元素,須要從起點開始迭代列表。node
下面是單向鏈表的具體實現代碼:git
function LinkedList() {
var Node = function(element){
this.element = element;
this.next = null;
};
var length = 0;//鏈表長度
var head = null;//第一個節點
this.append = function(element){
var node = new Node(element),
current;
if (head === null){ //列表爲空
head = node;
} else { //列表不爲空
current = head; //如今只知道第一項head
while(current.next){ //找到列表的最後一項
current = current.next;
}
//創建連接
current.next = node;
}
length++; //更新列表長度
};
this.insert = function(position, element){
//檢查越界值
if (position >= 0 && position <= length){
var node = new Node(element),
current = head,
previous,
index = 0;
if (position === 0){ //在第一個位置添加
node.next = current;
head = node;
} else { //在中間或者尾部添加
while (index++ < position){ previous = current; current = current.next; } node.next = current; //先連上添加的節點 previous.next = node; //再斷開以前的鏈接 } length++; return true; } else { return false; } }; this.removeAt = function(position){ if (position > -1 && position < length){ var current = head, previous, index = 0; //用來迭代列表,直到到達目標位置 if (position === 0){ //移除第一項 head = current.next; } else { //移除中間或者尾部最後一項 while (index++ < position){ previous = current; current = current.next; } //鏈接前一項和後一項,跳過當前的項,至關於移除了當前項 previous.next = current.next; } length--; return current.element; } else { return null; } }; this.remove = function(element){ var index = this.indexOf(element); return this.removeAt(index); }; this.indexOf = function(element){ var current = head, index = 0; while (current) { if (element === current.element) { return index; } index++; //記錄位置 current = current.next; } return -1; }; this.isEmpty = function() { return length === 0; }; this.size = function() { return length; }; this.getHead = function(){ return head; }; this.toString = function(){ var current = head, string = ''; while (current) { string += current.element;//拼接 current = current.next; } return string; }; this.print = function(){ console.log(this.toString()); }; }複製代碼
雙向鏈表和單向鏈表的區別在於,在單向鏈表中,一個節點只有鏈向下一個節點的連接。而在雙向鏈表中,連接是雙向的:一個鏈向下一個元素,另外一個鏈向前一個元素。示例代碼以下:github
function DoublyLinkedList() {
var Node = function(element){
this.element = element;
this.next = null;
this.prev = null; //新添加的
};
var length = 0;
var head = null;
var tail = null; //新添加的
this.append = function(element){
var node = new Node(element),
current;
if (head === null){ //列表爲空
head = node;
tail = node;
} else {
tail.next = node;
node.prev = tail;
tail = node;
}
length++;
};
this.insert = function(position, element){
if (position >= 0 && position <= length){
var node = new Node(element),
current = head,
previous,
index = 0;
if (position === 0){ //在第一個位置
if (!head){ //列表爲空
head = node;
tail = node;
} else { //列表不爲空
node.next = current;
current.prev = node;
head = node;
}
} else if (position === length) { //最後一項
current = tail;
current.next = node;
node.prev = current;
tail = node;
} else {
while (index++ < position){ previous = current; current = current.next; } node.next = current; previous.next = node; //把node節點鏈接進去前一個節點和後一個節點 current.prev = node; //斷掉以前previous和current的鏈接 node.prev = previous; //prev一樣須要鏈接 } length++; return true; } else { return false; } }; this.removeAt = function(position){ if (position > -1 && position < length){ var current = head, previous, index = 0; if (position === 0){ //移除第一項 head = current.next; if (length === 1){ // 列表只有一項 tail = null; } else { head.prev = null; } } else if (position === length-1){ 移除最後一項 current = tail; // {4} tail = current.prev; tail.next = null; } else { while (index++ < position){ previous = current; current = current.next; } previous.next = current.next; // 連接前一項和後一項,跳過當前項 current.next.prev = previous; //修復prev } length--; return current.element; } else { return null; } }; this.remove = function(element){ var index = this.indexOf(element); return this.removeAt(index); }; this.indexOf = function(element){ var current = head, index = -1; //檢查第一項 if (element == current.element){ return 0; } index++; //檢查中間項 while(current.next){ if (element == current.element){ return index; } current = current.next; index++; } //檢查最後一項 if (element == current.element){ return index; } return -1; }; this.isEmpty = function() { return length === 0; }; this. size = function() { return length; }; this.toString = function(){ var current = head, s = current ? current.element : ''; while(current && current.next){ current = current.next; s += ', ' + current.element; } return s; }; this.inverseToString = function() { var current = tail, s = current ? current.element : ''; while(current && current.prev){ current = current.prev; s += ', ' + current.element; } return s; }; this.print = function(){ console.log(this.toString()); }; this.printInverse = function(){ console.log(this.inverseToString()); }; this.getHead = function(){ return head; }; this.getTail = function(){ return tail; } }複製代碼
循環鏈表能夠像單向鏈表那樣只有單向引用,也能夠像雙向鏈表那樣有雙向引用。循環鏈表和其餘鏈表的區別在於最後一個元素指向下一個元素的引用不是null,而是指向第一個元素(head)。示例代碼以下:算法
function CircularLinkedList() {
var Node = function(element){
this.element = element;
this.next = null;
};
var length = 0;
var head = null;
this.append = function(element){
var node = new Node(element),
current;
if (head === null){ //列表爲空
head = node;
} else {
current = head;
while(current.next !== head){ //最後一個元素將是head,而不是null
current = current.next;
}
current.next = node; //創建鏈接
}
node.next = head; //首尾相連起來變成一個環列表
length++;
};
this.insert = function(position, element){
if (position >= 0 && position <= length){
var node = new Node(element),
current = head,
previous,
index = 0;
if (position === 0){ //在第一項
node.next = current;
while(current.next !== head){
current = current.next;
}
head = node;
current.next = head;
} else {
while (index++ < position){ previous = current; current = current.next; } node.next = current; previous.next = node; if (node.next === null){ //在最後一個元素更新 node.next = head; } } length++; return true; } else { return false; } }; this.removeAt = function(position){ if (position > -1 && position < length){ var current = head, previous, index = 0; if (position === 0){ while(current.next !== head){ current = current.next; } head = head.next; current.next = head; //更新最後一項 } else { while (index++ < position){ previous = current; current = current.next; } previous.next = current.next; } length--; return current.element; } else { return null; } }; this.remove = function(element){ var index = this.indexOf(element); return this.removeAt(index); }; this.indexOf = function(element){ var current = head, index = -1; if (element == current.element){ //檢查第一項 return 0; } index++; while(current.next !== head){ //檢查列表中間 if (element == current.element){ return index; } current = current.next; index++; } if (element == current.element){ //檢查最後一項 return index; } return -1; }; this.isEmpty = function() { return length === 0; }; this.size = function() { return length; }; this.getHead = function(){ return head; }; this.toString = function(){ var current = head, s = current.element; while(current.next !== head){ current = current.next; s += ', ' + current.element; } return s.toString(); }; this.print = function(){ console.log(this.toString()); }; }複製代碼