TL;DR
2016 岁终末了一篇,对链表举行插进去排序。系列目次见 前言和目次 。
需求
完成一个 insertSort()
函数对链表举行升序分列(插进去排序)。完成历程当中能够运用 上一个 kata 中的 sortedInsert()
函数。insertSort()
函数接收链表头为参数并返回排序后的链表头。
var list = 4 -> 3 -> 1 -> 2 -> null
insertSort(list) === 1 -> 2 -> 3 -> 4 -> null
假如传入的链表为 null
或许只需一个节点,就原样返回。
关于插进去排序
插进去排序的引见能够看 Wikipedia ,大致逻辑为:
竖立一个新的空链表。
顺次遍历待排序的链表节点,挨个插进去新链表的适宜位置,始终保持新链表是已排序的。
遍历完成,返回新链表。
视察这段逻辑不难发明,第二个步骤实在就是上个 kata 中 sortedInsert
做的事变 — 把节点插进去一段已排序的链表的适宜位置。在此之上轻微包装一下就能够完成 insertSort
。
递归版本
起首我们记着两个函数的表达的意义:
insertSort
返回链表的排序版本。sortedInsert
把节点插进去一个已排序链表的适宜位置,并返回修改后的链表(也是已排序的)。
然后我们用递归的思绪形貌 insertSort
逻辑,应该是先把原链表的第一个节点插进去某个已排序的链表的适宜位置,这段逻辑能够用 sortedInsert(someList, head.data)
表达。而这个 “某个已排序的链表” ,我们须要它包括除了 head
以外其他的所以节点,这个链表能够用 insertSort(head.next)
来表达。
整顿后的代码以下:
function insertSort(head) {
if (!head) return null
return sortedInsert(insertSort(head.next), head.data)
}
轮回版本
轮回版本是最接近算法形貌的版本,所以不多赘述。代码以下:
function insertSort(head) {
for (var sortedList = null, node = head; node; node = node.next) {
sortedList = sortedInsert(sortedList, node.data)
}
return sortedList
}
总结
由于有上个 kata 的函数的协助,这个插进去排序完成起来异常简朴。递归版本再次表现了声明式编程的上风。有时候能表达某种数据的不只是变量,也能够是函数。只需我们发明表达适宜逻辑的函数,完成历程就会异常简朴。
算法相干的代码和测试我都放在 GitHub 上,假如对你有协助请帮我点个赞!