python数据结构学习笔记-2016-11-26-01-链表排序

        12.5 链表排序

        12.5.1 插入排序

         将原链表的每一个结点取出,放入到新的排序链表中。

#-*-coding: utf-8-*-

# 链表的插入排序

def llistInsertionSort(origList):
    # 确保链表非空
    if origList is None:
        return 
    # 对原链表遍历
    newList = None
    while origList is not None:
        # 临时外部指针
        curNode = origList
        # 移动原链表的头指针
        origList = origList.next
        # 将结点从原链表中抽离,并放入到新的排序链表中
        curNode.next = None
        newList = addToSortedList(newList, curNode)
    return newList

def addToSortedList(head, node):
    predNode = None
    curNode = head
    while curNode is not None and node.data > curNode.data:
        predNode = curNode
        curNode = curNode.next
    node.next = curNode
    if curNode is head:
        head = node
    else:
        predNode.next = node
        与python列表类似,其时间复杂度也是O(n²)。不同之处在于,不需要像列表那样,对每一个元素进行移位。





        12.5.2 归并排序

#-*-coding: utf-8-*-

# 链表的归并排序

def llistMergeSort(theList):
    # 如果链表为空,即递归终止条件,返回None
    if theList is None:
        return None
    # 分割链表成两部分
    rightList = _splitLinkedList(theList)
    leftList = theList
    # 对左半部分链表分割
    leftList = llistMergeSort(leftList)
    # 对右半部分分割
    rightList = llistMergeSort(rightList)
    # 合并两个排好序的子链表
    theList = _mergeLinkedLists(leftList, rightList)
    return theList

# 分割链表,返回右半部分链表的头指针,左半部分链表的头指针,仍然是原链表的头指针
def _splitLinkedList(subList):
    # 临时外部指针,分别指向第一和第二个结点
    midPoint = subList
    curNode = midPoint.next
    # 对原链表进行遍历,curNode的移动速度是midPoint的两倍,当curNode移动至原链表末尾时,此时midPoint正好移动到链表中间的位置
    while curNode is not None:
        curNode = curNode.next
        if curNode is not None:
            midPoint = midPoint.next
            curNode = curNode.next
    rightList = midPoint.next # 设置右半部分链表的头指针
    midPoint.next = None # 将右半部分链表从原链表中分离
    return rightList

# 合并两个排好序的子链表
def _mergeLinkedLists(subListA, subListB):
    # 创建假结点
    newList = ListNode(None)
    newTail = newList
    # 向新链表补插入subListA和subListB的结点,直到遍历完其中一个链表为止
    while subListA is not None and subListB is not None:
        if subListA.data <= subListB.data:
            newTail.next = subListA
            subListA = subListA.next
        else:
            newTail.next = subListB
            subListB = subListB.next
        newTail = newTail.next
        newTail.next = None
    # 将另一个链表的剩余部分,也添加到新链表中来
    if subListA is not None:
        newTail.next = subListA
    else:
        newTail.next = subListB
    # 返回假结点的下一个结点
    return newList.next

         与之前序列的归并排序不同的是,链表的归并排序并不需要包装函数,因为只需传入链表的头指针即可。我们要注意的是两个辅助方法。

         _splitLinkedList()将原链表分割成两部分,尤其值得注意的是两个外部指针midPoint和curNode的移动,后者的移动速度是前者的两倍,当curNode移动至链表末尾时,midPoint正好指向链表的中间位置,再将右半部分的头指针设置为midPoint的下一个结点即可,左半部分的头指针仍是原来的头指针,最后将两者分开即可。





        再看另一个辅助方法_mergeLinkedLists(),该方法主要是将两个排好序的链表合并。它使用尾指针的目的在于,在链表的末尾补插元素(元素从小到大排列)只需要O(1)的时间复杂度。此外,该方法还使用了假结点(dummy node),假结点是数据域为None的结点,使用它可以在插入或删除结点时避免使用if来分情况讨论(?)。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值