算法与数据结构全阶班-左程云版(二)基础阶段之3.归并排序和快速排序(下)

简介: 本文主要介绍了两种排序,归并排序和快速排序,归并排序有递归和非递归2种方式实现,快速排序的升级版为荷兰国旗问题。

2.快速排序

Partition过程:

给定一个数组arr,和一个整数num。请把小于等于num的数放在数组的左边,大于num的数放在数组的右边;

要求额外空间复杂度O(1),时间复杂度O(N)。

思路如下:

2345_image_file_copy_125.jpg

Partition过程升级版(荷兰国旗问题):

给定一个数组arr,和一个整数num。请把小于num的数放在数组的左边,等于num的数放在数组的中间,大于num的数放在数组的右边;

要求额外空间复杂度O(1),时间复杂度O(N)。

思路如下:

2345_image_file_copy_126.jpg

两种分区实现如下:

public class PartitionAndQuickSort {
    /*
    普通分区:
    给定一个数组arr和一个整数num,
    请把小于等于num的数放在数组的左边,
    大于num的数放在数组的右边
     */
    public static int partition(int[] arr, int L, int R) {
        if (L > R) {
            return -1;
        }
        if (L == R) {
            return L;
        }
        int lessEqual = L - 1;
        int index = L;
        while (index < R) {
            if (arr[index] <= arr[R]) {
                swap(arr, index, ++lessEqual);
            }
            index++;
        }
        swap(arr, ++lessEqual, R);
        return lessEqual;
    }
    /*
    分区升级版:荷兰国旗:
    给定一个数组arr和一个整数num
    请把小于num的数放在数组的左边,
    等于num的数放在数组的中间,
    大于num的数放在数组的右边
     */
    public static int[] netherlandsFlag(int[] arr, int L, int R) {
        if (L > R) {
            return new int[]{-1, -1};
        }
        if (L == R) {
            return new int[]{L, R};
        }
        int less = L - 1, more = R;
        int index = L;
        while (index < more) {
            if (arr[index] == arr[R]) {
                index++;
            } else if (arr[index] < arr[R]) {
                swap(arr, index++, ++less);
            } else {
                swap(arr, index, --more);
            }
        }
        swap(arr, more, R);
        return new int[]{less + 1, more};
    }
    public static void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
}

快速排序:

快速排序有3种方式:

(1)利用普通分区算法;

(2)利用荷兰国旗算法;

(3)随机选数与最后一个数交换,再利用荷兰国旗算法。

分析时间复杂度:

随机快排的时间复杂度分析:

1)通过分析知道,划分值越靠近中间,性能越好;越靠近两边,性能越差

2)随机选一个数进行划分的目的就是让好情况和差情况都变成概率事件

3)把每一种情况都列出来,会有每种情况下的时间复杂度,但概率都是1/N

4)那么所有情况都考虑,时间复杂度就是这种概率模型下的长期期望,

时间复杂度O(N*logN),额外空间复杂度O(logN)都是这么来的。

(1)前两种:

最差情况是数组已经有序:

2345_image_file_copy_128.jpg

(2)第三种

一般情况是获取到的随机数在数组中间位置附近,就属于较好的情况:

2345_image_file_copy_129.jpg

2345_image_file_copy_130.jpg

空间复杂度:

2345_image_file_copy_131.jpg

最差情况下是O(N),累加求期望收敛于O(LogN)。

3种快速排序实现如下:

public static void quickSort1(int[] arr) {
    if (null == arr || arr.length < 2) {
        return;
    }
    process1(arr, 0, arr.length-1);
}
public static void process1(int[] arr, int L, int R) {
    if (L >= R) {
        return;
    }
    int M = partition(arr, L, R);
    process1(arr, L, M - 1);
    process1(arr, M + 1, R);
}
public static void quickSort2(int[] arr) {
    if (null == arr || arr.length < 2) {
        return;
    }
    process2(arr, 0, arr.length-1);
}
public static void process2(int[] arr, int L, int R) {
    if (L >= R) {
        return;
    }
    int[] equalArea = netherlandsFlag(arr, L, R);
    process1(arr, L, equalArea[0] - 1);
    process1(arr, equalArea[1]+ 1, R);
}
public static void quickSort3(int[] arr) {
    if (null == arr || arr.length < 2) {
        return;
    }
    process3(arr, 0, arr.length-1);
}
public static void process3(int[] arr, int L, int R) {
    if (L >= R) {
        return;
    }
    swap(arr, (int) (Math.random() * (R + 1)), R);
    int[] equalArea = netherlandsFlag(arr, L, R);
    process1(arr, L, equalArea[0] - 1);
    process1(arr, equalArea[1]+ 1, R);
}

总结

归并排序有很多个应用场景,一般应用在数组中左边的数比右边的数满足某个条件时,进行某个操作,都可以在归并的过程中进行解决。

目录
打赏
0
0
0
0
2
分享
相关文章
|
3天前
|
算法系列之数据结构-二叉树
树是一种重要的非线性数据结构,广泛应用于各种算法和应用中。本文介绍了树的基本概念、常见类型(如二叉树、满二叉树、完全二叉树、平衡二叉树、B树等)及其在Java中的实现。通过递归方法实现了二叉树的前序、中序、后序和层次遍历,并展示了具体的代码示例和运行结果。掌握树结构有助于提高编程能力,优化算法设计。
32 9
 算法系列之数据结构-二叉树
|
2天前
|
算法系列之数据结构-二叉搜索树
二叉查找树(Binary Search Tree,简称BST)是一种常用的数据结构,它能够高效地进行查找、插入和删除操作。二叉查找树的特点是,对于树中的每个节点,其左子树中的所有节点都小于该节点,而右子树中的所有节点都大于该节点。
43 22
C 408—《数据结构》算法题基础篇—链表(下)
408考研——《数据结构》算法题基础篇之链表(下)。
88 29
C 408—《数据结构》算法题基础篇—链表(上)
408考研——《数据结构》算法题基础篇之链表(上)。
99 25
C 408—《数据结构》算法题基础篇—数组(通俗易懂)
408考研——《数据结构》算法题基础篇之数组。(408算法题的入门)
72 23
|
4月前
|
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
381 9
|
4月前
|
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
64 1
|
2月前
|
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
158 77
|
7天前
|
STL——栈和队列和优先队列
通过以上对栈、队列和优先队列的详细解释和示例,希望能帮助读者更好地理解和应用这些重要的数据结构。
17 4
☀☀☀☀☀☀☀有关栈和队列应用的oj题讲解☼☼☼☼☼☼☼
### 简介 本文介绍了三种数据结构的实现方法:用两个队列实现栈、用两个栈实现队列以及设计循环队列。具体思路如下: 1. **用两个队列实现栈**: - 插入元素时,选择非空队列进行插入。 - 移除栈顶元素时,将非空队列中的元素依次转移到另一个队列,直到只剩下一个元素,然后弹出该元素。 - 判空条件为两个队列均为空。 2. **用两个栈实现队列**: - 插入元素时,选择非空栈进行插入。 - 移除队首元素时,将非空栈中的元素依次转移到另一个栈,再将这些元素重新放回原栈以保持顺序。 - 判空条件为两个栈均为空。
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等