原地排序算法
1、选择排序
参考算法:每一轮循环都选择出当前范围最大值,然后从右到左开始占位存储
第一轮循环
1)从数组0~N中选择出最大,与索引位0的数进行交换。
第二轮循环
1)从数组中1~N选择出最大,与索引位1的数进行交换。
2)……
第N-1轮循环
3)从数组N-1~N中选择出最大,与索引位N-1的数进行交换。
时间复杂度:
1)交换操作0~N-1次;最好的情况:已经有序,O(0)。最差的情况每次比较都需要交换O(N-1)
2)比较操作(N-1)+(N-2)+(N-3)+……+(N+1-N)次【等差数列】O(n^2)
N*(N-1)/2
3)不稳定性:个人感觉是指交换操作在值相等的情况下,是不需要操作的。以后有更深的理解后再看。如果当前值已经在排序后的位置上,那么也不需要交换
示例:
2 5 3 1 3 8 -> 索引0和6位置交换
8 5 3 1 3 2 -> 不变
8 5 3 1 3 2 -> 不变
8 5 3 3 1 2 -> 索引3和4位置交换
8 5 3 3 2 1 -> 索引4和5位置交换
代码示例:
// 从0~N选出一个最小的值放到0索引位置 // 从1~N选出一个最小的值放到1索引位置 // …… // 第一层循环,N-1次循环 for (int i = 0; i < arr.length - 1; i++) { int min = arr[i]; int idx = i; // 第二次循环N阶减次循环,可以理解为从左开始占位,每次占1位用于存储当前范围内的最小值 for (int i1 = i + 1; i1 < arr.length; i1++) { if (arr[i1] < min) { min = arr[i1]; idx = i1; } } if (idx != i) { arr[idx] = arr[i]; arr[i] = min; } }
2、冒泡排序
参考算法:每一轮循环都不断比较数组中的左右值,大的往右冒,一轮结束,最右侧为当前最大,特点是每次比较都可能包含交换
第一轮循环
1)索引位置0和索引位置1比较,左边大于右边,则交换
2)索引位置1和索引位置2比较,左边大于右边,则交换
3)……
4)索引位置N-2和索引位置N-1比较,左边大于右边,则交换
第二轮循环
1)索引位置0和索引位置1比较,左边大于右边,则交换
2)索引位置1和索引位置2比较,左边大于右边,则交换
3)……
4)索引位置N-3和索引位置N-2比较,左边大于右边,则交换
……
第N-1轮循环
1)索引位置0和索引位置1比较,左边大于右边,则交换
时间复杂度:
1)交换操作0~(N-1)+(N-2)+(N-3)+……+1 -> 套用上面的结果 N*(N-1)/2
2)比较操作(N-1)+(N-2)+(N-3)+……+1 -> N*(N-1)/2
3)不稳定性,也是交换上面,有些是不需要交换的
示例:
2 5 3 1 3 8
2 5 3 1 3 8 -> 不变
2 3 5 1 3 8 -> 索引1和2的位置交换
2 3 1 5 3 8 -> 索引3和4位置交换
2 3 1 3 5 8 -> 索引4和5位置交换
2 3 1 3 5 8 -> 不变
2 3 1 3 5 8 -> 不变
2 1 3 3 5 8 -> 索引1和2的位置交换
2 1 3 3 5 8 -> 不变
2 1 3 3 5 8 -> 不变
1 2 3 3 5 8 -> 索引0和1的位置交换
1 2 3 3 5 8 -> 不变
……
1 2 3 3 5 8 -> 不变
代码示例:
// N-1外层循环 for (int i = 0; i < arr.length - 1; i++) { // N-1递减循环,最右侧不断占位 for (int j = 0; j < arr.length - 1 - i; j++) { if (arr[j] > arr[j + 1]) { int tmp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = tmp; } } }
3、插入排序(模拟扑克牌的排序原则,抽到一张牌之后找到合适的位置插入)
参考算法:从第二个数值开始往左比较,如果右值小于左值,则交换。一直判断到最左侧。再开始下一轮循环。则左侧一部分始终保持有序。
由于索引位置0必为有序,所以不处理
第一轮循环
1)从索引1位置开始与索引0位置比较,小于则交换
第二轮循环
1)从索引2位置与索引1位置比较,小于则交换
2)从索引1位置开始与索引0位置比较,小于则交换
第三轮循环
1)从索引3位置与索引2位置比较,小于则交换
2)从索引2位置开始与索引1位置比较,小于则交换
3)从索引1位置开始与索引0位置比较,小于则交换
……
第N-1轮循环
1)从索引N-1位置与索引N-2位置比较,小于则交换
2)从索引N-2位置与索引N-2位置比较,小于则交换
……
N-1)从索引1位置与索引0位置比较,小于则交换
时间复杂度:
1)交换操作:0~(0+1+2+3+……+N-1) -> 0~(N*(N-1)/2)
2)比较操作:N-1~(0+1+2+3+……+N-1) -> (N*(N-1)/2)。当左值始终比右值大的情况下,就不需要继续向左比较了,所以最好的情况下是每一轮循环值需要做一次比较的情况
3)不稳定性:如果数值正好处于最终排序后的位置,则当前循环可以不必向左比较和交换。此特性在数组已经有部分排好序的情况下,将提升效率
示例:
2 5 3 1 3 8
2 5 3 1 3 8
2 3 5 1 3 8
2 3 1 5 3 8
2 1 3 5 3 8
1 2 3 5 3 8
1 2 3 3 5 8
1 2 3 3 5 8
代码示例:
// 从1开始,进行N-1次循环 for (int i = 1; i < arr.length; i++) { // 从当前比较的值索引位开始,向左比较 for (int j = i - 1; j >= 0 && arr[j] > arr[j + 1]; j--) { int tmp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = tmp; } }