📅  最后修改于: 2023-12-03 15:27:10.513000             🧑  作者: Mango
双向链表是一种常见的数据结构,它允许在数据中间进行快速的插入和删除操作。合并排序是一种高效的排序算法,它通过将一个数组分成两个部分,分别排序,然后合并这两部分,从而达到排序的目的。
在本文中,我们将介绍如何使用 JavaScript 实现双向链表的合并排序算法。我们将从定义数据结构开始,然后讨论排序算法的实现。
我们首先需要定义一个双向链表的数据结构,它包含两个属性:前驱指针和后继指针。每个节点都包含一个数据元素,以及指向前驱和后继节点的指针。
class Node {
constructor(data) {
this.data = data;
this.prev = null;
this.next = null;
}
}
class DoublyLinkedList {
constructor() {
this.head = null;
this.tail = null;
this.count = 0;
}
}
在代码中,我们使用 class
关键字定义了 Node
和 DoublyLinkedList
两个类。Node
类表示链表中的一个节点,它有一个 data
属性用于存储数据,以及两个指针 prev
和 next
,分别用于指向前驱和后继节点。DoublyLinkedList
类表示整个链表,它有 head
和 tail
两个指针,分别指向链表的头节点和尾节点,以及一个 count
属性,统计链表中节点的数量。
我们还可以定义一些方法来操作双向链表,例如添加和删除节点等。这里我们只定义一个用于输出链表中所有节点的方法:
print() {
let current = this.head;
let result = '';
while (current) {
result += `${current.data} `;
current = current.next;
}
console.log(result);
}
有了数据结构,我们就可以开始实现双向链表的合并排序算法了。我们可以先将链表按照某个规则拆分成两个部分,然后递归地对这两部分进行排序,最后将它们合并在一起。
mergeSort(list) {
if (!list || !list.head || !list.head.next) {
return list;
}
let [left, right] = this.split(list);
left = this.mergeSort(left);
right = this.mergeSort(right);
return this.merge(left, right);
}
在代码中,我们定义了一个 mergeSort
方法,它接受一个双向链表作为参数。如果链表为空或只包含一个节点,就直接返回原链表。否则,我们使用 split
方法将链表拆分成两个部分,然后递归地对这两个部分进行排序,最后使用 merge
方法将它们合并在一起。
接下来,我们实现 split
和 merge
两个方法。
split
方法用于将双向链表按照某个规则拆分成两个部分。这里我们采用的规则是将链表分成前半部分和后半部分。我们使用 fast
和 slow
两个指针,fast
每次走两步,slow
每次走一步,当 fast
走到链表末尾时,slow
正好走到中间节点。
split(list) {
let fast = list.head;
let slow = list.head;
while (fast.next && fast.next.next) {
fast = fast.next.next;
slow = slow.next;
}
let left = list;
let right = new DoublyLinkedList();
right.head = slow.next;
slow.next.prev = null;
right.count = left.count - Math.floor(left.count / 2);
left.tail = slow;
left.tail.next = null;
left.count = Math.floor(left.count / 2);
return [left, right];
}
merge
方法用于将两个有序的双向链表合并成一个有序链表。我们使用了两个指针 p
和 q
分别指向两个链表的头节点,比较两个节点的大小,并将较小的节点插入到新链表的末尾。当其中一个链表遍历结束后,我们将另一个链表中剩余的节点插入到新链表的末尾。
merge(left, right) {
let p = left.head;
let q = right.head;
let newHead = new Node(null);
let current = newHead;
while (p && q) {
if (p.data <= q.data) {
current.next = p;
p.prev = current;
p = p.next;
} else {
current.next = q;
q.prev = current;
q = q.next;
}
current = current.next;
}
if (p) {
current.next = p;
p.prev = current;
left.tail = right.tail;
}
if (q) {
current.next = q;
q.prev = current;
left.tail = right.tail;
}
let result = new DoublyLinkedList();
result.head = newHead.next;
result.count = left.count + right.count;
return result;
}
class Node {
constructor(data) {
this.data = data;
this.prev = null;
this.next = null;
}
}
class DoublyLinkedList {
constructor() {
this.head = null;
this.tail = null;
this.count = 0;
}
print() {
let current = this.head;
let result = '';
while (current) {
result += `${current.data} `;
current = current.next;
}
console.log(result);
}
split(list) {
let fast = list.head;
let slow = list.head;
while (fast.next && fast.next.next) {
fast = fast.next.next;
slow = slow.next;
}
let left = list;
let right = new DoublyLinkedList();
right.head = slow.next;
slow.next.prev = null;
right.count = left.count - Math.floor(left.count / 2);
left.tail = slow;
left.tail.next = null;
left.count = Math.floor(left.count / 2);
return [left, right];
}
merge(left, right) {
let p = left.head;
let q = right.head;
let newHead = new Node(null);
let current = newHead;
while (p && q) {
if (p.data <= q.data) {
current.next = p;
p.prev = current;
p = p.next;
} else {
current.next = q;
q.prev = current;
q = q.next;
}
current = current.next;
}
if (p) {
current.next = p;
p.prev = current;
left.tail = right.tail;
}
if (q) {
current.next = q;
q.prev = current;
left.tail = right.tail;
}
let result = new DoublyLinkedList();
result.head = newHead.next;
result.count = left.count + right.count;
return result;
}
mergeSort(list) {
if (!list || !list.head || !list.head.next) {
return list;
}
let [left, right] = this.split(list);
left = this.mergeSort(left);
right = this.mergeSort(right);
return this.merge(left, right);
}
}
在本文中,我们介绍了如何使用 JavaScript 实现双向链表的合并排序算法。我们首先定义了一个双向链表的数据结构,包含了节点、指针、以及一些常用的操作方法。然后,我们讨论了合并排序算法的实现,通过递归的方式将链表拆分成两个部分,分别进行排序,最后将它们合并在一起。在实现过程中,我们需要用到一些常见的链表操作技巧,例如快慢指针、指针移动等。