简介
上文中,我们讲到了选择排序,冒泡排序,插入排序,希尔排序。
都是相对比较简单的实现方式,因为它们都是以人的思维,维护一个index,将index与周围元素逐步对比。直到整个数组有序。
但越是效率高的算法,反而要越接近计算的的思维。否则非常难以突破O(N^2)的桎梏。
而接下来的几种效率高算法,则是一步一步接近计算机的思维,实现排序高效。
二叉树前序遍历:快速排序
快速排序的核心思路是:先将一个元素排好序,然后递归排序剩下的元素
这里可能难以理解,这说的是什么逼话?我们再拆解一下。
- 进行排序,将大于pivot的元素放右边,小于的放左边
- [1,1,2,3,4,5,9,6]
- ^
- pivot
复制代码- [[1,1,2],3, [4,5,9,6]]
- ^ ^ ^
- pivot2 pivot pivot3
复制代码 根据上面的思维描述,我们可以写出一个代码框架,并将它们抽象成一颗二叉树- public void Sort(int[] arr,int left,int right)
- {
- if (left > right)
- return;
- //进行切分,并将P排好序
- int p = Partition(arr, left, right);
- //对左右子数
- //是不是类似二叉树的前序遍历?
- Sort(arr, left, p - 1);
- Sort(arr, p + 1, right);
- }
-
- /// <summary>
- /// 分区操作
- /// </summary>
- /// <param name="arr"></param>
- /// <param name="left"></param>
- /// <param name="right"></param>
- /// <returns></returns>
- private static int Partition(int[] arr, int left, int right)
- {
- // 选择最右边的元素作为基准元素
- int pivot = arr[right];
- int i = left - 1;
- for (int j = left; j < right; j++)
- {
- if (arr[j] <= pivot)
- {
- i++;
- (arr[i], arr[j]) = (arr[j], arr[i]);
- }
- }
- (arr[i + 1], arr[right]) = (arr[right], arr[i + 1]);
- return i + 1;
- }
复制代码 其实没什么变化,相对之前实现的优先级队列来说。只是把数组作为参数传递,实现原地排序而已。
复杂度分析
- 时间复杂度
O(n log n) ,因为要对swim/sink要对每个元素调用
- 空间复杂度
O(1)
- 排序稳定性
不稳定,因为skin过程中,要将堆顶元素,与堆尾元素交换。 违背了相邻元素交换的原则,所以不稳定。
- 原地排序
是,我们的优化过程就是为了结果原地排序的问题。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |