冒泡排序 O(n^2)
前后两两数据进行比较,交换,大的数值往后走,小的数值往前走,一轮之后最大的数值到达正确位置,再多进行几轮使之都到达正确的位置
时间复杂度 O(n^2)
数据量x
第一轮:比较了x-1次
第二轮:比较了x-2次
第三轮:比较了x-3次
......
第k(x-1)轮:比较了1次
第一轮把最后一个数排好了j=0
第二轮把最后两个数排好了不用再排了j=1
-j是为了让排好的不再排
选择排序 O(n^2)
默认待排序数组第一个为最小值,找待排序数组中真正的最小值,找待排序数组真正的最小值和待排序数组的第一个位置进行交换 ---- 真正的最小值到达正确位置
时间复杂度 O(n^2)
第一轮:x
第二轮:x-1
第三轮:x-2
...
第x(k)轮:1
插入排序 O(n^2)
1、认为数组当中的第一个数值是已经排好序的数值
2、定义一个游标:从第二个数值开始,不断地向后进行遍历
3、游标指向的数据插入已经排好序的数组当中
如何实现插入按顺序排序??
定义 j 游标,j 游标指向 i 的前一个数值,j 和 j+1 指向的数据进行比较
- 如果 j+1 指向的数据比 j 大,则插入完成
- 如果 j+1 指向的数据比 j 小,则 j 和 j+1 指向的数据进行交换。j-1,直到 j+1 指向的数据大或者 j=0,j 不再向前移动,插入完成
时间复杂度 O(n^2)
j 和 j+1
第一轮:i = 1 1次操作
第一轮:i = 2 2次操作
第一轮:i = 3 3次操作
...
第x-1轮:i = x-1 x -1次操作
越小的数值在后面,j 和 j+1 移动的次数越多,所以有
希尔排序(缩小增量排序)O(nlogn)
1、将数组按照数据长度的一半为间隔(步长)进行分组(奇数的话向下取整),组内进行插入排序--------小的数值在前面,大的数值在后面
2、将数组按照数据长度的一半的一半为间隔(步长)进行分组(奇数的话向下取整),组内进行插入排序--------小的数值在前面,大的数值在后面
3、将数组按照数据长度的一半的一半的一半为间隔(步长)进行分组(奇数的话向下取整),组内进行插入排序--------小的数值在前面,大的数值在后面
...
直到无法继续分组,步长为1的时候整个数组成为一组,进行插入排序,这时候只需要微调即可
时间复杂度 O(nlogn)
忽略j和j+1的移动,因为小的大部分都在前面,j和j+1交换的次数少了,可以忽略。
看 i 遍历的次数,都看成x次
堆排序 O(nlogn)
① 利用完全二叉树构建大顶堆
② 堆顶的元素和堆底的元素进行交换,除堆底元素之外,其余元素继续构建大顶堆
③ 不断地重复②(构建大底堆),直到数据全部被处理,排序完成
完全二叉树,按照从上到下,从左到右的顺序排列(与平衡二叉树是独立的)
大顶堆:要求父节点的值大于等于其左右孩子的值
构建数组:
知道流程了,所以如何构建大顶堆?
①
从后往前依次对每一个元素进行维护,让这个元素符合大顶堆
有孩子的话一定会有左孩子
1、定义parent游标,指向要维护的节点;定义child游标,指向parent的左孩子
有孩子一定会有左孩子:
2、父子节点进行比较。如果父节点的值大,则符合大顶堆
3、如果子节点的值大,则parent指向的节点不符合大顶堆
4、父子节点进行交换,交换完成之后,parent指向child,child指向左右孩子的更大值,重复2 3 4,直到父节点的值大或者child为空
②
只需要维护堆顶元素即可
重复步骤二,所以每个尾结点都要换上来,直到结束,一直变的是堆顶元素,所以需要维护每一个堆顶元素,x个数据就是x个
因为只有堆顶元素和堆底元素进行互换了,只有堆顶元素变了 ------ 从堆顶往下遍历
时间复杂度 O(nlogn)
维护一个节点的时间复杂度:和层数相关 O(logn)
- 维护单个节点,都可以看成从上往下
- 维护单个节点,不论你是根节点还是其他的都是logn。维护一个是节点都是logn
- 比较下一层是左右任意挑一个,所以每层只与下节点比较一次
O(logn)
总体的时间复杂度:
①的时间复杂度:O(nlogn)
第一大步里,是从后往前,所有的都维护了一遍所以nlogn
对所有的数据都需要维护,一共x个数据
从下往上遍历,每到一个节点就要立马维护
②的时间复杂度:O(nlogn)
第二大步里,是每一个节点都跑到了最上边,所以每个也是对n个节点进行维护的,所以也是nlogn
基数排序 O(kn)
基数大,最大数值小
定义0-9 十个桶
排序到多少位由最大的数值决定
取数据,先进来的先取走,依次取出再依次按十位放入
重复...
没有位数的话就是0
时间复杂度 O(kn)
一共x个数
按照个位:2x (放进取出) O(n)
按照十位:2x (放进取出) O(n)
按照百位:2x (放进取出) O(n)
...
按照k位:... (放进取出) O(n)
O(kn) k不能省去,因为不知道k有多大
归并排序 O(logn)
合并有序序列:把两个短小的但是是有序的序列排序
先拆分再合并,在合并的过程中借助临时空间(没有形成新数组)进行合并
拆分??在中间位置拆开,数据分成左右两部分,按此逻辑继续拆分,拆分成一个一个的时候停止
时间复杂度 O(nlogn)
拆分:代码实现的时候,只是left和right换了一个值而已,所以实际没有拆分,不算时间复杂度
合并:每一轮需要遍历n个数据,一共logn轮,O(nlogn)
快速排序 O(nlogn)
1、定义待排序数组当中的第一个作为基准数
2、定义 j 游标,j游标从后往前移动,找比基准数小的值,找到后停下
3、定义 i 游标,j游标从前往后移动,找比基准数小的值,找到后停下
4、i 和 j 数值进行交换
5、重复2 3 4,直到 i 和 j 相遇
6、相遇位置的数据和基准数进行交换,交换完成之后,基准数到达正确位置
7、以基准数为起始点进行拆分,分成左右两部分 重复上述所有,直到数据都被拆分开停止(也没有产生新数组,用的临时空间)
把这些移上去之后,独立的数据就到位了
时间复杂度 O(nlogn)
每一轮都需要遍历n个数据,一共logn轮,O(nlogn)