[ 插入排序 ]147. 对链表进行插入排序

217 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情

每日刷题 2021.04.03

题目

  • 给定单个链表的头 head ,使用 插入排序 对链表进行排序,并返回 排序后链表的头 。
  • 插入排序 算法的步骤:
  • 插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。
  • 每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。
  • 重复直到所有输入数据插入完为止。
  • 下面是插入排序算法的一个图形示例。部分排序的列表(黑色)最初只包含列表中的第一个元素。每次迭代时,从输入数据中删除一个元素(红色),并就地插入已排序的列表中。
  • 对链表进行插入排序。

示例

输入: head = [4,2,1,3]
输出: [1,2,3,4]

解题思路

拓展

  • 所谓稳定性:就是两个相等的元素在数组中相对的位置,排序后是否改变
    • 不改变:稳定的排序
    • 改变:不稳定的排序

插入排序

  • 生活中的场景:打扑克牌的时候,每次摸一张牌,就将它插入到手上已有的牌中的合适位置,逐渐完成整个排序。
  • 遍历过程中,write 指针都指向当前链表之前最大的那个值,所以当 read 指针读到了小于write指针的是,需要作出删除插入的操作
  • 首先write 指针就是 read 的前一个指针,所以很容易就能删除当前的 read 指针
  • 然后找到插入点,这里如果是双向指针,可以从尾到前查找,当然也可以从 head 开始查找
  • 从起始 head 节点开始查找比当前 read 指针值大的节点,在它之前插入
  • 最后得到链表就是所求: 在遍历的过程中反复遍历,时间复杂度应该是0(nlogn)

快速排序(经典题目)

AC代码

var insertionSortList = function(head) {
    if(!head || !head.next) return head
    let  emptyNode = new ListNode()
    emptyNode.next = head
    let  write = head
    let read =write.next
    while(read){
        if(read.val<write.val){
            // 先删除
            let next = read.next
            write.next = next

            // 从empty指针开始,查找要插入的位置
            let prev = emptyNode
            let temp = emptyNode.next
            while(temp.val<=read.val){
                temp = temp.next
                prev = prev.next
            }
            // 插入到 temp 之前
            prev.next = read
            read.next = temp
            read = next
        }else{
            read = read.next
            write=write.next
        }
    }
    return emptyNode.next
};

总结

  • 在一些有时间复杂度要求的题目中,使用快速排序,会比冒泡排序更优。