学习了选择排序算法、插入排序算法、冒泡排序算法等。
选择排序算法: 时间复杂度是O(n*n)
主要思想是: 每次循环是第i个与后面的元素逐个比较,一次循环后得出了最大值,放在了第i个位置上
插入排序算法:
1. 从第i个元素开始,逐个比较i-1到0个元素,谁大谁小。在每次比较的过程中是交换比较的元素
由于每次比较采用的是交换每个元素,交换存在时间的消耗。
2. 每次比较记录比较的最大值,采用的是向后移一位的方法来避免交换带来的时间上不必要的消耗
冒泡排序算法
1. 相邻的两个元素比较,符合条件的就交换每个元素的值,然后在i+1,再相邻的每个元素比较
比较一趟下来,最后一个元素就是最大值了
由于每次比较采用的是交换的方法来处理符合条件的元素,存在着时间上的不必要的消耗
2. 把交换的操作改为移位的操作,这样就减少了交换带来的消耗
*X*:不难看出插入排序和冒泡排序都可能由于交换操作带来时间上的消耗,仔细观察可以发现排序算法中存在着许多可以
优化代码的小细节
归并排序算法:(每次归并的时候采用的是二分)
1. 自顶向下的过程 开始是全部,每次递归都是二分 。在最后一次的时候子块变得有序,主块也变的有序了
2.自底向上的过程 采用一个增量(增量的大小在没次循环之后*2),增量把整体分成了几个部分,分别把这些部分排好序
整体就有序了
// 自底向上 的 归并排序算
function MergeSortBU(arr, n) {
for(var sz=1; sz<n; sz += sz)
for(var i=0; i + sz <n; i += sz +sz)
Merge(arr, i, i+sz-1, min(i + sz + sz-1, n-1))
}
快速排序算法:时间复杂度(O(nlogn))
主要是Partition函数
1. 设置两个k,j变量
k 是遍历的元素 j是大于和小于指定元素的边界
返回值p保证 arr[l...p-1] < arr[p]
arr[p+1...r] > arr[p]
问题来了:
当排序数组近乎有序的时候 快排的节点组成的树节点的高度为n(本来是log(n))
这时 快排退化成 o(n*n) 级别的排序算法
解决: 在采取指定值的时候可以随机一个值来作为这次Partition的指定值
问题又来了:
当数组元素中有大量的重复元素 是一样的情况下
会导致快排的时候一端 变得非常长 而另一端变得很短
这时如果重新改变 Partition函数 尤为重要
2. Partition函数采用两头的办法来解决这个问题
使用两个变量i和j
保证 [l+1...i) <= arr[l]
[j...r] >= arr[l]
返回的是 i
快速排序的最优算法(三路排序算法)
三路快速排序算法 分成三部分 小于 等于 大于
小于arr[l] 范围是 [l+1...lt]
等于arr[l] 范围是 [lt+1...k)
大于arr[l] 范围是 [gt...r]
堆排序算法:
// 二叉堆
// 父亲节点大于等于 子节点
// 是一颗完全二叉树
// 堆排序算法
// 将n个元素逐个插入到一个空堆中,算法复杂度是O(nlongn)
稳定排序 对于相等的元素 在排序后,原来靠前的元素依然靠前
至此排序算法就算告一个段落了,在排序算法的过程中还是挺有意思的。就是发现问题,解决问题的过程。要想达到自己想要的
时间复杂度,就要想办法优化算法。