在数组排序中,常见的排序算法有:冒泡排序、选择排序、插入排序、希尔排序、归并排序、快速排序、堆排序、计数排序、桶排序、基数排序等。
而对于链表排序而言,因为链表不支持随机访问,访问链表后面的节点只能依靠 next 指针从头部顺序遍历,所以相对于数组排序问题来说,链表排序问题会更加复杂一点。
下面先来总结一下适合链表排序与不适合链表排序的算法:
适合链表的排序算法:冒泡排序、选择排序、插入排序、归并排序、快速排序、计数排序、桶排序、基数排序。
不适合链表的排序算法:希尔排序。
可以用于链表排序但不建议使用的排序算法:堆排序。
希尔排序为什么不适合链表排序?
希尔排序:希尔排序中经常涉及到对序列中第 i + gap 的元素进行操作,其中 gap 是希尔排序中当前的步长。而链表不支持随机访问的特性,导致这种操作不适合链表,因而希尔排序算法不适合进行链表排序。
为什么不建议使用堆排序?
堆排序:堆排序所使用的最大堆 / 最小堆结构本质上是一棵完全二叉树。而完全二叉树适合采用顺序存储结构(数组)。因为数组存储的完全二叉树可以很方便的通过下标序号来确定父亲节点和孩子节点,并且可以极大限度的节省存储空间。
而链表用在存储完全二叉树的时候,因为不支持随机访问的特性,导致其寻找子节点和父亲节点会比较耗时,如果增加指向父亲节点的变量,又会浪费大量存储空间。所以堆排序算法不适合进行链表排序。
如果一定要对链表进行堆排序,则可以使用额外的数组空间表示堆结构。然后将链表中各个节点的值依次添加入堆结构中,对数组进行堆排序。排序后,再按照堆中元素顺序,依次建立链表节点,构建新的链表并返回新链表头节点。
刚才我们说到如果一定要对链表进行堆排序,则需要使用额外的数组空间。除此之外,计数排序、桶排序、基数排序都需要用到额外的数组空间。
链表归并排序(通过)
分割环节:找到链表中心链节点,从中心节点将链表断开,并递归进行分割。
使用快慢指针 fast = head.next、slow = head,让 fast 每次移动 2 步,slow 移动 1 步,移动到链表末尾,从而找到链表中心链节点,即 slow。
从中心位置将链表从中心位置分为左右两个链表 left_head 和 right_head,并从中心位置将其断开,即 slow.next = None。
对左右两个链表分别进行递归分割,直到每个链表中只包含一个链节点。
归并环节:将递归后的链表进行两两归并,完成一遍后每个子链表长度加倍。重复进行归并操作,直到得到完整的链表。
使用哑节点 dummy_head 构造一个头节点,并使用 cur 指向 dummy_head 用于遍历。
比较两个链表头节点 left 和 right 的值大小。将较小的头节点加入到合并后的链表中。并向后移动该链表的头节点指针。
然后重复上一步操作,直到两个链表中出现链表为空的情况。
将剩余链表插入到合并中的链表中。
将哑节点 dummy_dead 的下一个链节点 dummy_head.next 作为合并后的头节点返回。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:def merge(self,left,right):dummy_head = ListNode(-1)cur = dummy_headwhile left and right:if left.val <= right.val:cur.next = leftleft = left.nextelse:cur.next = rightright = right.nextcur = cur.nextif left:cur.next = leftelif right:cur.next = rightreturn dummy_head.nextdef mergeSort(self,head:ListNode):if not head or not head.next:return head# 快慢指针找到中心链节点slow,fast = head,head.nextwhile fast and fast.next:slow = slow.nextfast = fast.next.next# 断开左右链节点 left_head,right_head = head, slow.nextslow.next = None# 归并操作return self.merge(self.mergeSort(left_head),self.mergeSort(right_head))def sortList(self, head: Optional[ListNode]) -> Optional[ListNode]:return self.mergeSort(head)