基礎
連結串列是一種在物理儲存單元中非連續,非順序的資料結構,它的邏輯順序是通過指標連結次序實現的。一個單連結串列的節點在Javascript中可以表示為:
function Node(data){
this.data = data;
this.next = null;
}
複製程式碼
單連結串列的結構示意圖如下:
連結串列的實現
連結串列需要實現的幾個基本的方法是:append(向連結串列尾部追加節點),print(列印整個連結串列的元素),insert(向某個index位置插入新節點),remove(刪除某個位置index的節點),get(獲取某個位置index的節點),indexOf(給定某資料,查詢它在連結串列的哪個位置)。
function LinkList() {
let Node = function(data) {
this.data = data;
this.next = null;
}
let length = 0;
let head = null;
let tail = null;
this.append = function(data) {
let node = new Node(data)
if (head == null) {
head = node;
tail = node;
} else {
tail.next = node;
tail = node;
}
length = length + 1;
return true;
};
this.print = function() {
let curr_node = head;
while (curr_node) {
console.log(curr_node.data);
curr_node = curr_node.next;
}
};
this.insert = function(index, data) {
if (index < 0 || index > length) {
return false;
} else if (index == length) {
return this.append(data);
} else {
let node = new Node(data);
if (index == 0) {
node.next = head;
head = node;
} else {
let insert_index = 1;
let curr_node = head;
while (insert_index < index) {
insert_index += 1;
curr_node = curr_node.next;
}
let next_node = curr_node.next;
node.next = next_node;
curr_node.next = node;
}
length = length + 1;
return true;
}
};
this.remove = function(index) {
if (index < 0 || index >= length) {
return false;
} else {
let del_node = null;
if (index == 0) {
del_node = head;
head = head.next;
} else {
let del_index = 1;
let curr_node = head;
while (del_index < index) {
del_index += 1;
curr_node = curr_node.next;
}
del_node = curr_node.next;
let next_node = curr_node.next.next;
curr_node.next = next_node;
if (del_node.next == null) {
tail = curr_node;
}
}
length = length - 1;
return del_node.data;
}
};
this.get = function(index) {
if (index < 0 || index >= length) {
return null;
} else {
if (index == 0) {
return head;
} else {
let curr_node = head;
let curr = 0;
while (curr < index) {
curr += 1;
curr_node = curr_node.next;
}
return curr_node.data;
}
}
}
this.indexOf = function(data) {
let index = -1;
let curr_node = head;
while (curr_node) {
index += 1
if (curr_node.data == data) {
return index;
} else {
curr_node = curr_node.next;
}
}
return -1;
}
}
let link = new LinkList();
link.append(2);
link.append(4);
link.append(8);
link.append(7);
link.print()
複製程式碼
連結串列的應用題
- 反轉單連結串列
比較常考的一道題,有兩種方式來解決,一種是迭代法,一種是遞迴法。迭代法就是需要定義三個節點指標,一個指向當前節點,一個指向前面一個節點,一個指向後面一個節點,反轉就是說,當前節點的next指標指向前面一個節點。
遞迴方法就是你不會反轉當前連結串列,讓遞迴方法先幫你反轉當前節點的下一個節點開始的單連結串列,把反轉後的頭節點返回。你再將當前頭節點連線到返回頭節點的尾部。
class Node {
constructor(data) {
this.data = data;
this.next = null;
}
}
let node1 = new Node(1);
let node2 = new Node(2);
let node3 = new Node(3);
let node4 = new Node(4);
node1.next = node2;
node2.next = node3;
node3.next = node4;
node4.next = null;
function print(node) {
let str = "";
while (node) {
str += node.data.toString() + "->";
node = node.next;
}
str += "null"
console.log(str);
}
print(node1);
function reverse(node) {
if (!node) {
return null;
}
let curr_node = node;
let pre_node = null;
while (curr_node) {
let next_node = curr_node.next;
curr_node.next = pre_node;
pre_node = curr_node;
curr_node = next_node;
}
return pre_node;
}
let node = reverse(node1);
print(node);
function reverse_digui(node) {
if (!node) {
return null;
}
if(node.next == null){
return node;
}
let new_head = reverse_digui(node.next);
node.next.next = node;
node.next = null;
return new_head;
}
複製程式碼
- 從尾到頭列印單連結串列
還是用遞迴方法,不知道如何反向列印,就先讓下一個節點所在的單連結串列反向列印,等全部列印完,再把自己列印出來。
function reverse_print(node){
if(!node){
return null;
}
if(node == null){
return;
}else{
reverse_print(node.next);
console.log(node.data);
}
}
複製程式碼