八大排序------数据结构

本文详细介绍了排序的定义、稳定性及其重要性,接着讲解了七大内部排序算法,包括选择排序、插入排序、希尔排序、归并排序、快速排序、堆排序和冒泡排序,特别强调了快速排序在不同场景下的优化策略,如随机化、非递归实现、二路快排等,并探讨了海量数据排序的处理方法。
摘要由CSDN通过智能技术生成

目录

1.排序是什么?

2.排序的稳定性

 3.七大排序的时间复杂度与空间复杂度

4.选择排序

5.插入排序(O(n^2)) 类似于打牌(稳定)

6.希尔排序:缩小增量的排序(不稳定)

7.归并排序(和希尔排序很像)

8.快速排序(基于算法导论中的分区思想)重要

8.1随机化快排的问题:

8.2快排的非递归实现

8.3二路快排

8.4挖坑法分区方法代码(直到在纸上如何画图即可)

8.5三路快排 (了解)

9.堆排序(非常稳定)

10.冒泡排序(时间复杂度o(n^2))

 11.面试题:海量数据的排序处理(常考)

题外话:设置注释

七大排序代码:

1.排序是什么?

排序就是一串记录,按照其中的某个或者某些关键字的大小,递增或递减的排列起来的操作。

2.排序的稳定性

两个相等的数据,如果经过排序,排序算法能保证其相对位置不发生变化,则我们称该算法是具备稳定性的排序算法。

 为什么稳定性这么重要?

 3.七大排序的时间复杂度与空间复杂度

这里都是内部排序(一次性将所有待排序的数据放入内存中进行排序,基于元素之间的比较的排序)

而外部排序 :依赖硬盘(外部存储器)进行的排序算法,桶排序、基数排序、基数排序(对于数据集合的要求非常高,只能在特定的场合下使用)。时间复杂度都是O(n),应用场景非常局限,只能在特定的场景下去应用。内存放不下,需要外部存储。

器,称为海量排序算法。

4.选择排序

每次从无序区间中选择一个最大或最小值,存放在无需区间的最前或者最后的位置(此位置的元素已经有序) ,直到所有的数据都排序结束。

为什么选择排序不稳定?

选择排序的进阶版本

双向选择排序,一次排序过程中,同时选出最大值和最小值,放在无需区间的最后和最前。 

5.插入排序(O(n^2)) 类似于打牌(稳定)

思路:将集合分为俩个区间,i是当前已经便利的元素,一个已经排序的区间[0...i),一个待排序的区间(i...n]。

每次从待排序区间找到一个元素,放入已排序的区间的合适位置,直到整个数组有序。

在近乎有序的数组下,插入排序的数组性能非常好,甚至优于nlog(n)的排序。

插入排序和选择排序最大的不同在于:当插入排序当前遍历的元素>前驱元素时,此时可以提前结束内层循环。

极端场景下,当集合是一个完全有序的集合,插入排序内层循环一次都不走,插入排序时间复杂度变为O(n)。

插入排序经常用作高阶排序算法的优化手段之一

了解:插入排序优化的手段:(用二分查找法)

折半插入排序:

首先:二分查找的前提是该集合必须是一个有序的集合。

而在插入排序中,我们每次都是在有序区间中找一个合适的插入位置,所以可以使用二分查找法来定位元素的插入位置。

这里注意这个公式为什么要这么写:(是为了防止溢出)

6.希尔排序:缩小增量的排序(不稳定)

 先选定一个整数(gap,gap一般都选数组长度的一半或者1/3)

将待排序的数组先按照gap分组,不同组之间使用插入排序,排序之后,再将gap/==2或者gap/=3,重复上述的流程,直到gap=1

当gap=1时,整个数组已经被调整的近乎有序,此时就是插入排序最好的场景,最后再在整个数据上进行一次插入排序。

插入排序和希尔排序,当gap=1时,公式完全一样。

希尔排序为什么要不断地向前比较,能否从零开始向后看gap步?

例:3-----2-----1

不断向后比较

2-----3-----1

2-----1-----3

这样的话,2就没办法换到合适的位置了 

7.归并排序(和希尔排序很像)

思想:将原数组不断拆分,一直拆到每个子数组只有一个元素,第一个阶段结束,归而为1这个阶段结束。

并:将相邻的两个数组合并为一个有序的数组,直到整个数据有序。

分:用的是递归

并:第一步:先创建一个大小为合并之后数组大小的临时数组aux,将数组的值拷贝过去。

第二步:如下

 为何合并过程需要创建一个新的aux数组?

防止在合并过程中,因为小元素要覆盖大的元素,丢失某些元素

归并排序是一个稳定的nlogN排序算法,此处的稳定指的是时间复杂度稳定(无论集合中的元素如何变化,归并排序的时间复杂度一直都是nlogN,不会退化为O(N^2))且归并排序也是一个稳定性的排序算法(相等元素的先后顺序并不会发生改变)。

(递归类似于树结构,n不断的2/2/2/2,直到只剩下一个元素,这就是logN(树的高度)级别的样子)

递归的深度就是我们拆分数组所用的时间,就是树的高度,logN。

 public static void mergeSort(int []arr){
        mergeSortInternal(arr,0,arr.length-1);
    }
    //在arr[l..r]进行归并排序
    private static void mergeSortInternal(int[] arr, int l, int r) {
        if(l>=r){
            //当前数组只剩下一个元素,归过程就结束了
            return;
        }
        int mid=l+((r-1)>>1);
        //将原数组拆分为左右俩个小区间,分别递归进行归并排序
        mergeSortInternal(arr,l,mid);
        mergeSortInternal(arr,mid+1,r);
        //merge操作
        merge(arr,l,mid,r);
    }

而o(n)来自于合并两个子数组的过程merge,就是一个数组的遍历

综上为非常稳定的nlogN。 

归并排序的两点优化:

1.当左右两个子区间走完子函数后,左右两个区间已经有序了

如果此时arr[mid]<arr[mid+1]

arr[mid]已经是左区间的最大值

arr[mid+1]已经是右区间的最小值

=>整个区间已经有序了,每必要在执行merge过程,只有左右俩个区间还有先后顺序不同时,才merge。

2.在小区间上,我们可以直接使用插入排序来优化,没必要一直拆分到1位置

r-1<=15,使用插入排序性能很好的。

可以减少归并的递归次数 。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值