冒泡排序
设序列为【9,8,7,6,5,4,3,2,1】,希望由小到大排列
流程:
- 从前往后,或从后往前,两两比较相邻元素的值,若出现逆序,则交换他们
- 下一趟冒泡,已有一个元素确定最终位置,待处理序列规模减1,依次类推
- 同时为了减少无逆序情况下的循环次数,设置一个标记位,如果第一趟两两对比无交换产生,说明序列有序,直接跳出循环
运行结果:我习惯从后往前,称之为沉塘法
知识点:
- 最坏情况下(完全逆序),对比的次数为,1+2...+(n-1) = n(n-1)/2
- 最坏情况下(完全逆序),对比的次数为,1*3+2*3...+(n-1)*3 = 3n(n-1)/2
- 冒泡排序是稳定排序
- 冒泡排序的空间复杂度为o(1),最坏时间复杂度为o(n2)
快速排序
流程:
给定原始数列如下,要求从小到大排序:
首先,我们选定基准元素Pivot,并且设置两个指针left和right,指向数列的最左和最右两个元素:
接下来,从right指针开始,把指针所指向的元素和基准元素做比较。如果比Pivot大,则right指针向左移动;如果比Pivot小,则把right所指向的元素填入坑中。
在当前数列中,1<4,所以把1填入基准元素所在位置,也就是坑的位置。这时候,元素1本来所在的位置成为了新的坑。同时,left向右移动一位。
此时,left左边绿色的区域代表着小于基准元素的区域。
接下来,我们切换到left指针进行比较。如果left指向的元素小于Pivot,则left指针向右移动;如果元素大于Pivot,则把left指向的元素填入坑中。
在当前数列中,7>4,所以把7填入index的位置。这时候元素7本来的位置成为了新的坑。同时,right向左移动一位。
此时,right右边橙色的区域代表着大于基准元素的区域。
下面按照刚才的思路继续排序:
8>4,元素位置不变,right左移。
2<4,用2来填坑,left右移,切换到left。
6>4,用6来填坑,right左移,切换到right。
3<4,用3来填坑,left右移,切换到left。
5>4,用5来填坑,right右移。这时候left和right重合在了同一位置。
这时候,把之前的Pivot元素,也就是4放到index的位置。此时数列左边的元素都小于4,数列右边的元素都大于4,这一轮交换终告结束。
一轮的运行结果,运气好直接一轮有序,事实上一轮只是把大于基准者置右,小于基准者置左,接下来仍需递归地对左右半部分进行快速排序:
知识点:
- 由于是递归调用,快速排序的空间复杂度主要取决于栈的深度,而栈的深度取决于基准是否选的好,运气好的话,每一次选择的基准都能把待处理序列二等分,则栈的深度=完全二叉树的深度=log2(n+1);运气不好,每一次选择的基准都是把剩下的部分挪到另外一遍,这样需要递归n-1次,栈深度=n-1
- 平均空间复杂度为o(log2n),最坏为o(n)
- 不稳定
- 平均时间复杂度是o(nlog2n)