各排序算法的时间复杂度、空间复杂度、稳定性:
(排序算法的稳定性:排序前后相等元素的相对位置不变,则称排序算法是稳定的;否则排序算法是不稳定的)
排序算法 | 平均时间复杂度 | 最坏时间复杂度 | 空间复杂度 | 稳定性 |
---|---|---|---|---|
冒泡排序 | O(n^2) | O(n^2) | O(1) | 稳定 |
选择排序 | O(n^2) | O(n^2) | O(1) | 不稳定 |
直接插入排序 | O(n^2) | O(n^2) | O(1) | 稳定 |
归并排序 | O(nlogn) | O(nlogn) | O(n) | 稳定 |
快速排序 | O(nlogn) | O(n^2) | O(logn) | 不稳定 |
堆排序 | O(nlogn) | O(nlogn) | O(1) | 不稳定 |
冒泡排序算法需要多次遍历数组(N-1次),在每次遍历中,比较连续相邻的元素。如果一对元素是降序,则互换它们的值;否则保持不变。这样每一次遍历较大的值都沉到了后面:第一次遍历区间为0~N-1,第一次遍历后,最后一个元素成为数组中最大的数;第二次遍历区间为0~N-2,第二次遍历后,倒数第二个元素成为第二大的数……
选择排序是给每个位置选择当前元素最小的,比如给第一个位置选择最小的,在剩余元素里面给第二个元素选择最小的,依次类推,直到第n-1个元素,第n个元素不用选择了,因为只剩下它一个最大的元素了。
插入排序是重复的将新的元素插入一个排好序的子线性表中,直到整个线性表排好序。插入排序是在一个已经有序的小序列的基础上,一次插入一个元素。当然,刚开始这个有序的小序列只有1个元素,就是第一个元素。比较是从有序序列的末尾开始,也就是想要插入的元素和已经有序的最大者开始比起,如果比它大则直接插入在其后面,否则一直往前找直到找到它该插入的位置......
归并排序是使用分而治之法对数组排序。将数组分为两半,对每部分递归地应用归并排序。在两部分都排好序后,对它们进行归并。先什么都不管,把数组分为两个子数组,一直递归把数组划分为两个子数组,直到数组里只有一个元素,这时候才开始排序,让两个数组间排好序,依次按照递归的返回来把两个数组进行排好序,到最后就可以把整个数组排好序。
做法:分成两个函数:1)划分数组;2)归并两个有序数组。划分时创建两个临时数组,将数组前半部分与后半部分复制到临时数组中。归并时将它们先排序再归并到原始数组中。
在数组中选择一个基准元素(pivot),将数组分为两部分,使得第一部分中的所有元素都小于等于pivot,第二部分的所有元素都大于pivot。对第一部分递归的应用快速排序算法,然后对第二部分递归的应用快速排序算法。
堆排序使用一个二叉堆,它首先将所有的元素添加到一个堆上,然后不断移除最大的元素以获得一个排好序的线性表。
该二叉堆是一个完全二叉树,该二叉树具有如下属性:首先它是一个完全二叉树(二叉树的每层都是满的,或者最后一层没填满并且最后一层的叶子都是靠最左放置的),其次每个结点大于或等于它的任意一个孩子。
设h表示n个元素的堆的高度。由于堆是一颗完全二叉树,所以第一层有1(2^0)个结点,第二层有2(2^1)个结点,....,第h层有2^(h-1)个结点,最后第h+1层最少有1个最多有2^h个结点。因此1+2+...+2^(h-1)<n<=1+2+...+2^(h-1)+2^h,即2^h < n+1 <= 2^(h+1),所以h < log(n+1) <= h+1。所以堆的高度为O(logn)。