1、鏈表的基本介紹
數組不總是組織數據的最佳數據結構,在很多編程語言中,數組的長度是固定的,所以當數組已被數據填滿時,再要加入新的元素就會非常困難。在數組中,添加和刪除元素也很麻煩,因為需要將數組中的其他元素向前或向后平移。
鏈表是由一組節點組成的集合。每個節點都使用一個對象的引用指向它的后繼。許多鏈表的實現都在鏈表最前面有一個特殊節點,叫做頭節點。如下圖:
2、鏈表的實現
2.1、基於對象的鏈表的實現
Node 類用來表示節點,包含兩個屬性:element 用來保存節點上的數據,next 用來保存指向下一個節點的鏈接。
function Node(element) { this.element = element; this.next = null; }
LList 類提供了對鏈表進行操作的方法。該類的功能包括插入刪除節點、在列表中查找給定的值。
function LList() { this.head = new Node("head"); this.find = find; this.insert = insert; this.display = display; this.findPrevious = findPrevious; this.remove = remove; }
find() 方法遍歷鏈表,查找給定數據。如果找到數據,該方法就返回保存該數據的節點。如果查找成功,該方法返回包含該數據的節點;否則,返回 null。
function find(item) { var currNode = this.head; while (currNode.element != item) { currNode = currNode.next; } return currNode; }
insert() 方法在一個已知節點后面插入元素
function insert(newElement, item) { var newNode = new Node(newElement); var current = this.find(item); newNode.next = current.next; current.next = newNode; }
display() 方法用來顯示鏈表中的元素
function display() { var currNode = this.head; while (!(currNode.next == null)) { print(currNode.next.element); currNode = currNode.next; } }
findPrevious() 方法找到待刪除節點前面的節點。找到這個節點后,修改它的 next 屬性,使其不再指向待刪除節點,而是指向待刪除節點的下一個節點。
function findPrevious(item) { var currNode = this.head; while (!(currNode.next == null) && (currNode.next.element != item)) { currNode = currNode.next; } return currNode; }
remove() 方法從鏈表中刪除節點。
function remove(item) { var prevNode = this.findPrevious(item); if (!(prevNode.next == null)) { prevNode.next = prevNode.next.next; } }
2.2、雙向鏈表
給 Node 對象增加一個屬性,該屬性存儲指向前驅節點的鏈接,這使得鏈表從后向前遍歷變得簡單
function Node(element) { this.element = element; this.next = null; this.previous = null; }
insert() 方法
function insert(newElement, item) { var newNode = new Node(newElement); var current = this.find(item); newNode.next = current.next;
current.next.previous = newNode; newNode.previous = current; current.next = newNode; }
remove() 方法比單向鏈表的效率更高,因為不需要再查找前驅節點。
function remove(item) { var currNode = this.find(item); if (!(currNode.next == null)) { currNode.previous.next = currNode.next; currNode.next.previous = currNode.previous; currNode.next = null; currNode.previous = null; }else { currNode.previous.next = null; currNode.next = null; currNode.previous = null; } }
findLast() 方法查找鏈表中的最后一個節點,避免了從前往后遍歷鏈表
function findLast() { var currNode = this.head; while (!(currNode.next == null)) { currNode = currNode.next; } return currNode; }
dispReverse() 方法反序顯示雙向鏈表中的元素。
function dispReverse() { var currNode = this.head; currNode = this.findLast(); while (!(currNode.previous == null)) { console.log(currNode.element); currNode = currNode.previous; } }
2.3、循環鏈表
循環鏈表和單向鏈表相似,節點類型都是一樣的。唯一的區別是,在創建循環鏈表時,讓其頭節點的 next 屬性指向它本身,即鏈表的尾節點指向頭節點,形成了一個循環鏈表。如下圖: