定義
鏈表是由一組節(jié)點(diǎn)組成。每個(gè)節(jié)點(diǎn)都使用一個(gè)對(duì)象的引用指向它的后繼。指向另一個(gè)節(jié)點(diǎn)的引用叫做鏈。
設(shè)計(jì)一個(gè)基于對(duì)象的鏈表
- Node類(lèi)
function Node(element) {
this.element = element;
this.next = null;
}
- LinkedList類(lèi)
function LList () {
this.head = new Node("head");
this.find = find;
this.insert = insert;
this.remove = remove;
this.display = display;
}
實(shí)現(xiàn)方法
我們首先實(shí)現(xiàn) insert 方法, 但是實(shí)現(xiàn)insert方法之前可以先實(shí)現(xiàn) find 方法,先找到已知節(jié)點(diǎn),然后將新節(jié)點(diǎn)插入到已知節(jié)點(diǎn)后:
function find(item) {
var currentNode = this.head;
while(currentNode.element!=item) {
currentNode = currentNode.next
}
return currentNode;
}
現(xiàn)在就可以實(shí)現(xiàn)insert方法了:
function insert(newElement, item) {
var newNode = new Node(newElement);
var current = this.find(item);
newNode.next = current.next;
current.next = newNode;
}
展示所有數(shù)據(jù)的 display 方法:
function display() {
var currentNode = this.head;
while(currentNode != null) {
console.log(currentNode.element);
currentNode = currentNode.next;
}
}
測(cè)試我們寫(xiě)的方法:
var cities = new LList();
cities.display();
cities.insert('second', 'head');
cities.insert('third', 'second');
cities.insert('second-third', 'second');
cities.display();
我們似乎還少寫(xiě)了一個(gè) remove 方法,從鏈表中刪除節(jié)點(diǎn)時(shí),需要找到待刪除節(jié)點(diǎn)前面的節(jié)點(diǎn)。找到這個(gè)節(jié)點(diǎn)后修改它的 next 屬性,使其不再指向待刪除的節(jié)點(diǎn),而是指向待刪除節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)。我們可以先寫(xiě)一個(gè)findprevious方法:
function findPrevious(item) {
var currentNode = this.head;
while(currentNode.next != null && currentNode.next.element != item) {
console.log(currentNode.next);
currentNode = currentNode.next;
}
return currentNode;
}
所以,現(xiàn)在可以寫(xiě)remove 方法了:
function remove(item) {
var currentNode = this.findPrevious(item);
if (currentNode.next != null) {
currentNode.next = currentNode.next.next;
}
}
現(xiàn)在可以來(lái)測(cè)試下我們寫(xiě)的remove 方法了。
cities.remove('second');
console.log('刪除second后:');
cities.display();
雙向鏈表
首先我們需要給Node類(lèi)增加一個(gè) previous 屬性:
function Node(element) {
this.element = element;
this.next = null;
this.previous = null;
}
由于現(xiàn)在節(jié)點(diǎn)多了一個(gè) previous 屬性,所以需要改造下 insert 方法:
function insert(newElement, item) {
var currentNode = this.find(item);
var newNode = new Node(newElement);
newNode.previous = currentNode;
newNode.next = currentNode.next;
currentNode.next.previous = newNode;
currentNode.next = newNode;
}
雙向鏈表的 remove 方法比單向鏈表的效率更高,因?yàn)椴恍枰俨檎仪膀?qū)節(jié)點(diǎn)了,首先要在鏈表中查找待刪除的節(jié)點(diǎn),然后再設(shè)置該節(jié)點(diǎn)前驅(qū)節(jié)點(diǎn)的 next 屬性,使其指向待刪除節(jié)點(diǎn)的后驅(qū)節(jié)點(diǎn)就好了。
function remove(element) {
var currentNode = this.find(element);
if (currentNode.next != null) {
currentNode.previous.next = currentNode.next;
currentNode.next.previous = currentNode.previous;
currentNode.next = null;
currentNode.previous = null;
}
}
最后我們?cè)賹?shí)現(xiàn)一個(gè)反向打印鏈表的方法,就基本完成了鏈表的基本方法實(shí)現(xiàn),實(shí)現(xiàn)這個(gè)方法之前我們需要實(shí)現(xiàn)一個(gè) findLast 方法來(lái)查找鏈表最后一個(gè)節(jié)點(diǎn):
findLast() {
var currentNode = this.head;
while(currentNode.next != null) {
currentNode = currentNode.next;
}
return currentNode;
}
這時(shí)候我們就可以很容易實(shí)現(xiàn)反向打印鏈表了:
function dispReverse() {
var lastNode = this.findLast();
while(lastNode.previous != null) {
console.log(lastNode.element);
lastNode = lastNode.previous;
}
console.log(lastNode.element);
}