基础
链表是一种在物理存储单元中非连续,非顺序的数据结构,它的逻辑顺序是通过指针链接次序实现的。一个单链表的节点在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);
}
}