1.常数操作:跟底层数据量无关,如 + - * / 位运算 int a = array[i];与底层数据量有关的 int a = list.get(i) 链表由于地址是乱的,需要在内存中进行遍历寻址。
2.选择排序:从0~n-1位置寻找最小值,将它与第一个位置进行数值交换,由此从第二个开始遍历寻找最 小的值与前面第二个进行交换,以此类推,知道最后一个。
3.冒泡排序:遍历一遍,将最大的排在后面,相邻两个数进行比较,比较顺序,01 12 23 34(下标) 谁大谁往后移动,每一次遍历确定一个数的位置,知道完全排序
3.插入排序:从下标00 01 02 03 04 05进行排序,找到当前几个下标的排序最优解,新元素和之前元素进行多次比较,找到合适的位置进行插入,直到找到合适的位置或者到头为止。(类似扑克牌,新抓的牌按照顺序插入到排列中)如图:
4.归并排序:找到中间值,先让左边排好序,再让右边排好序,最后整合,移动指针,不越界的前提下谁小拷贝谁,相等优先左边,进行整合
5.快速排序:把数组范围中的最后一个数作为划分值,然后把数组通过荷兰国旗问题分成三个部分;
左侧<划分值 中间==划分值 右侧>划分值
(2)对左侧范围和右侧范围,递归执行。
6.堆:堆是一种完全二叉树结构,堆排序:先让整体形成一个大根堆,然后最后一位与头节点进行交换,heapsize–,之后将头节点的值按照大根堆的语法重新排列,直到heapsize = 0即为排好序.
二.时间复杂度:
评价一个算法流程的好坏,先看时间复杂度的指标,然后在分析不同数据样本下的实际运行时间(常数项时间)
(1)选择排序:
时间复杂度计算方法,从第0~n-1一共遍历了 n次 并且此过程中需要比较寻找最小值,此过程是n次,加上交换的一次操作,0~n-1一共进行了N+N+1次常数操作。直到最后常数操作为1+1+1次,根据等差数列的通项公式遍历次数N+N-1+N-2+…,比较次数N+N-1+N-2+…,交换次数 N得出公式为aN^ 2+bN+c,时间复杂度需要在常数操作数量积的表达式中,只要最高阶的项,并且忽略高阶项的系数最后即为O(N^2),其中O类似一个上限,当数据量巨大的时候,决定复杂度的增长趋势,所以可忽略系数。
(2)冒泡排序:
同样的道理,最大的次数为N^2(异或运算,相同为0不同为1,类似无进位相加)条件是 a 和 b 在内存里是两块独立的区域
(3)插入排序:
数据情况的不同会有不同的时间复杂度
7 6 5 4 3 2 1 等差数列,需要O(N^2)
1 2 3 4 5 6 7 则需要O(N)
取最坏的情况 O(N^2)
(4)二分查找: O(log2 N)(有序无序都可用)
由于每次二分则,需要找的次数为 8 4 2 即为 log2 N
(5)递归复杂度:
子问题规模一样,可用master公式T(N) = a*T(N/b) + O(N^d)
(6)归并排序: (小和问题 和 逆序对问题)
此代码两个子问题,即左右两边先排序,是 2*T(N/2)的过程,进行归并的过程是O(N)的过程,根据公式为O(N^d * logN)
求小和
(7)快速排序:(荷兰国旗问题)好的情况下O(N^d * logN) 坏的情况 O(N^2) 空间复杂度O(logN) 最差O(N)
(8)堆排序:时间复杂度O(N*logN),空间复杂度O(1)
三.稳定性:排序后相同元素相对位置的变化
1.选择排序:做不到稳定性
2.冒泡排序:具有稳定性,由于相等不交换。
3.插入排序:有稳定性,一直向左看,相等不交换
4.归并排序,看具体情况。
5.快排:做不到稳定性。
6.堆排序:做不到稳定性。