zoukankan      html  css  js  c++  java
  • 快速排序

    快速排序思路:

    1)选定一个基准元素;
    2)经过一趟排序,将所有元素分成两部分;
    3)分别对两部分重复上述操作,直到所有元素都已排序成功。

    因为单链表只能从链表头节点向后遍历,没有prev指针,因此必须选择头节点作为基准元素。这样第二步操作的时间复杂度就为O(n)。由于之后都是分别对两部分完成上述操作,因此会将链表划分为logn个段,因此时间复杂度为O(nlogn) 。

    可以看出,快排实现也是先对数据进行一遍遍历找到关键值得位置,和数组不同的是数组可以从两端向中间靠拢,但是单向链表只能从一段开始,但用两个指针同样可以实现。

    图解示意:

    以[4,2,5,3,7,9,0,1]为例模拟一趟快排的过程:

    1、初始化时,i指向链表首元素4;j = i +1,指向2。基准数字为当前i 指向的数字:4。

    j
    4 2 5 3 7 9 0 1
    i

    2、随后开始循环,j 当前指向2,因为2小于4,所以要把2移动到前面去。

    按照算法步骤操作:

    • i ++,首先 i 向后移动一位,指向2;
    • swap(i, j) ,随后交换 i、j 位置的值,这里面是2和2自己交换;
    • j ++,然后 j 向后移动一位,指向5;

    执行一次交换后的结果如下:

    j
    4 2 5 3 7 9 0 1
    i

    3、接下来,由于 j 指向的值5 大于4,直接跳过,执行j++,此时 j 指向3;

    j
    4 2 5 3 7 9 0 1
    i

    4、 j 指向的值为3,小于4,仿照步骤2,我们再次执行一次交换移动过程。

    • i ++,首先 i 向后移动一位,指向5;
    • swap(i, j) ,随后交换 i、j 位置的值,这里面是5和3交换;
    • j ++,然后 j 向后移动一位,指向7;

    交换后的结果如下:

    j
    4 2 3 5 7 9 0 1
    i

    5、j指向的值为7,大于4,所以直接跳过,执行 j++,j 指向9:

    j
    4 2 3 5 7 9 0 1
    i

    6、同理,j 指向的值为9,也大于4,跳过,执行 j++,j 指向0:

    j
    4 2 3 5 7 9 0 1
    i

    7、j 指向的值为0,小于4,执行一次交换过程:

    • i ++,首先 i 向后移动一位,指向5
    • swap(i, j) ,随后交换 i、j 位置的值,这里面是5和0交换
    • j ++,然后 j 向后移动一位,指向1

    交换后的结果如下:

    j
    4 2 3 0 7 9 5 1
    i

    8、j 指向的值为1,小于4,我们再执行一次交换过程

    • i ++,首先 i 向后移动一位,指向7
    • swap(i, j) ,随后交换 i、j 位置的值,这里面是7和1交换
    • j ++,然后 j 向后移动一位,已经超过了链表的长度,不再向后移动。

    交换后的结果如下:

    j
    4 2 3 0 1 9 5 7
    i

    9、最后,交换当前 i指向的值1,和4。得到[1、2、3、0、4、9、5、7],一趟排序结束。

    j
    1 2 3 0 4 9 5 7
    i

    此时可见:4的左边都是小于4的数字,右边都是大于4的数字,一趟排序确定了一个数字最终位置。

    接下来,对左边和右边分别排序,递归,直到元素全部有序。

    代码实现:

    # Definition for singly-linked list.
    class ListNode(object):
        def __init__(self, val):
            self.val = val
            self.next = None
            
    class LinkList(object):
        # 单链表快速排序
        def quickSort(self, head):
            """
            :type head: ListNode
            :rtype: ListNode
            """
            if not head or not head.next:
                return head
            ans = ListNode(0)
            ans.next = head
            return self.sort(ans, None)
        
        def sort(self, head, end):
            if head == end or head.next == end or head.next.next == end:
                return head
            tpmHead = ListNode(0)
            # 划分节点
            poi = head.next
            # 遍历指针
            cur = poi
            pre = tpmHead
            # 一趟划分
            while cur.next != end:
                # 当前节点值域小于划分节点的值域,则将当前节点放到左侧
                if cur.next.val < poi.val:
                    pre.next = cur.next
                    pre = pre.next
                    cur.next = cur.next.next
                else:
                    cur = cur.next
            # 合并临时链表和原链表,将原链表接到临时链表后面即可
            pre.next = head.next
            head.next = tpmHead.next
            self.sort(head, poi)
            self.sort(poi, end)
            return head.next
    
    

    运行截图:

  • 相关阅读:
    Rust语言环境配置;Rust版本1.45.2学习
    《代码英雄》系列整理
    Pingcap High Performance TiDB 课程学习记录@yaowenxu
    11. C语言百钱买百鸡问题(详解版)
    10. C语言输出菱形(详解版)
    9. C语言判断素数(求素数)(两种方法)
    8. C语言求圆周率π(三种方法)
    7. C语言杨辉三角(两种方法)
    6. C语言九九乘法表(五种输出形式)
    5. C语言希尔排序算法
  • 原文地址:https://www.cnblogs.com/panweiwei/p/12897773.html
Copyright © 2011-2022 走看看