快速排序——数组and链表实现

421 阅读2分钟

原理

选择一个基准线,利用二分法,使得基准线位于正确的位置(大于基准的在它右边,小于的在左边,直到分到最后一个元素)

复杂度

时间复杂度:O(nlog2n) 空间复杂度:O(nlog2n)第一个基准需要进行n-1次比较,之后二分进行log2n次

数组代码实现

首位设定为key,首位和末尾放指针i j ,从右开始找(j--)比key小的放到i 位置,再从左开始找比key大的,放到j位置,直到i j 相遇,将key放到相遇点。再利用二分法进行左右的快速排序。

image.png 图片来源:www.cnblogs.com/skywang1234…

就是一个把大的放右边 小的放左边的过程

int getStandard(int array[], int i, int j) {
    // 基准数据
    int key = array[i];
    while (i < j) {
        // 因为默认基准是从左边开始,所以从右边开始比较,
       //因为如果从左边开始,第一个数就没法移动了
        // 当队尾的元素大于等于基准数据 时,就一直向前挪动 j 指针
        while (i < j && array[j] >= key) {
            j--;
        }
        // 当找到比 array[i] 小的时,就把后面的值 array[j] 赋给它
        if (i < j) {
            array[i] = array[j];
        }
        // 当队首元素小于等于基准数据 时,就一直向后挪动 i 指针
        while (i < j && array[i] <= key) {
            i++;
        }
        // 当找到比 array[j] 大的时,就把前面的值 array[i] 赋给它
        if (i < j) {
            array[j] = array[i];
        }
    }
    // 跳出循环时 i 和 j 相等,此时的 i 或 j 就是 key 的正确索引位置
    // 把基准数据赋给正确位置
    array[i] = key;
    return i;
}

void QuickSort(int array[], int low, int high) {
    // 开始默认基准为 low
    if (low < high) {
        // 分段位置下标
        int standard = getStandard(array, low, high);
        // 递归调用排序
        // 左边排序
        QuickSort(array, low, standard - 1);
        // 右边排序
        QuickSort(array, standard + 1, high);
    }
}

代码来源:blog.csdn.net/weixin_4210…

链表代码

148.排序链表 给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。

class Solution {
public ListNode sortList(ListNode head) {
        if(head==null||head.next==null) return head;
        // 没有条件,创造条件。自己添加头节点,最后返回时去掉即可。
        ListNode newHead=new ListNode(-1);
        newHead.next=head;
        return quickSort(newHead,null);
    }
    // 带头结点的链表快速排序
    private ListNode quickSort(ListNode head,ListNode end){
        if (head==end||head.next==end||head.next.next==end) return head;
        // 将小于划分点的值存储在临时链表中
        ListNode tmpHead=new ListNode(-1);
        // partition为划分点,p为链表指针,tp为临时链表指针
        ListNode partition=head.next,p=partition,tp=tmpHead;
        // 将小于划分点的结点放到临时链表中
        while (p.next!=end){
            if (p.next.val<partition.val){
                // 将小于它的节点储存到 临时链表,并后移一位指针
                tp.next=p.next;
                tp=tp.next;
                // 将小于partition的节点删除掉
                p.next=p.next.next;
            }else {
                // 大的话不删除,后移指针
                p=p.next;
            }
        }
        // 合并临时链表和原链表,将原链表接到临时链表后面即可(这是的临时链表就是从小到大了)
        tp.next=head.next;
        // 将临时链表插回原链表,注意是插回!(不做这一步在对右半部分处理时就断链了)
        head.next=tmpHead.next;
        quickSort(head,partition);
        quickSort(partition,end);
        // 题目要求不带头节点,返回结果时去除
        return head.next;
    }
}